From 2efcf2aac27f6b7e29c180d4067bd03cd0d7b0d3 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Sat, 30 May 2015 22:05:17 +0000 Subject: [PATCH 01/28] Fix minor typo in comment. No changes to code. FossilOrigin-Name: 73fc058b3a74c1b018cff990de793f19a602c12f --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqlite.h.in | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 81903c791d..9ca096fae7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\sthat\sallocateBtreePage()\salways\sclears\sthe\sMemPage\spointer\swhen\nit\sfails\sdue\sto\san\sI/O\sor\smemory\sallocation\serror. -D 2015-05-29T18:42:11.874 +C Fix\sminor\stypo\sin\scomment.\s\sNo\schanges\sto\scode. +D 2015-05-30T22:05:17.458 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -252,7 +252,7 @@ F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e F src/select.c 5978cc521cb8fc1aa6a0089e35edaf531accb52a F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee -F src/sqlite.h.in 4d0ecd8e1e0272d9a2742b39602f5e4fad8d3246 +F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 2ebeb634e751a61a6f0eebfa0f4669f46a42f6cd F src/sqliteInt.h bc8496de6a514ac66a5a938ee0e4f0d17d150c77 @@ -1281,7 +1281,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P db4e9728fae5f7b0fad6aa0a5be317a7c9e7c417 -R 203c94cd3aa280d28c1c7c31381f4eb0 -U drh -Z e97ffe3d4cc6b6234faac86c9e55619e +P 09a38bf665902834936d39341627ded88142e6ae +R ef3c3ce42e00538e32e192eb7a670812 +U mistachkin +Z 7d37f32a6f8f03a1b757dcda37cff44f diff --git a/manifest.uuid b/manifest.uuid index c7a37738d8..264528281f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -09a38bf665902834936d39341627ded88142e6ae \ No newline at end of file +73fc058b3a74c1b018cff990de793f19a602c12f \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index f14f4c9ce1..9e7efc9978 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -956,7 +956,7 @@ 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]] +**
  • [[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 From f960a64d29ee23c1c6ff427d14a0b97ea96b3ddd Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 30 May 2015 22:57:49 +0000 Subject: [PATCH 02/28] Updates to configure.ac to help it find where the TCL libraries hidden on Ubuntu 14.04. FossilOrigin-Name: c864ff912db8bc0a3c3ecc1ceac61a25332e76c5 --- configure | 14 ++++++++++++++ configure.ac | 14 ++++++++++++++ manifest | 16 ++++++++-------- manifest.uuid | 2 +- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/configure b/configure index 1b9060d3ad..b92c4e210e 100755 --- a/configure +++ b/configure @@ -10715,6 +10715,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 \ diff --git a/configure.ac b/configure.ac index 6a1188842a..92d9b47b39 100644 --- a/configure.ac +++ b/configure.ac @@ -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 \ diff --git a/manifest b/manifest index 9ca096fae7..7b8605d3c0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sminor\stypo\sin\scomment.\s\sNo\schanges\sto\scode. -D 2015-05-30T22:05:17.458 +C Updates\sto\sconfigure.ac\sto\shelp\sit\sfind\swhere\sthe\sTCL\slibraries\shidden\non\sUbuntu\s14.04. +D 2015-05-30T22:57:49.610 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -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 35cbd52af707ae22401641fe7b3672f05aea0eb1 x -F configure.ac 0b775d383c536bbaafc1e46dd3cbb81a7ea11aeb +F configure 17bd8dc3e35c718df68d04f53bf7dacf2b639732 x +F configure.ac 713de38000413e469188db2cb85bed759b56f322 F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1 F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710 @@ -1281,7 +1281,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 09a38bf665902834936d39341627ded88142e6ae -R ef3c3ce42e00538e32e192eb7a670812 -U mistachkin -Z 7d37f32a6f8f03a1b757dcda37cff44f +P 73fc058b3a74c1b018cff990de793f19a602c12f +R 6be0a2acb8b138e304ff212c6a26c60d +U drh +Z d3293018ae234b91be7ef388addbca2d diff --git a/manifest.uuid b/manifest.uuid index 264528281f..202770641e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -73fc058b3a74c1b018cff990de793f19a602c12f \ No newline at end of file +c864ff912db8bc0a3c3ecc1ceac61a25332e76c5 \ No newline at end of file From 5fea98585190ff8ef37710d62980bcaff97cb9fb Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 1 Jun 2015 11:10:39 +0000 Subject: [PATCH 03/28] Typo fixes and additional background information in README.md. FossilOrigin-Name: 9b8e5823bccf69f5cdedd8655e75df6e9718b809 --- README.md | 15 +++++++++++++-- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1cb0c7cae5..dbc020574e 100644 --- a/README.md +++ b/README.md @@ -178,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. @@ -186,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 @@ -210,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/manifest b/manifest index 7b8605d3c0..d2a7b5d5ff 100644 --- a/manifest +++ b/manifest @@ -1,11 +1,11 @@ -C Updates\sto\sconfigure.ac\sto\shelp\sit\sfind\swhere\sthe\sTCL\slibraries\shidden\non\sUbuntu\s14.04. -D 2015-05-30T22:57:49.610 +C Typo\sfixes\sand\sadditional\sbackground\sinformation\sin\sREADME.md. +D 2015-06-01T11:10:39.796 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.msc d37d2c2323df3acae6e24c71a478889421c17264 F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858 -F README.md 0bfccb18927349653c09137a458b961fa8ab4cb9 +F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7 F VERSION ce0ae95abd7121c534f6917c1c8f2b70d9acd4db F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F addopcodes.awk 9eb448a552d5c0185cf62c463f9c173cedae3811 @@ -1281,7 +1281,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 73fc058b3a74c1b018cff990de793f19a602c12f -R 6be0a2acb8b138e304ff212c6a26c60d +P c864ff912db8bc0a3c3ecc1ceac61a25332e76c5 +R 36a9006d323883fc8b82cd3617fe7735 U drh -Z d3293018ae234b91be7ef388addbca2d +Z 5f89713174f72e7e8f725e1fe0117a4f diff --git a/manifest.uuid b/manifest.uuid index 202770641e..a45b93450f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c864ff912db8bc0a3c3ecc1ceac61a25332e76c5 \ No newline at end of file +9b8e5823bccf69f5cdedd8655e75df6e9718b809 \ No newline at end of file From fcb9f4f3caa92fa042a988fa19d99ade66382287 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 1 Jun 2015 18:13:16 +0000 Subject: [PATCH 04/28] Corrections to comments in expr.c. No code changes. FossilOrigin-Name: f925389eaf5bf8962a28fcaa652b75caa606efba --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/expr.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index d2a7b5d5ff..879a00fb94 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Typo\sfixes\sand\sadditional\sbackground\sinformation\sin\sREADME.md. -D 2015-06-01T11:10:39.796 +C Corrections\sto\scomments\sin\sexpr.c.\s\sNo\scode\schanges. +D 2015-06-01T18:13:16.094 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -202,7 +202,7 @@ F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e -F src/expr.c 3fb2ab3ab69d15b4b75ae53fceb4e317f64cb306 +F src/expr.c 5de0af7c63a3722d4eb5335f81841f386daa4c20 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 F src/func.c 5b8b8e77a0fb644eaf8947d413804622e32692b6 @@ -1281,7 +1281,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P c864ff912db8bc0a3c3ecc1ceac61a25332e76c5 -R 36a9006d323883fc8b82cd3617fe7735 +P 9b8e5823bccf69f5cdedd8655e75df6e9718b809 +R 79c21798380eea59e3e40be5d7ba64b0 U drh -Z 5f89713174f72e7e8f725e1fe0117a4f +Z 59ba12ae4d822d8c7d37e1e41f2f9dfd diff --git a/manifest.uuid b/manifest.uuid index a45b93450f..f27f0a3260 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9b8e5823bccf69f5cdedd8655e75df6e9718b809 \ No newline at end of file +f925389eaf5bf8962a28fcaa652b75caa606efba \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 7e27ba99f5..6c22f75d09 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1268,7 +1268,7 @@ u32 sqlite3ExprListFlags(const ExprList *pList){ ** ** sqlite3ExprIsConstant() pWalker->eCode==1 ** sqlite3ExprIsConstantNotJoin() pWalker->eCode==2 -** sqlite3ExprRefOneTableOnly() pWalker->eCode==3 +** sqlite3ExprIsTableConstant() pWalker->eCode==3 ** sqlite3ExprIsConstantOrFunction() pWalker->eCode==4 or 5 ** ** In all cases, the callbacks set Walker.eCode=0 and abort if the expression @@ -1376,7 +1376,7 @@ int sqlite3ExprIsConstantNotJoin(Expr *p){ } /* -** Walk an expression tree. Return non-zero if the expression constant +** Walk an expression tree. Return non-zero if the expression is 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. From 69b72d5a29c2e2db120376ebae702ee353fb9bfd Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 1 Jun 2015 20:28:03 +0000 Subject: [PATCH 05/28] For FROM-clause subqueries that cannot be flattened, try to push WHERE clause terms of the outer query down into the subquery in order to help the subquery run faster and/or use less memory. FossilOrigin-Name: 297fae7551a2af9e600d833801ff79fca0602ad5 --- manifest | 15 +++-- manifest.uuid | 2 +- src/select.c | 181 ++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 140 insertions(+), 58 deletions(-) diff --git a/manifest b/manifest index 879a00fb94..ca7b8564e1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Corrections\sto\scomments\sin\sexpr.c.\s\sNo\scode\schanges. -D 2015-06-01T18:13:16.094 +C For\sFROM-clause\ssubqueries\sthat\scannot\sbe\sflattened,\stry\sto\spush\sWHERE\sclause\nterms\sof\sthe\souter\squery\sdown\sinto\sthe\ssubquery\sin\sorder\sto\shelp\sthe\ssubquery\nrun\sfaster\sand/or\suse\sless\smemory. +D 2015-06-01T20:28:03.248 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -250,7 +250,7 @@ F src/printf.c 13ce37e5574f9b0682fa86dbcf9faf76b9d82a15 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c 5978cc521cb8fc1aa6a0089e35edaf531accb52a +F src/select.c 7acdb105dccfa226ea30f3c08a847d448e216240 F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad @@ -1281,7 +1281,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 9b8e5823bccf69f5cdedd8655e75df6e9718b809 -R 79c21798380eea59e3e40be5d7ba64b0 +P f925389eaf5bf8962a28fcaa652b75caa606efba +R 033219587dbe88756604bf887ec3da43 +T *branch * subquery-opt +T *sym-subquery-opt * +T -sym-trunk * U drh -Z 59ba12ae4d822d8c7d37e1e41f2f9dfd +Z 48ce2765ca9875a4f4c27e6792269bfa diff --git a/manifest.uuid b/manifest.uuid index f27f0a3260..d83252b194 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f925389eaf5bf8962a28fcaa652b75caa606efba \ No newline at end of file +297fae7551a2af9e600d833801ff79fca0602ad5 \ No newline at end of file diff --git a/src/select.c b/src/select.c index e5e1a9988b..0558c79281 100644 --- a/src/select.c +++ b/src/select.c @@ -3718,6 +3718,73 @@ static int flattenSubquery( } #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ + + +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) +/* +** Make copies of relevant WHERE clause terms of the outer query into +** the WHERE clause of subquery. Example: +** +** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10; +** +** Transformed into: +** +** SELECT * FROM (SELECT a AS x, c-d AS y FROM t1 WHERE a=5 AND c-d=10) +** WHERE x=5 AND y=10; +** +** The hope is that the terms added to the inner query will make it more +** efficient. +** +** Do not attempt this optimization if: +** +** (1) The inner query is an aggregate. (In that case, we'd really want +** to copy the outer WHERE-clause terms onto the HAVING clause of the +** inner query. But they probably won't help there so do not bother.) +** +** (2) The inner query is the recursive part of a common table expression. +** +** (3) The inner query has a LIMIT clause (since the changes to the WHERE +** close would change the meaning of the LIMIT). +** +** (4) The inner query is the right operand of a LEFT JOIN. (The caller +** enforces this restriction since this routine does not have enough +** information to know.) +** +** Return 0 if no changes are made and non-zero if one or more WHERE clause +** terms are duplicated into the subquery. +*/ +static int pushDownWhereTerms( + sqlite3 *db, /* The database connection (for malloc()) */ + Select *pSubq, /* The subquery whose WHERE clause is to be augmented */ + Expr *pWhere, /* The WHERE clause of the outer query */ + int iCursor /* Cursor number of the subquery */ +){ + Expr *pNew; + int nChng = 0; + if( pWhere==0 ) return 0; + if( (pSubq->selFlags & (SF_Aggregate|SF_Recursive))!=0 ){ + return 0; /* restrictions (1) and (2) */ + } + if( pSubq->pLimit!=0 ){ + return 0; /* restriction (3) */ + } + while( pWhere->op==TK_AND ){ + nChng += pushDownWhereTerms(db, pSubq, pWhere->pRight, iCursor); + pWhere = pWhere->pLeft; + } + if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){ + nChng++; + while( pSubq ){ + pNew = sqlite3ExprDup(db, pWhere, 0); + pNew = substExpr(db, pNew, iCursor, pSubq->pEList); + pSubq->pWhere = sqlite3ExprAnd(db, pSubq->pWhere, pNew); + pSubq = pSubq->pPrior; + } + } + return nChng; +} +#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ + /* ** Based on the contents of the AggInfo structure indicated by the first ** argument, this function checks if the following are true: @@ -4816,60 +4883,72 @@ int sqlite3Select( p->selFlags |= SF_Aggregate; } i = -1; - }else if( pTabList->nSrc==1 - && (p->selFlags & SF_All)==0 - && OptimizationEnabled(db, SQLITE_SubqCoroutine) - ){ - /* Implement a co-routine that will return a single row of the result - ** set on each invocation. - */ - int addrTop = sqlite3VdbeCurrentAddr(v)+1; - pItem->regReturn = ++pParse->nMem; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); - VdbeComment((v, "%s", pItem->pTab->zName)); - pItem->addrFillSub = addrTop; - sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); - explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); - sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); - pItem->viaCoroutine = 1; - pItem->regResult = dest.iSdst; - sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn); - sqlite3VdbeJumpHere(v, addrTop-1); - sqlite3ClearTempRegCache(pParse); }else{ - /* Generate a subroutine that will fill an ephemeral table with - ** the content of this subquery. pItem->addrFillSub will point - ** to the address of the generated subroutine. pItem->regReturn - ** is a register allocated to hold the subroutine return address - */ - int topAddr; - int onceAddr = 0; - int retAddr; - assert( pItem->addrFillSub==0 ); - pItem->regReturn = ++pParse->nMem; - topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); - pItem->addrFillSub = topAddr+1; - if( pItem->isCorrelated==0 ){ - /* If the subquery is not correlated and if we are not inside of - ** a trigger, then we only need to compute the value of the subquery - ** once. */ - onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); - VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); - }else{ - VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); + if( (pItem->jointype & JT_OUTER)==0 + && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor) + ){ +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x100 ){ + sqlite3DebugPrintf("After WHERE-clause push-down:\n"); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + } + if( pTabList->nSrc==1 + && (p->selFlags & SF_All)==0 + && OptimizationEnabled(db, SQLITE_SubqCoroutine) + ){ + /* Implement a co-routine that will return a single row of the result + ** set on each invocation. + */ + int addrTop = sqlite3VdbeCurrentAddr(v)+1; + pItem->regReturn = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); + VdbeComment((v, "%s", pItem->pTab->zName)); + pItem->addrFillSub = addrTop; + sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); + explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); + sqlite3Select(pParse, pSub, &dest); + pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); + pItem->viaCoroutine = 1; + pItem->regResult = dest.iSdst; + sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn); + sqlite3VdbeJumpHere(v, addrTop-1); + sqlite3ClearTempRegCache(pParse); + }else{ + /* Generate a subroutine that will fill an ephemeral table with + ** the content of this subquery. pItem->addrFillSub will point + ** to the address of the generated subroutine. pItem->regReturn + ** is a register allocated to hold the subroutine return address + */ + int topAddr; + int onceAddr = 0; + int retAddr; + assert( pItem->addrFillSub==0 ); + pItem->regReturn = ++pParse->nMem; + topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); + pItem->addrFillSub = topAddr+1; + if( pItem->isCorrelated==0 ){ + /* If the subquery is not correlated and if we are not inside of + ** a trigger, then we only need to compute the value of the subquery + ** once. */ + onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); + VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); + }else{ + VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); + } + sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); + explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); + sqlite3Select(pParse, pSub, &dest); + 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)); + sqlite3VdbeChangeP1(v, topAddr, retAddr); + sqlite3ClearTempRegCache(pParse); } - sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); - explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); - sqlite3Select(pParse, pSub, &dest); - 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)); - sqlite3VdbeChangeP1(v, topAddr, retAddr); - sqlite3ClearTempRegCache(pParse); } - if( /*pParse->nErr ||*/ db->mallocFailed ){ + if( db->mallocFailed ){ goto select_end; } pParse->nHeight -= sqlite3SelectExprHeight(p); From cd8fb7cfd5f1e0f5dd1d733e4a41479cd136f413 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 2 Jun 2015 14:02:18 +0000 Subject: [PATCH 06/28] Fix a faulty assert() in btree.c. Update the database fuzz test file with new test cases. FossilOrigin-Name: 4e621af1345a001360938de76e3b0a14deb5e991 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/btree.c | 6 +++--- test/fuzzdata3.db | Bin 9322496 -> 10724352 bytes 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 879a00fb94..84ea37edf4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Corrections\sto\scomments\sin\sexpr.c.\s\sNo\scode\schanges. -D 2015-06-01T18:13:16.094 +C Fix\sa\sfaulty\sassert()\sin\sbtree.c.\s\sUpdate\sthe\sdatabase\sfuzz\stest\sfile\swith\nnew\stest\scases. +D 2015-06-02T14:02:18.322 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -192,7 +192,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3 F src/bitvec.c 5eb7958c3bf65210211cbcfc44eff86d0ded7c9d F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 -F src/btree.c 9e837a0e7e35c54bedddf55db906b7902d175078 +F src/btree.c c73a170115df068764126a85288cdec092ec180c F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 973a22a6fd61350b454ad614832b1f0a5e25a1e4 F src/build.c 85a169a0a22f8b80caf513eaf2944d39b979f571 @@ -655,7 +655,7 @@ F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26 F test/fuzzcheck.c a60f926e3fa86c8d33908406d75eec868c22b9ca F test/fuzzdata1.db b60254eeb6bc11474071b883059662a73c48da7f F test/fuzzdata2.db f03a420d3b822cc82e4f894ca957618fbe9c4973 -F test/fuzzdata3.db 2701a08185d24d8570eb6e765201131fe75eff84 +F test/fuzzdata3.db 3632e598ff8574228aadf09897bd040d3c5f5ffb F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36 F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536 F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98 @@ -1281,7 +1281,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 9b8e5823bccf69f5cdedd8655e75df6e9718b809 -R 79c21798380eea59e3e40be5d7ba64b0 +P f925389eaf5bf8962a28fcaa652b75caa606efba +R ae4a37b7f156067ca4ef803074aa5dc0 U drh -Z 59ba12ae4d822d8c7d37e1e41f2f9dfd +Z d6aea5d5b820e4f6ddc306cbfe7d28b3 diff --git a/manifest.uuid b/manifest.uuid index f27f0a3260..a97991bf5c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f925389eaf5bf8962a28fcaa652b75caa606efba \ No newline at end of file +4e621af1345a001360938de76e3b0a14deb5e991 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index cc97dc6b1f..c81059f5b4 100644 --- a/src/btree.c +++ b/src/btree.c @@ -6141,9 +6141,9 @@ static void insertCell( ins = cellOffset + 2*i; rc = allocateSpace(pPage, sz, &idx); if( rc ){ *pRC = rc; return; } - /* The allocateSpace() routine guarantees the following two properties - ** if it returns success */ - assert( idx >= end+2 ); + /* The allocateSpace() routine guarantees the following properties + ** if it returns successfully */ + assert( idx >= 0 && (idx >= end+2 || CORRUPT_DB) ); assert( idx+sz <= (int)pPage->pBt->usableSize ); pPage->nCell++; pPage->nFree -= (u16)(2 + sz); diff --git a/test/fuzzdata3.db b/test/fuzzdata3.db index 197654a9f688a21b70c977dc4d03a63dd13491bd..376459f2d624ff28e69b8f0b3892e89d2fc43c88 100644 GIT binary patch delta 247614 zcmeFaXJAxS7dATkv?-aHB%}f9)Kp05orK;~0O=*6D4l?)5Cmoh6%{c>*{CRB0Sih3 z%C-wCiUkD)#X^l0RKW6DK)BC7GfB=Q=gfG&@8`XF-z>H>IqP}$+P$2$)~tC+T61uN zTox-^Os13{>9%7bF|=2Ab4um34RZC&t)j&)zG%W%PgDC(nawI&OJ%Fa35CK)VTjOQ z=q+>=vW0Y^wU8(@6CwnMU=|3uO#UDj$d9CkoFJc*Bjf{efV@FoB74ZQWCz(s9wPUX zd&!-|LvAHElM*tI%p%js1Tvb8B!fvV=}9`1_9T_G1TOy(pK*1Ae8SZga*Jzq7yR>p zt21P!s}tlsu8xp*xH>?(T-lJNt}Mu9uJ(|NT=xPO-=>ik6t*ZrOvMYHt{)u%ZK}NX}AwyjWkXBbbq{$U$ zG6`2)%^?49HHEz7iiZ5z6$SaDD-!ZsR|Mo4R};t+u5idNTw#!(xI!U6a5*5~b%j8_ z<+4G(;j%)$=rThxmuy;X685+x{Krn02>GOoKt2Li!hZiKjLDa4W`5c5hPu3rQ(VW{pVeboPMRzpWbHo}=cH6IrmM)oDu!Kor$z9}Agr3fmEgRd(t@ecW`<)Q;?tbUV zo(lsb1^Pti%nXLdi%4bJ&`+c>1ILe{(?>-2H}|-PACrk~8zPS&mM*5noW7M^8Y=%q z*e}bnWr5!Ra_&j~Y%+PYP(UV3AuPOC+9i>Woa}TGJIl>*BoLZ)Z1x?rYJz>-?kc_Y+H# zIQ%%Wx6e$8_avnz^dhvp+BThk9!A7-m%2lBM<5B%+#%H**Ldt#sdhRD1-$Tm>fp-v^u zURipG!qoeGS?W}$w42!?kfkPahAic<*Aw%T_E5=mIF6p_ZjR+Oy|Vp=PMmp{$}?X? z3)j|EhF2u)iFx`5(u8+aU2U={$7?{|k_v{%mBiO%FA>_lOm0HMhDCSg3c9hJA@Z9d z=h2&V=V${}6E7C1vqB!s|D*>im^nUA{gdL2Ymy~)bzJmmvGVljB--RvC5AuRk@RYi zUvKZwyDqn+kJo_c8s?KM_U}DJ5lG)ag~)2GBu3nig}jm1qCnB`wv%Vr85to`9iq%{!u5$TcD>6wCQFgue>5(F8ejA;m( zo&7SqW?!{Kh%z-bk@qk#o**Ck{`V4b)9U-}gYe-{mOD3X0kM}|U488;?+{l%a+O}1 z<7i9sCOZo%^PB%vnLq0qJN-fGhlG7{VpW#FE!&oft%%)54$$N*xrD8WmY0yq3j-Z{ zv&a>Zm&V@bg&LXF6u?&OT2Ip2MqGQ62Yf~L4k5BaoA;5wtV|l+zH-;ZU-z!Tw20Nr zQU7u@`8SkZ=}5lEvo7_Mc|>W#Av zH@%$u6@wX*iP|yHni8Qqi@QsJA+Ajl=GoZXjlu(ji8lzRt+eJ&p?hV{*!FCCKY25u z=XOLyu`5f3za8w4YT*|%tJ$XF-K`QlrV=a@u2Usm>S(Rf*4 zS3<@03R`!RI0@fotKY_o9c(NsT7J`8uTsQ&%%l}9pJZ#JZ}g$+Qys-F4%Yc4@i_~t zDN;WfF7|0cbG}<1AE>r0SO0W|SlEOWC{hJTl&hbVioX(e$svUcOjsj^h0?1JmWEcI zE^Mb(k0-@zBD+>8R#;hirc{Ez*(%;`re%|CZS^_sSCu{^R@kJ~Xli@P2h1aTUlcnN zx@JfG8ut2FWpI6gu$nK_KYvSn-^Sh>By}fDI4t&5SWcgWn+f;yZT^D3HiLYAbJt%vqTg|-jUA2PzCCjJ*B@yb!x>f_mw_U*uKLt7^;UzHNc&t z{>5nNiYSJNzoDC!MDxZd`B$~Sn6CbbOZ}61(#Iim-_q<38*h=CiP=&!7M?GEK^jz4 zbOY*Nd!#{jHt?eK2q3EQ3BC4^)P;49ls^(l8eR2xeAhi$Ij`_Zpp8%6NIH9Npt%E~ zi_24Fy5_!_lhNl-udRPOq;-U?O_rxwXw7@l<8+@r{k!sfh2~GQrSh_zPOt32@U2cB z!waJ`Sl0pahaweUl-jZEA@V086JM3we1`cJ8!}3Mg^&&`w2XX5*tr7vZ!@hqBQ0a& zC(1j}z(0`o5%$Iuc>vnVVX0E28)wK1n0QnYL@Hk|UuEKP=`E2aT_;O)b+_3acoVJ2 z|A&6vXJrcSdr#_&66SSMPsvnfFRLAfo70oql`tpSk5y(hd5Ua<1$wYEe@hr3Ff+%r zcf&e4kI+Y-ZP$zDtjEwRzb_=wX}d~0(3MZdW5{`5=)nHkEYBr$$tFjUKzdP3w3`zL zO&$^5hlKGt^hsi>%pF)@=lW`Y=(Z^NEfU7?^*u25A1++^e&eXB6O5u)wKZGWWxXPL;6t6 z20DQ zoebr3GIrr53G2b|E3>hX7;GOtArC_9pCB*Wvv@<9cfH2#KN!EG zxc$Fp=YNo!iX^XI8Ois~@L1W<_(Z~X{VI58JVWE2^ERQGEqmjux3&XIA z{k*gv`mZNg=R)NpLZ+}wBcqA10}ElHJYV9a%4gWWc?Sh4S6fE)vjuLj3HY6^k6Wa{ zEv_})YZ9_JgO`GbusaqglTivU$dk+SEqkVI*j8T<)1Y^@zTWFKdT-F`jhI9JA{WUI z4wHjqA9;-yZI8d1uK6V9gUbBDNfB2X|FH5|<3rVXuDY`D&1Dbqg2Vm#x!$3^N@-%RjZIfI36S1uA6TTNt111MklEv<*C zF1d%GhbtB$-}L*z!^_@$lZI8ui+THQ$sX7jKhI31SCzJ8C?(y^bEP}0q#@pvr%D>^ zP2E~04N_C&W_IRZIY9`)z6`kqD>wYGyivuEVymV7$~by)OR1eDE-uYb2iN83`fR__ z_7SB=XjTuWnSFFX=`4^H+yuFNdQ<9V$m9w>Lf$|x7TCt|4!D%&K5e_i{`f|5iex4K z+h^78gIBaGYHFjqbokz*iYS>^1*5Q9mjWv)yQ{t0IwFi%xO^%hCbaLehLEv2z6afGc#6i5ZvxK=HGhT?A`2&9sR z?JV8TTS4c&1B++Ke1g7_L>A_KK6F5ruHCvPwY8;s$Nn!EnQR`Qmf{9+r+pYrdNpA_ z8}_Yk)$1 zm9SSIFb@{Yj|L<1m_Cum0~2||*T(jl(Z;q1AcB_uWH1U(=~H+*FokEdw%8ef0v62` z;g*F0wrR<8!MNYXa7 z(3{#Kg&FiW<1zn1y$^ zdsCmnTZR;(=p9-jx`!F$MKmOX0;fWUqF1S06G?X80Z@`IMckAXRy560mq0}ea&IjBbXg%iL$bcod<(w=Q*NAkJq zLwZxuoEDPg?E#}K^Q71+X*wlQmbp??l{C$p3ayf+dQ;XaX^J-`R!Nh+z1_c6(j;%{ z&nju6nj)8ISvT{7kaOt%ehrqp-*j_Fe&2mLK zuD;q})-MnrnO+uIq~Vu)7jy0-bjloT?q~OJ0vodwgp45TlHr@B0g6X3Yp7s%-e>_* zWyR2B3q~PCmjV-0EQXz+;Ls4D$!&|T=e8KEV+$ii*6NdamB6;I4MewWjt<5p#(>NC09>$ZrY?$jB_YiXOD3$pAX$XCU<~37 z7%UFJAW>yNul{a*f<4wfX_`O;mb|IsB6Ts;w{hFqJHUck(jpj@mIhST1)$Q}N99AM zfaN)C&kNqOZ`~z3?eX1g&C)D?tbF++bgGhOdb`PXRniPK zMN(*4q-8+}R#`%7u&ku%W(C{*0oz=LuVnYNltcl0fkur^HD~)^9J2H|WC!NZq0XQa z+4$bJXN0=5_cI0sOFA1Za)mB+i`;KS(v<_(ueKuu(#>y`J4$9lCfZ))w+w_HOgh;1 zDvZ#R7EN?UQtaF$ur43A#qoylgC$!%3gJEJ625iA*Y2TYhwy1zA_%>yV`pg}+RlS5 zIK9z=b z%bZPPb7n8+o0!Y!!BcI!C<1On2|4tQ1Ioi}+mp6pk>t|wE{+JkyL61OpPseF2y}mk zHJv$1Vcn|U$+x70{?xg%^exW3etTi7VBWQ8j$}GjtX^5bDMoU4bEJf`xbNttXiEoa zc$IX6w=xdgX}g}Ce9e|Dgy5EvFvwd4D0aYhFl^A`oMCXILO)@{p4X7Tg+7!QI<|Vg zv0<*k_o6xXk!a4{GE)pny~zkKxOcV}g4={Y&~nKUQ=V_*yS6#u9mM{H19Qg=Od6Bh zZ^Xc)8#~ZTHb)zt^>Dg1#Ni+xQPhWaqV$i*Pf$}y2;Ki$LN-}VtKYBpU!!@wiVKOA7QCr6rTcFz9ZSa2@TY9C!kTL|`B-TLIY+aPl*SViEqV`U zFAJ#a?-eb{Pju0{N}O=sN)HdUQCTuFVL{}<0HnBz9gHpCGjMJSWVYV zfAC_tPLAY9fdj?SQcqr#<0=bgN1;77p?BXqE~Ac46FT-v>n8N{7o{CZI8E+R9254} zHq!&9GSeNVRiVQYvWvk0~j9ZdzW6SeH1Ob}@xMreWfm188&_?1@lQ??%Q$-?iG&yZ$1TB9#_Y=o8yIB+o4%9>N zFTK=RZpzC{qDi|;aTx!)J)}I}Oc$O=anfII&bFcL>|gKbjuMNIaii2^I*f}+Z7m|* zUmf3@_8Bc_(+R)z?nvXNt_Y*~16QTfH4A2ja|)00)4-<0OshUsM&dHt)lZcS5<#=i zw@IecACY6|^oh}F{Df;ZSyNe37>iTC83_YZ`wB`-csQANV^OgQP2xsPW1UIMjwx+z zgww!P9Mk)B|1o6}z4Wg=xjf&g$!Tnp7B_ZEu_YxHCGjKZqyYo55yMXwIdF)V0)X3- zVH+peB8B!hR+bk=kw}`HzA~G1pamhN9qEVDrgh=j$Pk3W`iplCK^U#MdB<=auoYp4 zdpIIxdb+zKoNhU!I5!>*QRGHf4>wun@ry}w&0{x9bG3I5WqPV&WEczkDCJ9Brz$|T zyN(r2Ov@*1j3Z?tkqM?XgYMv(&!L`*^L-cSosFlc}vI<$$Ou1 zQ9~^=p=FMrmbn@&>XlO>Gtw?Z#7&;YcSAQ>O1uR$f3vi>q3#=?dqHine8G!lp0@;P_dn#P23f=6#WVbiKWkAUvQUQ(tP@4z40a zVM@lzcZs+;X(c;cVs9rX0)?W@G`T9J8$-AGw09DlKhfEP$EFFl!&nPw5TY_{FX z^MB?wTN3X#W)ix`}2xTub>7xCrXcu0=1V#O^ z;Re;?YjfDB-|f%C3a?dWFN$PMuh`GQK(Et+Q;rTVba5Ou%hxz_n!VHUyXB#H7cQ>v z?Zaufu()dNXk!!hJ=n{I8}QGsvB@cp?YOo?bC0h@1IuunHmfy%fa4D$VF{p?T|A2$?Y0=R1nQZ#7v_wJ|j&qbL!rQ=pkAC!3UKTHtw>1q0=EZvw zZ9dL>P7vO2P#gbbTcvgtQC9u=L! zM;MsBKdmG?Z*N^1RhRY5xybRm#Ds1kSp6g&wku5N6%r}1=oOC1X52JG6&^;j-1a8) zW0%8W6F%MSbm5Zri%HztYYCm}aok6*4i4dOGT0ZZceE;hPV2&su64A7U5-^2&F#Rt ztaE&b!u*`KyD;@GP0sz(FnfX>D*bBNO;~i1NzMs0Z1Bimco*UngyR~Ec>5@)l-I?Nu+1Mc@PE3))SavUGJfRmqTl@Cj z`!Fc8^9A@ILqg@xV8*W~NIt=yDsxN#|F0W?^V#3ygdRR!`Yq=_ zmM`YV0_8{c1ZX$cuhsy zlY9r5^W1v#+2SjX3Rv%_2AS*1P7`N{MZ%@W`uZD#svqJ!t_axT7cNvLPsgnYyA!t} zgo{iHbDp)z(fIRdZ)eiFx$_I;=okFyZyah3H~+_cZ8elzWO8lRG@}rz(C?f_BwHliH7vPZ$TqwS(AU{sk(e3LY~Ud0OVIx} z^k3yw0Jn{khB?o|`q#8p!T>ZIH=Nr2Pqvz}P2>mDI8!!nx-FHKt~k*&f^H~rCRrZ5 z)fI~#c9qvC4~%h+A{K(|G;f%lf3bAJ+~kdv6qYgG`8kH96h|^&g|^21U50lUo;PET zjGK1;?}*_&8d34yqOyiY3dGC@2>u$6BNVsMEZWOjjI4E@m8E#ijW;W^-{t&`U~Djn zAq|wX(AS-~VrSPVclarHYL#nVG28nQ>V$+T#qqi~$5_lK&L0SWVN48f0E0JKcpjQ) zU?RLQ*cX`3uAFdUNe~$jDp3b23{WxpP)+Nh)O)cE)$zt!i#0bw>bLH!D7%t$pz!LT zh{=Fo$*@p&HqTZAA+B}TDj11wnZ2jY;|)Lj!5 zTWL^R`=Pc8h}yycwFOX98>8ZGALo;%K~s0D>#AQyK(v+yXerRyzA+l|h*?nWRah}g zgR1UN*P(U@h}y~k6)&EOopn)DrSLk`E*eyIbGi<-TR_y-2B^5gF80(#E)HV%J6_P}YdYV)H?xTu5z#+E*2NwEWC>no14RC)y-~j=F+x{ou8~_h) z0PL;I+JYXU;V{&X!?1uHQvMT%LEtb_k3;0>f)R6WoRu^itABCSk_AOKCUrE?q%3)f z_boAYLG5qz{21j2WR&`!7>xkl=*EoD*my5JrrsL#%*hD#q=aSNLg<~~k0`T?%fhgCEKaP)Ba{5{I@tiMqEKSe?O~@xDP0Tbceh%^PM0{%AJWQx zKNf~5fH++PS>y*TA0e*0i7ejrT1x)FyE%erNduwql`=cHo`#?0P_& zoZ*P!1Hw(UHod_Bv!bvKYZD#*nkZ!&XLBY{=QTj}4S4hGLCJ#JT=ouM0s|~Gfb?dw zU7&2v1z?Fj;1Ug>`ra$=y2h%2HwFZ3Z=AoyfV){A?iLN)a&P`Hpud8*3W~bOTh#a5 z!+kHSiz@=+XBp$)1pHg|@mJO3^VdKNd7<{?H_W+(*YG!HMzVqz!z-*(wz2+|(C^XL zzqVdKxy_qDpYq$e@~L=rsAx>|BVwb8Q3qoJdnJU54fhmd@&HGGc`msZp-*x^(??&%dp20OtMrm>V^iw62m| zPw~&@!ZVCvE7p;w;?*sHh`p}y-&=1!^AHqu!MNQ>LYW*mPj|7D7VhsHt zpttEmKdOO#tj^NBG#@uY8`T6;>aNCUTYtSaN!HdGq)XJ=}p)B_4@EVLyJAuDP zAOCp`zPdM7Hy_*ke}TWvnL$I_MLSsBKTXaOr?{I>#8!}7A;odjzB2Tw|KC&2|L-a1 z|I40orqp@L$%{a%7}NwJ2WxIq=TM0D{B@U9{yJ?6KbmfVb-yXu3X#Mo_Hl4`WQyVI z8*H7KOils9L1b}|X%RMlO(yeh>ij7)o~Et|J+)fGHjnw58%JPrJJ$-x6xVXd7Oq<$ z<6QjnXcwjda+nME0%V)(Mo7tpBRA=)YYF6EF1+|9{p!M0Mf%Bw$-MNPYa!%m*8<2d zUGpK2y6}#g^pOj*C+VPT4&~+nCta8nQeA>3Aoo$ETt zJl9yrp{~)8{au)oOTAqMIB1i)y7D2jU3rk{u2GP!U3l+ON_1hVAT@Ihhm3FygLJrt zLYiGeAc+eve2SM{e1Y?aYarwW*8s>LUHu_zT>T(VxN;#scjZ8S=EC(L@vy58zZgd4dv$GVX#<(wN-m6zNgpgidA33-#d3*f9RvBGy9x3y zm%34jcw?9;>zwfD)mML>hn`qGvUh+3zNK>N z4?nj@;P6xYLZ8f+8Zuw`k@?z~Ob*L=IpQ(ccxY%tXD}EW#N+rqr4M&n19!#`?yND~ z06KW;jnRSTnnk)iPJ+j``aHg?=r^8C{yk#5D2U(t@%X`j2b?O~5BIAE z?l(WU-wog@3J0-4#gPvKty&lDBGCTSNBgTD4R?WVEmV)ddis_V{{#Yjv+HJ&o_#O0 zC!M|yHw;gAGe`TI^nXD8S0DAN1{H_Y@L_|Eg7K^@K5VJL$kg#23F|vndB^L|rYv%> zzy_~~1YFIT&>lu`S1|sH4d7Vl|H84ODtY0u!*EuED^K3D8jgh*0Q5cfsV1#ZP5QSX zByR4QB&$B8O#>O?2WdBi{D6J%Wn@$2GCa&EmlE2m6sivyRu4(Tca*l`n=f;)-K1u; zi2>@yo4S9^zHSkvpe$3vjLK4S0yat?Ho6{`#Q5d3sS&0y?j$=|7$pHSH>@|E-p!oi zS9PRFz{Tpr#cAN;{ooP|;3^7{!|mM_k)53o7B9%np*&e%c?*s5mVU}x1yb&Y`PkVK zt~?3K+v+P%saHy0}K52pUKd9=zlk0B-{h9ju+tuqQ?fuAS1ya6SE&FX@ z%~)7J`KP+kSIPiVM}4GD8l=vCNL`GP=+}i&Hac@q-xSqx8{c$*XR$E2#pnQ}?)peQ zG)O)Dka`&)?L8ZH7KL$y8><@>_tjUNqfwmer?{Vy;uhmSC+3}64?NzDlOMxSlzyhe zbY2?R0M~oQg4t{B0h2UHLt(HV1@6LA&yVQd7UR#N&5-cUew%&L0N@R8famM_Mrc4r z`hkox0I4YKD8fY%&DkB_n!z2>1l3(wI6ZJVs&9jts`CcL5Haa~v% zuMa#y13Xa!%m7?X6fA~J(xgCm@Cg@=%F5S{Q}rRHX&|Q8L)^z&?S;21K`IKYemPgq zm#;JR)z8wXpY2tT&3!ByK7y+qLAu^ZJKx5nHRX+rg_VvpS08Gg25P<+$~TTIFhIeS zCy(VRG4M!s_Nnmh{xf-rukIJ?LzUD+v4U=Q4=gUpAH-D-I{LFfRrJa9??=*D0j8tNMZ$4;Hi1N`0_fHDIg!z*ZZB6%q!p zGJ&1F#Pfo6v*gxS@6o7V>!4L(uGp z<74>%wWM}{x;p?0+qo;I3jmTiz#RbC;13YSE`J+?J3`XE^$2kOqE5tcep5miNo-2c zLdp$5)CLb|IQvRye^6ih zLmKUy{j@)9puM6H$``82=Wyi@K>1dE<=ZsMAN5oIn4$7vY}nqWo6z7~O>$}Mpd$Yz zjkE=5+x5|QXwaVYLwm{)4Qq^#nr?=j9^hGd0?K#lD}Pp_{5e16y9|}%2KAt3Un48k zO`35B&<#$KrDp)QTOV$Z2JU%3xEBoJ(pmb{W(;|GkLRTt%3su1{*p%d%YMpVF;Koy z7&nPc+TQFAWadnhh8-aT)a&|CZ)l+Q`9bYBfT}2*z$U!j>`oy4-3aM5Aib@RbU=gj zjvvyy21vULLkSE0yxFG$JsTdeh~-Uzk`g zh-m7q*J6+6mx&@B1IE`4Fe*d)U0_%HG?&m5p3nfD^aDD@4-nz`Z%Fe2R(iH1qBS%3 zX#OWueg&0h8>sYkj5Qi<-*~lQ>VS>QDb2BQDSaD=JFB^q8|4hN|Ddn^M~(J#eq7HR zD6S}MC0*mb^s|Q*cQD>4f_GvL{XL+6(TBdEfmUDY;75__g7=aEG%8stOI_9cC0s1T zdrbz1*wW9y{JjCDcM4yunZo~}fmc0a)WQF00Pm{~uSIlYu@5%KL96r|kp5|a#6oAo zS)w3auGe4Z^Wr&Q2LBC=aI7BTZ@%VefZ)vwTzl3oM`Yr~S`f+IT>4yEq{EuqBC$^* z1_t{%0v@RUX?_;jxdt#LD44k(%+L3k{SlRudnI+Q-j9n&`nqXss6k?`}un4?Vo8d_knY42LsR`19~NpqNpM z7Zn(tz3IcXiwAEo?dS+8Xh;JZf>jAxlAT~6MNFi&fXu1Q708zvh=lNYqXGi z9A$j1@~z9l@EKI~d#t0j zZ>`#8akpC7*%KOtI4YF;`6=wL;W@y7=fGNp_oxd0&?wA>!XbVNeV%o_U5?MQZgk_k zt4?-#-k(r)I-=@xjpJ5X^{-oJOrL{YwHoCckSwSr`C8m6_?F<)hjW(cWeAo*bbf|Mn>cPm&fC4M5ny4 zC*DTuDYaC3@VC;cmu2_no~N6zX-~#KhCg0Jw~mbN!TRisf7@)4OX|I_;PsPdzKtJ; zMzy4o6OIE4Uip;Oo0^6mvE&=F!^R9uPgE`bzWESI*+X0 z*Q|HD(gZwK`1xI_b#h973rz^8QcglFTyfMHRgpKq$~Nr>>+pe9`+*xDShOFk+-Y~4 zxlkvolvs16PS63t^8ifE**U>7`R^ zKP%67@UEr_ui|qQ`6Z;oed#?&hxyWQv+EA^rQvAT?ewMLYS-=Xr5{4tuBPoWF0{%4 zeC!@4bmz?p*9o$on_b?WJYtynaS~Lkes=5f9mvrx9EHgNeC%=}_i`e7Zgx45z$6ZZKlA+-&RW%qs>h_tn5eUh^aJdcZm($omY(!u^`D5Mv46F~6B_KRfy4NOc^> z$3r;e(sBAttB%2`&)f8`z6otf3~#gD=$bBx*^2x*8gaC*K_5Xn%9s8C=}2Gt0EWN_ zh9R(pV3*%OoqNaFSl;gbT?0$0SDtkHIJKF-=hxG|Z)mBRiEk73c6MSf?j=$FFc_Od z25i(@QO0aO_G5E60Gs`U?H`$#i~9UYFfN}Oa8Ykf8FM-2$K|sCTzF+Z9*o5o1}whh zij7%(<;UXd04#X<98>zhA}51!Ic31*bYL!L{J5Mo5 z(=VTP{}{k1yqW~_^(*W7`sEzdD_)H`z;_{B4u6_BNRU;JzyDA~J6OY3{hYWK4_yet z=8|zmsT&G@HK;4V-1h;sKTGlST^)xcH)DpyDd#z(!H5!HC!l zh^W`hjEJn}MC`sI`cN6f2Dp-57X-x-giUBLHetGKVE@`HXz< zOxLc_{d;VE>4mRK!)fBq(%rm}xdYBTA}A4tOh>f5OA_2E-abm{jy?+0NWKD4IwIZ1 zm(E1GwJ+Tk=~g`5m4*#!(?L;^@j*-9mvGGOZsAMAHMcuiP1_aRfm4Dx3P$MA#vxqL ztKhbm(cn{SiduKUo051fX>OQXb@r_U@E2S=rBfQa3|6-{;Gxxs3-3@A)oU<1l&U1e zlfhPg?LM!b!(cC&U><{&#vX$?6JAMP%#Gj;6H#^=R}zUn`$5uJLGk(y_O@j~X%oaU zDZy%NszDK@8JeY*NV=vWbMn4@WCWu11-PnrLk?%xw-I{a-hv3a^;Fw<9`I(QU{SF5 zh0$0y7ShLrKK2`YG%M{5_+FN})TJaSy@J}OcU^Du4tqN@xewZ9p8%Zru#gjsO|C8* z7^v2@up^Lx`qweq!>Xqw7l6?KLq^_yF3Z<7%|+ML-j|+PIgOE;D({`mVn*ZQnIUb^$V?h}j)c(UX)qx4Enr%=odnGq+J#d@foHgH+ z{DWvwMh4?E%79N^P(Jy7e0mx4L2Kp}v|6p8qm2piu9qcWCn#fdIiXh6x{qiXs8(F( z$7@VLUc8b{FlOX!#S?Yu2+E|OCYr3RpqEfVnJ_;npJ~DPOgG?D6qHYKooRLm^ofub zQ<$(eD4$uu_{{e5!RF}>_V8WKa4OFSrJ^|zX}G`ctuzLwBg)dCRO$~%whQ#}o-L*_;lluYa$4LV3+^ty{^(xx zN1fHQO}TT|VmF)|oSMnciDoGZLJhh*`u+~V2HhQe>6?+xR?~I`ZxkxQLJlf=AqV+1 zZAH+$sbL4zP^6(91pvXCqqfXEf}u!6EZU^!WoVCN%>?|g)x*s;xy zma}0D0us7$uSRVZ2ubMf?Movlp}UuwwkvzkE&_xl^cp}fCSfN` zw0>&dUvKVFn|p6iLcR^zk!5GLJc9c3hGAB{3-w^J2^GEAgq(^L8<2`OG9kVC!_Xo& zZF$SbK;=LXD!~F2DtZA5IhDA;RJ`E{xmAkU^zxREg31R$s052rsOUv0h*2Lry$6=p@pW2=E$ANXOC!3Vdyp@E3F(2p^m(KQsA;?M4LY`; zg3X71)}0SAp-R8Ts?*pDwbR&Ed>VT(NJ#{Ud02a{qUeP^nDtI2|*hC9S;o)f@gG(f;Z>`m}tHbAVyI!iPTcUY8waEGg( zj1T2oc^&me8(t`8;wzNRoQ=8edbnQ1!@c7Z5JN6NutV?m^f-P!xAXi+XkeE<6UR zU^YIx@ODb0z1>d^x|2e0vImj{-XtRWx%0hAg!FUgd6Owf;+`+>%UU2g(wmG!a)g=; zi9#)nH|~#W4V|EyL9dr+-N8%EUXri+^X#Gem;7qS%ku9F_v`KZtEO%loJlKvCarm$ zHfGYs$3zXrYHl020R)SFXl@++kXJjB9+*Q0=YS>1#dyTE%+#a6UdU@bQnHwXg+4Sl z4t=N+$PP@v8~V^oz$oe=d*OPOLTBTWP$%E!F8bxrH86#4S{roNx4~+aK+j+Vdg&AB z9hg8LErGuJ1ZeBw67CS0bAwUn*MI`w=oux#1vg6^mhcTB{SCP^jjGZ6p~)*s`2{}n z08SIvb!qr;TZ*sB45V*_x9iUPlM!~rj_c4Z#T(0wgT$##ieeAu_#SacD{ljPA!c}n zz=N>G@rOq7&}K%mfm=GaQZ`0HbxNL_@o7>haB35L1x35Htjj1MqyMw{4Xv|#og zV9=|_m%PMSa+~3TU>>e#`;G3>;d{N?niKeh$#=|bo`nu;ytnU~hU7SJasraqd6T1& z9P3SvL=tZzpvwyx1WS$zR)~2G3Xy%JW-8yX>}oSrpsh-UhS@o)Oe1XCiQ$h47W0^3 zWX9@}p?H5{IxoYsIs-{9opC-oW7=RUZXR#QN9|}Q1|u>_mk600)GAX{8hj#-leqZ5H(Fnm*NI8@CJ#`^jOtbO(BhQLJU_)2jz zN|6d%<7aXf!;M(L0r36<%2{|Cc}ppxIbW9kO4~=2zRP=%1-^@+_C$oHUC2Re_cX&3 z5t7ceC?@KWgI}IX8!7)pRX({9 z|C<4`$`EF?2B!W1;X3b)S~VN4Mo8yWq$!P%ZUxd>L!{d@NJKpu@XOF0jbMbf+*(r` z!FT|3mm$pES{QYM-w)=VMlcg?n+UP8GoQBk8|6Q(5!{`CD>H;E*TSiL_KhelXRIV4hZCw9(4F-OaOrdEOT>+x$Y~ zh}nk|0z}LottT{Qm6n^Qa@T;H-D^d{E#FAkqqT*gelWrI>M=_t?WN|O#k!hppsI@5t zcst*GVzcC~4aOV6gqu>X5XJljzBtLF?%hV`HFq|xyqGqImfe;zmTsM4chZP;DMM-0 zpp0R)5z)G{(z{abP#Z`zja#46lg~X)RTf0Xvm4i^Y%tSZAt6`*oZ%YZWbfRU(hF7M zEXy8m|AOqOlJQ3JiAP7YmId=SmEqIJvI$iwPvH-~)nt)}uj|Rac_Ag-qPXFCg5AVi z+fuN{X|4ej0!x>t_TZtgZFJ(DDb4wGu8=*yFJ%%^aR z3Ot^n)Be50FBO{MCd2$weH6CJq_Fb(kd@4OB;{|xZ2nmdBT4sPpBc~E98EcCX3`q_ zX;gzHyc!^yXaq$yC}1N`rc@Kbd>-Cu|3QOZ%C7vJ0#_mCOS}mG#OeE`6gYG;|4I=$ z?rV1X_Y|8|cGm{cRdqbbHeXFCMoGZ?sQC{>xV5*bjU^dM_g%DyzHnXYPGs(XG`yD+ z@zpbr}NOZA*z|gPf@^LgnvJ`8Q{B4`R}{Of3=2 z|7a{7u)5cU)#Xu}o3geEsh>mPUr_k3U+uiAtFQxM*T$uumu2_OwXx*<^uP(Jg=qCy z1VcU7r^*tQ)~7xoxJ&7l^{I0diw%_&L)wh=ay4zWNT}g;5qPzL@WErU$h=Zs zrq?#74y0R$r%kChb5d1GcRumf#Gj>M8&g_{CX2#y=ce@_s`=>Qn%UXx^n{Tu6v1Lq zwXth!XNaO;v9h8;BOg}d)sFGS(LG2U6k(%Rl;=w{Yij0AY-`x+5;dUpZ-NE!#KDE3 z6X8$W8$W%CeX=Vx3t>i_er5{QHIp{XuCKdV>9e~UaL7)#zAz(_WerO^M3Czc>l&ED zf!`)x<)QMmYrJjbk_+5W5&soL4Xs-;#T!}|aSttU%3+DFCyaNdUrd9oVtfk2mfLMC z<5KGD7TLY3wqh`EfN=}9CN0eyKO5_PcH)|w8bSm5I$2dn=Hvt--d?)e+Y49zsgJ01F5ZVZR@LogFiXv@#n6^u!!!9Vx~hLA;;2%hTmdGh~(pGk6MYs4xLHM78FY- zeAAug-rz_>ul@^*`!?-6L9q0oTZ+<}vG^a-zP9p^!fY`E^Q+u3mj$j*ExqZsuk!lT z70P|}@H}L3KX$K@zLW@-KAPH8A3^p4do?6|fVA;wh@xya2~kA7@A9BpA*{YGD(9hb z9?J`D)4xS7djT+)NlEF53~K2|&)nlEU}IaQKWi2&18DVEnS<5PprBty^9E+9+kcbk z$PY7TvJ08%5y%Zr8Q&LrdkbSwR{A-s;z1N!X5x8*PsYJL)0trDzqe^}wK_7S)Q;Re zcxINcJNu+BM`niZkaE&3Ogf!*kdP2|XlOdOAKZjkMrg{-mf-CWMw-^Jg87cu1h!ZS z=`CZvL8Z7Espi(6Fv(OkipLL~rC7$J4TSo#JQiuEFI|YVLrq&Pd7C9q!??qi;egHm zkL?2?x@tSxP*zotUWo2x^nZMIO#QR9o%CM%OXt*kYP)C}HqSYLb>0&4f!a@x6)e~N zN7dsDR5xKy%}bwvZhXRjR5Z~*Q9Z{pY4szl*YfnYaj(*3nOt974#6@-Q%5O+z;2+Y zADc0t!SM44;tboE?XL9yk-alh&TGO9d%I$%Ws)pzMZgm~1_N71W}h4@kk!`x9>mhH zzT%kz`GRLM`gqGS;!45s-Nv)C}uT&oIc<{XIkRPjAl<$gUpL zRBN^e8@|?b&p^o5o&k`Fp8k-{JpCXeJaD9Ab$D_h%^uv?w-OH=4qN``=?!_&1HV0% zpFF(%|KRBg`HcsmF)XJ&ogu&W@Sfzjrz7N15Bx4$4z2cN8-V*^i!_x$Es)vuMqI-2Ire12S8S~};NT=e9*2*vvM^vjTF4 zXF22)&n=MSJlGGk6?ovf#Wvit40537M##RNrI6h{OCURXN+2^mi-Cfy;Hr33ue6_i zi$+WFe`;oXi&M^vbs@O*CSp#-0t;DY`L*HM8s+s<^sXY4-bw#Xls$;d?LTnB_?9_- zD(32{m@2aL&(hz33WVJDSAlZ1EbvpYP*+9WM04aY=iY7jXPc6+QT^E)8jj1eZrH^SVA5r&8Q_M2PqVqC_j+^5+$_KXA!y*GLLS+?!|)FKQa zx9~4p)vp8jy0R-~H2sA;{-wzur@WH*bKoDktvt0US-mGbEQ-*i>#$^5-EDRWUD-8r zB-a&IHw-JLM?eN!+m)$Fm5Yl@aBJnrb@rAdmtN}PSWQf{q^n~!O?rBUjXi#U>Sx3; zU;D%M*Vw(jpT9>ho+4aIru!eZ$J-0Y8q&*TvWsX6H1`(!w>(DuRl!oqhn*C{GMZ(4 zhRMT9mc1!ur@*R|5V)VRtnw?N)w(70w?yCRoAIgQL8$QO)llJ6>AyJ{KUys=SlTaC z_!&YkcFaJf=55nWv&T6)v+e^j-h;V4wCH9&UmKEf95bEU{BUpA#jUGqhZLuGn2M_{ zRf-kEFg9Uo#uFsOvKCm_pEij<>`9(}RxHoA^SM!oV7co*szuE4`pWVx34@m`sN>5a z%R2nt4cu(5T>J^km6IOs2}@+3o1X*6CZ= zzJ+Oc9Rzh|?cS#|&Os+ai2Lg-gUtnV|1i>&FF8J|D}LWBFOxDP5G@Kf=i zMg?Ci!MXmo8GoB)PjbU&H{scb{hocK!L#ECCi3k0pV2{(JuMpQ*bE)p{B%63 z(NUj;&m@{()H14855jW$=VL4MJmIHjyRM$|5`8f?bA&o=g*{T}t}g9& zj_38ICo?kB6w7n?ppEu}XYfJm`VXv@CsFGWr`w;#TZr~ z*11#WAyoLCzVCXe-#zR1-7epEL)7o8G~b0sZ^pO-tcXoG` z{br!-p+y}WXjaeLzcf>6Oy*O9CxesiOureE*-5dy0`}?J4_?FvY2FWx-jLVHYI$L; zVy9PC0IWE?|H*m z;b4w;GO;5mmDz75iU)y(tDJn{Hk9rhEl1PC$6A;zAE9m|qH!ZuPRsjX^>J<4QrB*K z1fB9_<|nl8SD9O>(8D>4jrb_@d2AZAcSh2thco-}Iox5IeK@b2oj;rzCDN_ot3RY! zpO+5hUE3p(OdMl=pPX1rtfUAT*vAP_<~NL z)$iFOS+nmlpCYvENS?wDUe0WRz6UXl>odf=fW$+T?y+N+injC<4rz) zrC&hlNnNFa<&>rp)OVXxC6=Dv?hPnI0Ahb-C!p-CfwCH1Wy3@kv!dOn=r$2j*k9Qh zDErPp+4s82IJ3J|W?dU9`xeU187Mn%sO%wC86pJxGy4(BeqktxIDsV%bDl-H^SwWPfv^k?PfVVJw$~1MCI?^P|eR!^DBd6(o;i6E??_~T!CQsM-eQ3|E9Ajk>t&sQh^NKM)1#9#;Seo4LC$_44lE;UeQR6P zcxNza1kO@_Z@Ix|Mchni80#z}^sFp<`e^);TN#Y?D=cyaOU{Pz%}`=|ZrZz=ZqR>B^5y8Rq{ZxrOrhllZ^afY!M zVr>}S%vY43@}g8@ocS>0{q1WMXHUyH{! ztW`aHt83?0qqt{2ya9T6(OJ9>B>}H-B(xP-98e8~h74MTklea12BoQqismg%qp)Z` z_<D=T)HrG?92352g?IVT+YPU6GKQhlygkGaEfzg^?f;?eyW^uM{`a$++@)R3 zrO*jIgx*67B=nL>=rx7VAs_-$1mqfs2tipyq*)L|1(A#u!H*RY0kL2~iWLc;i9CUXx`b1Ma$3BF+OYQ!q@F`sG*Ut*J>bPkkYLwz&Zdc1A_Si`EpI?#Oq zUEPt|uJ*LfGEZs>bjx69o-;M2o(@sC0?o3GDi9i6UWno$IU zvk@!glvenOiTFwrx3D2U#+SeILK7G8h_QMeduI?aGI$zh0yJ+Is2I-#=k21bMb+`k9G~D{)qOJt`c+)1<|3+ z___u$VeOSx7H8ks}>a21i@wF7YJ&4tp$Q>%Woj$s|+T(jFc2{V+(L6e=xyL@v zp?g9_x7$Z2&#Ru~&{Y<8A>CeYwv74wtUk*b!;|qCWIPol19|87f^kWq%GtiSdWuRsY>Y9W|h1mGnvo-E%<-d=f9%j|HWT%YYAlU>5ikI?m57bQ3MWgAZG2Sz4MLx{uKlQ_FRNrH-m z*-`d&Em(D>Ne~2SZU&s5DP@Bb{5%pHNK*7kYWPWnILW>lClj&AFrRjuG_Pt=BJ^QH zJJCK2$Mty($zZ6f&rr|LAjZ{~^NOrL+KIxaaw@elhnTJABPs4qSSgCD1Exm$OpX0a zlDIalmYfoq%NW;G_*0A}_9EkNk*Y3Yj+#PSG7Ul0T%Rc2Pb9{*&?c#+l4EkOj~fHL z97_Xy8!bFME(@J;KtHan3ZGr8_m_P8&^d-%20Xsj;OnI2qoWLV60ZE%DN&5;tm0(% z=>41-G)d!0apTS_Q3-J6fJf006y2*+(B{}fh0ZR?Gj!UicI%8zH7+xBy6)hUb^~da zK54d!l--8+lNK`4zBFNr$kL+Dx& zE6liu!DB82^JsnMF@9z-Zmh4_QC6XBtu0h?}CG$xJPcbTnKfO{&u9H)msm+AB0?dL}|pkDiEQ||8DL5o|#(ZDica2Hzt zaL0x5>ZW`tm{;jDJN?XJoJ*T>cPQ2p#)|7Pywu(U&ei&yYy6x-9KBa^pFg2%Ih1e_ zok=p^63`n&Y`lMD2i0az<2IKBdd-HX!wVhv>+4wW*CEDj(5AhTFQgyox3|k9kp?Gd zd8F$=`k+4PCKaiqCEd&;&CHlAeHWL}Oq#UKkRnYQlbo)*@5Qo0XW{uB7Iv+`VOCTBAK`?V--m8@ySc+8z6m8 zpY*tj^nESq2_EU<)nAY=8YUS*8m~`^D-m(W@P`P4u|;?AN>(DK9H&)OA8M)2@TeAa z1=Y71lnS@5cM0sc$+{9mj2PkrTVK>26-`M>4!pCjj5ca1`B zK7xzUcUNNTikVykg5e;Y42#~^IZYo@A`ZfGxeTz#gpLG#aQ>CM0;%?APx05&jPQsBBC$8u4GW%vk z1PmbPEuO`TR0#QHe49j(GSiC>{Egi2+LK=z+Tai9BOX4#j$dv8M1@6Tn(ipS4zil?dgd{AF4v6k%p} znzOk3#7kxk5Z13wh$9YIr}HiL#-|3j{dPF#`zlpKj)1D`tuIAJ)l_rSjbfNR7?;M* zGS#7HMFhj&2qO%_-@*kr&%|l!_cJ>t0`( zv}+F>*o^Ndr&wA)yvM6jehtG?@@{62uJ~2|kOFY|Dj*=RT#fbp_-xu5<_P5oEgut; zEhAD`-qKYN5n)Yp^9aj#*8ZNBzSrc7D5ZYXW5t>|s5XQI$0^_<1 zx0)>%UA+*Vb77U$@|mkE!jD}UxY>8giEFo}9nOge=Qwe}+LZ4EzG<)%IHtZ%;FvO( zI{{?Ma01BG-iZ}WQ%h$*giW1&5vDr(AgtxgMwsZ#LTGXJMi}D+rAc&VB2oW1dm_By zq}h7a*&X3!C#1xG?Sz#0b52N!|I~>K)A6UBwAhb3abY_CEhko@9kQ zT3&D=m6qpRNQ`Bl3yHBj;X-08J6uSNWr3>&ZYf*(xuDdN=mNd@cNaj-@42i9x42>u zPIIBQm@}M<5Y}{7AapoqAQYX`LH3;!zl^)!v>^Q4X-4>w6T@2E2TqLQaql|g5dP1J zvm$Y?I)N5PoY4pmIE@IOavE?;I_`026#mb4Ck{NsJ>*2wi`(cFAn3FUWfpgz6ZCPO z|Nj@J;|B}x3P%Ofw6o!};F}WhLsX4_sITK0-UG|$@i`$IU#foNL(=0>-Q)B1n|*4`DSI9!d>`& zJv(t>j3ix3Q6I-*pFd618UtN86@)G|es+)`V$JMHM~^uwMHR9l>;ROL8?UC|v`ze6 zjx2em&{WMyQjVoyYb$;h*ydMbTio`lU_{%EzjNh5A^WoO6(B6oWWqu<8xfZFykIam zo2f~(34>jGBQ}4PTBasZZC+ItwjeDw^(3fPX=+ML#7xveP-D$O z_xQWOy+X^4ebz^MVxKjBrHcF>f2QK>!{a@%trEYAqd?Bo=4x_ndTGb+)^aK*dg47Q zO0SyoBSyJ8BxO3E5?O6+bLkl$vTG5}9_3xg)7~}5+MP(3$Qi>Z@sba3s*3$hc4@og* z{s{61L#C>wnopaN8$h|aIwd|Y3@ZYk7Z0h}xA^lE?DZJ?!y(ymotM`&Nnqbrot-wv z?J7#<+{|BXcXHU!K@^dq%*=JDx472J<9r01kLhzhuHs~No&21;`J7|OnAw?LaN>S1 zkMmJ*?$zgfO2x_imialK4#6q5YEOz^iW^n!Kq~72ai^E3WDk_=*H>~trG$Ae^D8+R zLJ1k;W~s*oV;<+T;H=W;Br47qdWIi1kP9VIbT(A9@cQa7LxM> zNX$#; z+u%H*&-sChlNo3A*P&A!&Z-H$===p&jd^tMgYJwz-A5|Ak2OjBghPi;Vl)|jxaMkb z;zlx$^FwfcrqB7git`H%=a(GL=L)R?vEJY7L#%Az;xdo(EI7~WabkW}ycefU+O{>6 zkQK>>dA>QrMGgHW4n30GoHT!;*NaFpEew_)y7Xr28pM`u_{o1rJpNy-A4CPw(Z#mk1i=vCfT2dVjev-NahcRy<9kysGoQ;8wXyB+USv|X0hi-1?{*~N>%fE$ zZIew)g^M^WRdy9qf|}`0#^m5LU5b=0ncFnip~JVoDY+Wm-VVsb6ct?!U&UudRg=Sn zMxI8}2G@BhQo7irO}Y*pRy|C0BxEFf6y?`}6A@Eg6-zw{MU^XU-)ef9eh021>tF4S z4|Y?1`u$fdkjY1TFN={b_H5ITL>=pWQ!v67SA?md2Cq>7PqM#|<)A=4szWyML0)5! z!`rkX)=hPAH`>$ykZBso<^f0{og=Y@4=*;0N}LtI!>W?0wFa+^3a>2(ubmIC0mE|z z@UZw}>PYdvBR_s`NI@2M3gAih{G28v^|3oo;*4IWtT<#|7fxX*?dp*>Ee~2p(1c?d z&D2c+9+yRdyHjACw|ku&D9I`iL{ksB8lWvrC4Ww4@I8a!CybLV! zTS?jbZE8s9F;YmvnyjCYzFy$!ugSOpmD%&ig7sNzk=B9gq&>)p22~@XVw81x>C!iC zf_fxVKQIiX47Ex9$FeR(8cjLWPbBeo9N6F5lVwMt$l-%oQ=>#@p6uw+RJuRPnM>o{rTy>LZEZA-$AcX8gOPYJH1I$)6-ej* zZ3Ck<*@kV@9xp7kV`n)~4p{gz4Z)wnFy3ZN!>W0kdD93}{iY(Cm@J-yLep@?-OO=g zRHR^Heuij1<}#DFB-o|*5rG_OGBz9bsYmhk$UgB#h^EmTNn=7w8cQX?fWIvp-UCeI z=#TlH;Y|}l3%S1@giPcJnG{+`u|`Nq7$Ie$g)F2(CUb<8hZZu03W1lvv}||@G))a7 zWO`^JEJtQ=gv<;rWR^zAY_1UIuFyG>*7FQ$Md$kMjHU-r@kgj1tiyxh>IYstC{jPT z2M>m+A1uX#Li%8u(X;^Z0wrF7cs`4pOw-U<=JIoZ`K~j~<0PM*YSnElO{EXUW_J)x z^EEkeCpQO}Z&B02a6%Swgs{`Cx-2)#E!-4W*O7s)@bpB(eftKvO1iWHM&{^6Fn}=b;fF1tC4bF7%5*eDffqy zvR+q;XksU3`Povb(Xx@NrL6uN0(s;2>>eVvoJUkNHO0?|$5r`2#P#jh3AEuiptrcHO%iC)JQ+%ow6jg0V$rmRBV{kmWxkZB zG*X@nE9IHcQU*{d&vK;f4=v?@M#_<}Ql95ak;kP&9354mbr6k?PxW<>L!LhHEo*v- zFG6T;=Kbkm)#b8#<2a>cG&G^{I0qt%2|HhMxav zq{MUxRbeH8NI&wBHGxH_Rs% z^5&mDG;dNv3ZgAY@rV^tN_7uevXm2{r7#a!kdoM!O34TzMef$7(EbNgt{doj%9Z$4 z#3w89%ZQgL@vjjtRpRFmFHz#3B3`V-Pa{5w#Z9L7(0_e+8#Un!rzQ}4-=_SL_G6_M zv_wip(FN+opL4Ukw)94yzL}!w3ssF2O<#u5^3`o^-3%L<5vGe8QOv$Thz$DXHbi~P5%nEc6q}xXuLzmXN{ZPW2qEOh+Ys^- zN662ig=A^>kw0!j$e+4GFk2N`FXOkN zo4zW-bo?DAL;k%D9k+No+U+xUq9;pqI(0ZX{-p0PIMB*E*6g}G!U$$+w19ry)YDt7 z=-n_XDkd`GW<=zM$c9q!WXoVWU_2JJ&*Yp=;B2;`Xf(&7Cz>YrO6Ew!rz*YDKRAFD z6+R_qgKkQQXzK_|S1WcexreG-%ofO`s|7H7aNw7|1)@3Hm!%jdML2B=)h&tUIG%q^ zbG+hTb7GmsHY`#B>8r&Rxydb7yj!*S0E%z>vF%UI?lE?2UOOEjm@{O~yn zm6L+CLj9x|$O9w#tr0|L1ueM_(mNj+P13|s{nCx*mMG6TO4&9=e6|u#MSPYLuZ7Am zQ{~juMx7g*=@Gr!{L*JrHFF)^q8H6|^;`9x`l+Kub3Iz{_#mFz53B1iog1p)W6TZ0 zX=upN&`4hc>ILm<&5acmbj?pRH_=mp$znfD7R}B05`4>i<}_Uuw9Y72Nz?V(0#lN% zG=$ClXhUFT9Qb{lxz%lmX{{?pG`9(zC2bWU`%|fqc6wRDT+_2<9dn1<5Ymw&q*G`i zofRSPupH^a6(Y~f7Af_ZE;BD=af6wzFiRW8#Z5Pw3lP1NKF0UvU)iaWt$)+@M)MFn zov*yu5Ai#ccrV1~DeR$3VdH6!VDb)R~em}^{zNaS3 zGr1|1v%L3h2*}dS@{8P?c zP~NFGxXGC^lrKi^q;fb)+UhHblAeAqb+~BGqe^`1cINyrSrTq*!mPhFLBxSv6)h$} zg>P$OeSd6Cn8R&N;G4-DVpBrS4`oLJRrCq6)!e8YRdiBl5o|NUpA}&?Bg`Q-BV+-} zP6Pz(CXc+@e=-Ct3N3(bLih!Q*@Q5M*o2S;=)?cc`>9YP3B~F+17qhs*JRNaKcr~siydxE4 zME5kAOVKUO2-g5+>NWt;Jd4(8%^H)mzESfj()qJX3`!%It!V^vxQ*b*09y6JZ8?}Z zTMlOamIGSj=l#(R*p`Do@A+E}vXF3F4rb1lgPFhO5G6!vz8cMJ-$7A?mKk!BK~@!R zlflf{WH5)^WbpM@@;-xf>$vf8@~C;hL`;79n+>v{aN7)K&NhRYzs=xNquFUNt9Kfr z&e;EjpYTB?xmB`?a2pI}&IW^-yTRZSq1j_F>+Ug-LoEi-IbOJ}1v6)B!OY)U@Tt)3 zE|~ed3uoYCLYkP>v?+0Y(|?&5V-B~$VCHNvnE4wFK24fE1~Ye$;fcP!t}I6Bj=8~U zwyjzxMo(hU4^146)3(^{n$C=!me!qU%hfW(hJrkbaCQ;Q{9S}7cneXlJek!y3ZnUm zFx_j2{RCMNXEVXf-%Rk;2YEk%b{>zCou>vAqx0CuRU^;4LTo9>YB>7|X8wMHPmOO& z;rjtkibA4v!LVekXl7@vb<0cE6K-F@%-L5k^Y;~?=eq$Ie0*CA-w&YQitGS(2q7W% z7UYakHWo1dd5Y}(i)A){Pr;WbY+Hd1H&2Pup2>kUkuyghFgC$U-wt`O$+gb3b>BQ8q!`!;%L|4UZ(Gh>J zRWb3P*jM;SD3`8%<@^}yZc*r&tV%D1MSYh=iDOaUWme)?)OTSKne}Q|)OW=zaV+Y) zV4H(IKaO}Ti<``EqKA7wTn~3b?%_}^_6iwf=bJ{_3O}G(s+pttyEkQuc2eopo}54{ z=czD75MrA_E&^qbAuu@?%-rn-U*@wN2GmViLYN%}bBG-VS%R{?00~c$ZT$w8AshHR z3qB2OX8{_1i>28RW@o`1VrN0tz}Z$XhuBt7%7g7DpeFtni+R}Ofpi`gW=p{wVoO0* z!`V+T^Y;^c*}}FISi3kwPCq!XE!2eBS1^azSCG{xn+kIO_4q(qP5Ju?J|S#NL76U# z=3hcqQ_*~lyG(jrvrNji4}8m{X9v<1-`_OLq`3w%@N~nE1<{o#w@XV5+NDE@i-;#E z?e!nT?MnQ{K9kEPuaBF|SJ8Mw>@3K6!r4|ZbGH?eq{F`s>?@kt&H^i-#p3b^>FAOr zy`*0vm)NDc`<6UU7wbD!^()B}M01!;2Xlx`2U#L#$H7cO>^R6O1qUh!}NHTD1VQqtVDw?(e|HXQ2dEgt(aB!P-KMLwz+)GAW6IJjciYN@M^ zQuVR8>8h>7J0M<5iMK+$rV?+4cnu}q0Pz$hUK{abC7y(M5{sKG*x;}vhf8dVZem3X zJHW3y()kivlP2^Ex$YfgLqcnD6DrrfI^l%W~%#oT5g$ifBE+H37Qu)P_?J$e_NWrAe?V(b6UEv@;Ae0wdHHXKoHxuWP=yQLjfgcBb{ zjm?n|Biv`^@0-e1sAFg`^boP7ldc$=SbEO^iLI+wW=v2Ql_1fQ5vHud>^?9t%I-rO z$C6W0+ivI_Pq4EvmL8#V#U0)XS1mcWAtje1C66mb*#WZTD{5ws95uyUHBkb_Z`Ii)ONkk?PU}H*TDbN{mmMtkBi>wzuSPsgiLXMu8I5<5meU<@%Q8G@s{G?Z z#GBAK+aoVDSzv<6vWQ<**awB>F5P+}S{8@OijhNxiIyd_j`%(XElcU|br)*nVfgNF zLYC_a!KAEs{TfV}FbF$z4kDpk=1?&!HDc}wBgPp{j7wLHXmN+i6(+>PgeWU&tA}7k z&EgHCW=%LX_j1&%4XfrpC0lk3!GelqT^J$j`9f$bCJoTtZQy9B8NrsG7*LmCZRLTGTo^1HMlucUzxL7x1`I0ogomA9T@ zc|^UQVcAAued`(Q*q3FyW<8_aKqkcv-62%H()2SdYP3`i@mU^5gWbg?c~nEfHYl_t zk84OK8_2|ZLzhH~u2w$$oxp#Ri@!&MzqfiKp3>mcL@aK$82GJy_`8As3>W`d4L;jI z(CR->4Zo7%xAEaW4gBZ1_=hz3Y(qecPpaXU4?T?h?09gq{!^1+>kui8SXDf`z|fz&LrtJyAXf8S`SdLaI?U~qMbig-bqJ3cN|+VN3*4brS$^G^heTK^VfdsPywUPG;Ll5QM_E!xs>ysYQu^%FoXkX0-gUImXpf`NwY&Meah6LDFLuEe3Rxtr{0PQjQ5>Qm zbr_cOp3ws9E|#xp)%jccZ)@{L!ak{8oO!8qpr8C;BYj}`4-fjv55!9P;2%8bLm#9`6_q(zM$2D#kS#y>iaof2(#}$s_OB@6 z-b!izf@1uQ%C8H<;t%FrzzF>N#^SO|Qp;=2$B?Xta*iT>e~_rn>99?Xq z%T3>tzkN^s^*yonz9&ZClV}okKIcZP!8I@{!b^Jq2T8b` zb5#(nam3yu{aU1yGtOcbt?{ZhBB4iFC!K$^w6D~5LaPO2hi&;>R)*WE?uoyQ_Bcr0 zU=oS7qzvC_0S!;o`PRV^mG`Qf7UW*Eo zEY?~oRHGF}RU)Fufp?qVAy&(zrnxke;A3730xP%HdMXgnT3;ni-Hj7-|J*MD0k82| z2pG_{Hq<~g(uJU1XL&B|I^h6b3jxzD)}|VWW-18UjE9q3b8~+}=E9r1{H}y@89+uX z&V3Sv(*ywN8h{om067^FMx!%i=f>PYMuQ8!*%cU!J&B~zmfX()(;P6ZH85>dFtiFz zBC)%2FF*$zt!vW&^Dfr*s&|c6*k$1s$Kh2k3FIY`+ZH7Y|LIz&c7W=vf)cG=R5AjE z(l?UW-^x9U9ECe{Ekq|kbkjg|*M;~Yid21)+Yu_@(p(Dx6ED_G4MZ<4#CHq=PRg|q zJpqxef#{=xpyfJ{T)US07xEMHGwr)sc(=di-2tk11DWt+6nP;fuRT&QDi{K0U95vO z5JR{S%^1Y!V2DA0$kjmP=|X%QCFK`4iY9xzi$8k}LFaRxA)vB5Y6 zz!{;z8L7gdIohB6QjnKql%iU;dPsClq=Q2z>CDu;jz;T5j208r560oa_`ri$>*%df zF8JxzY99{HF?86dA&@$=^1c;C>sV=SOLI?>HLlgsXsdO696HAcQRovP^bwX5`>0me zB1J2hRKJ;|{!JeV-*f9XUQJ&@>Wpqh0gF{X7OkbyiO=)e(rp4*7Wi{R9?T(G%YxE5 zOgeEYFG2d{zVu46nAtIQkU}oI(gS;<9>l~70GdrMbTo2KvAnk z>lLa33N+7$L}~N4aWGC&x+`g&wZR0-O#LHu4sLPLS~cxX$4y$teqe7Awce^23fBM4AJeRh_DnME1E=M za|Hf}|E#+->3x)!v75TlG9A>bdYNtq$P?8VceSTgXtyd6PilzvaEK}ko06sr3SNQf zyW(CwN&RfwSEx6Sg9FQR8rRjtT0V_(Jgwq*M&>}JnL_@E?GTT=f0jd3CD+osdiC&; zJOz^HbV-a>tb|0A1^z9SSZW!r!x``pL#$|hUX!vzp$Rtx2oHepg#ajPd@w-ywP1(s ze`@3rUKrWm))!T2d`ZLha%i?alr651<{<&wVJ%xcxv{4M45C|KQ{f-+=OIjcCl&S+ zB73K%N(HS9&#GL;T91a}C6|u&sv{a+1>+l9MszN$F21QEd`l*j*6;CLBo&3pbp&bM zfWrBr_3cm`(xtP#8gHy$Y17!iw*C*C$MiYhQ*j;-;#?yrzHqJY??%JIXVYDU=U{;F zTCXP6Io<`wNqvq}Dvr~>f_l6V))%cGhE7dv?+ns5+i=`(!qSSR7wgCRG@qzwK9y+> zt{+4lM4#>m2hrBEYAzytQFy^XE;i_0M>JYL0_qp~s9&m3&&jB0NvH*eVfYfYekJ@V zTot|-&I_Lkr-<#1P9MgSOI>@{1}GLntQYk`FR4JkR)b>k1G(~zTB*uzJ!_uiQUTyC z)(Zx-1KC@P{SIRKsg)=!PuT086A_W{m>c77!Z!Czgqz(n5LUY3jw4~Mdm2Kwdn&>e z?kNZtyD@P{7~!6bu!(zOM1=h}_eg~QbLSzfbPqsyha21JcEOz%5n=n=-3;OHZa6Zr z{o-zd@CSEegqPfn5HA1H-4K6$;>O34?UXwe;d}1-2;X$Wqmu14H@?GcFS_AL#CFh) zFG1VWZa6Zr?RMi6&$iPIM<%w1-6;qkbinJlJ+#$zqldAjxCMlEH!|23?^=$~;JO>7`JZbU!oOTg5&r60 zg79Y-on(CLx(nfX*K&A4v3}-Si13VS0m2imI}yI)nvd{x*BuC7am_$oKJE@sYVYaBg;#qQcRPgb+-(uIaJNC&#N8TUeRnH_HQg-{I@~P~n%(ILqutFx z=60ceSeLm_Kdcol)C}u1R|&$&u1N?-xh5hka*aip?;3+}sB1LBfv!;q`?^NLTa2~0 zYXtsJ57%&n8LlFP9bLmfFw5Ny@wTo)g#QOVg{(hNcP*qzXT#?KZ!Jo<%A63AU+9!g z3iu!lG-A>E6P-6q!`4sn>6FX*?#}7JNG?rd4f}hfA=t;D!o_?H%3Q)Vb;Dl98aCI@ z;N87%8I0B|01kF0r~or(f(q~-{?2W$Aa#?5y(3zA4h5ep#9Zva!S?M$a`7S7)%^yJ zVCR7f2Xh{%WR%}`AiB_+LUcEn8vQRKg6te<80sGtc(`aS|}ijTmZ zy#qc1pB{!$!NzkEs7z1Z?cHEwol1vhj6+`#Vbk{tXj8lbQXaKeK$Ww3o8lZ$f}8s) zza7&r=y|}({NMf7Utg~*^b+rhVPhi6#S6XT+5WUUVCGc187tH0J3sZ`~b>%d1F`{@at&to9pA#&R)muA11Fh z#n&H8%-rjyn)F+i`udaesv&KxD~QupG$EE;%*uj~N;a4bsZ9;Oac2Z@-C}GoawMQuxAA2lWUA4*L zIoaFvMA2%pdO^`>w33}P*DzAqbiCq#dwqMK^m1=+Ge zKPYJ4he`sMiL`SVEKmKIf+1Q3Lpjqvm4Y~~g?!sUfag`GrMaB1;w;c|7IHY{S|cZ$ zVkvQ5$FoT}oSCUat(ZYD~k&F~?jZF(qP zxlH-~oNbu**=FhU&Q|fx(WbS6!?}rh2R}i*XS?}+n{Al!+V0RNogW}2k;k*BQwOP%7ms!$jP6mpBtK_bcpyc~#w&A_rWtss3= zpY$;m>El|`C-|gak}t=MFo0C!oLM`g-v!b=`lNeRq)%x{_wh&aY2b9~Z^#wMM+WOQvRHE6N4>BeWrT(9zGT@s=+o|m=heg+Z_=}V|m zNg!GYFYqNGvv;w~);L|(l0Fa8m-R_sQIWo?B|Xe1y}0}0OCyli8fVK|&X>S>RG;(p z04Irz>I3tRnC1=fHK8|nwD5f;ZRysggEVQIAw`-rCOKU?IVR3ZzNj^lmb=FJvR2Cx zXn9*-%R6cHO&}{CQuW_Jo?YV=(PW4(%p!Bzlp>BWZ)? zdz-Z#2k(cJ_pm@-UpcZjzJJb8KCEW{Lw<@VWFc{Wf}n>|HxD zBi7*N`~9DaRdW2A}ib=LMNxWCfpKCk9p z8q9q$EcbQB&38d-I|uG>g1E64lT2sd->S(U2qyoYLtfQz6x_zSgZ$CXGmtvjwJ!=r z+t*U4bzp(pVZv@g1N7R=GOR`g>O`F->gNsF9Z2n5VtS2*8_~g zuiDEw(cRZe+zd^paW<uhAA0^L5G)&P6UdG!qq2<# zcd&z5Wa8{mG!y^9s%T^ojl7m%kD_^qO-Z2{@H`w$VpUXVF%J-%cy5jW%yoY z=@yzjR-ZFY#mTNw2RKckIG zuS`$#O_l5k9O9}I7TPw{US>_idSVpLz}YRJOVXjk=QlP1?8$yc(Vn8Ip7t7{*)%?8 zQD0)Dlb6P&$)En;KiWOnXio%w?I3EUMC+(%>uPE1@o2M0(?n{V%j(kB0&N3*+J-9H zMlvn)94^6gxRabJ9Ni9u(3p1af0BQSMt>V)aPu9@+EYQ)OrI#tPecn+F`Rm*zaY~& zX~Zgn&l9s-<6RaB)$zn^Zwdvi^cA%BD-i8%?`E3&;UO=J(!+c|m{Mlinr zSUcSr>7Y;1QAN>7TZo-`3B0~`40Y$-PaxaB%j_c>+`cFRO08H(7foNc-uN_E(V( z(30Xb-XO!DtdrFou-UYDOiR*o@R%x)^4-bW`+{_cKIu>uX^xgOmqS`v*qAgf8FLt% ze0Q?;!Qd>==PXol4%2cLaX71PR?vQd?@!jA55AH5e4|u+qqTfvIDE)hw9(2j@Rshz zbqHQJk8MBucnLE~Tn=R37wr>NToWbicU1SjXrDyTEQ{fN@$oUs(E0eC$CAinz2WE7 zJ`Sj*6xHYT&R(`0`x$}6VdI8*y|Yi2Q-hJ%=k?BB9!Qba>)mT(8e?SExQgA_X5Bsh zjUSZ*J34xm;LkLTi0K>=GpdW2$rJI(nEp6+o|g5M5QU2rfou(>WGa-*(I~0lD4APb z$vmDCGS?C*nID~-jnC7;(kPPkfzT^(rPOG5?~ih4%2%Q6D-iFg#1|vpgT`fdfwA`a z`=Z=_SG9B|z)K4qq-W#Lonh|#*%ws1?`Q7YNfZ{+)ahCr!5Q5M`y%DS-xvK2k-}Z{ zx50N*$)QGLVLZ~lB%FYyx&lb#PyM(q2kduKdfb`nI2PtA?92ox!Nhc&p6!gNzL8PU zE5oU{hod5@KVOAYQ85%MM7v8b7nn_Oroh8j@V+4JoH({vw0k)s>Vy!nMpY8j=qGO4 zASdiPhE|x2`$EfDNM)?!$mkeC#(I?uVFNcS&KQS?WXPJahiFNy5#0lnRzRIy*$HZU zfAxa{c+gM%;3+)l8+ahvAD1?i4yY|V%d&6Bzh(#i)o6bR53-a8e`Pn0D(W|?NU}Fw zl1BTSjrhmj{(meq+1KLX1GkYq59(%*zz$#XTa2X6Aa6DMpHpJ&JHqMR zDeHw*G+2J$Gj}oGx!E@mh9IUS3oe&BRsTH&uNArMP z{^cupA)JC2seZh7r$n7N@rCKnytR2V37J7x3jxAmE#+H-) z?u`=iXeTnwX#XA^O0E*Whsx2Ud(P zz^sB=_IyUK(3y%)!m0RFU&UE{6?>%d$cE39Y{(x^o5AOy^Wn>I3eM>&Ad&M2=uT;1 zPhw&J5yE+R%`d7eec}6i&z2vW|esQX;M$pzCo15~yPb`?pFytf#Zf??Ti6 z5RU#bCmSB)W&_jklUl>iTn$GCV0QTnUxTkNy2?@UN@x|=)hgIxuU@}c#rmO{rkY-QXux zZvKDhCRF&7=Afn%lCt_tI4auzQc_62B&3~d;qwTc?frV~j%D>f;rRd6=f72rA8S{# zDRjBs|EK8KHxN2rlG0MB4yn41O!8~#1o-~Kac(h;mV`)I3u->>XYQOZSrihaxmTKH z?*_D>n zj+Yb_@rsI}$PmHAX#g#yH1{3#tC$W;I33n%Mbl~^9gi~x@;W4%8+Nshgxk=O7*0nL zM@N209Vtu)?HEsx<7X#y7R7`b95qAa45<}PNNtXgsUd~b^$YosoVqrl9fZ^iEhJSI zBEf6vF=_i&Q%`!DFP(HBH1Tb`+<>asOP(1zu?VxW6$8sidH%$$kzzt4g(#-!IqCfH zi3S=(k#B}itV=7h&+g{K)!WFBsx!vLB3V3PqMQEX8fnd>K{E}5(UnY4x|_a;k5}TE zh>ug^8HkTn;_VS1qr~B>%{`jM;}V+gukFSy-}Bw1x!(*dkFSrG7{Ut~>y;9!yC9=g z&%chY+YXp%)qX-c&4ttCy$Ydd{b&FhJ>*<>A(bqj;awv(ukywE}l z!V4+X7s6KcLkcNUge)D5WmunmP2D-h(!SFS!eph>nS)NJOo>lJyi|#oB3`1z;aJaI z%;I9gNPN-_o*j?PfrJo_#(XtiaW$s;I%Q3749%vHsbL<+(DW9uY#kRmTSGV;^9fO0 zjs**u6jliHJO&|KVT4pnC_J!l!~?w6-{9G|8=M9tW&HAuVb#R4pNYDZ!bYwwtI<-&fx;yV=+{)zWENS0$rjl z+Y~7z9GI*76-zY;3wT!F5*8{}-_8vDI#O6f6Rt7(mT;HG=o>YPSF0I};Gl%d2tBE2bP%Nb0^JjYI>k2PWLZMPH>xcUDJtY0&cw zWYDhS4M3l&pu=cDf|rZFT7~Yn8!%mn7Z*A)r|_=8m00m95|Bf-p@X@qlC< zm*jpG38u+|T^jri)$mWV?1A%QmOb|Y`vETYgBtAoAZ$s4z28XoMwY-ohI@vBy%E@3 zxY!SCu%`xLKcc}V#*KNSjna;Xmsq8Bc_od><=Q1M0_C2mFg*mO9n#S^jTgu_sU>yM z(d<;v8<$Y0#w!NXjCL}~EclFSYHQPTZS8cgKo$mCB2a=cxMB}#P9 zQYf~A;t6hIcB>L2MQ$G4$G?fWi2(ZraPHA?jxms;#U;2EXt32Q6QVX7-E(B?hY3&Z zGr4Ee2C`4e+mW6wq4jnlKiplCgr@R1M8KjNjQdG%JwJ55by&gBY4azimd}|tt9X8D z2WjVz<{G5EbB4&DyT^SUsZktBX^$yeC>o)@H= znF36B4l2p*z`wwSe~H20p$lIH_?K@7{uNz#X4%k^Y5D^C=j#&S3~s_}w?lA5m!L3` z)W2Nv9^miPg+B~`^oUqiAL;pC!Epw(MP@?O=dWsP*J1F_?e}T zL)53zsq3cpq;o~-v1qz%lMo&8Yrvt_DWN3dR|!Mvmr~1-jHyq!V@9g7*{$^bYnndd37Fnb+;1#67gj;4)fHV>YJn;he{Kr^Z7Y= z^E3RDWc@d8x+URbAb+kHUm8Y=)3HrVQhzeHf{D1!<`$6=319eSQV?x=0Ot@Gb;6VoP^=$$uMkLA3oh-M%3x17urOip| z-qMSLn4s8^Bs-s0%I~t;L{Y+zs+vlzxyc3v$&$mRE<;sn&X0ohqdkWioG}sPCXPHN z{DADcq5=6u7bMu=-lq2PF(l?(DQt9JZje)xm5>kfXJB5}VE%erm{slLI|#xk=|Wum zaYb&sAi387eM34~S_Tusb<$6wLjEE39%q?E&2JvepIl`m7k=$|Q;2zZrU&(#j3X-# zm3|;>{A5luW5Vxv_ohbH-)dRR!r{$QSUB`Vt6M0uwFv8Z34h`JTblR(Q@`)e@8GPe z$}EFzLQjkal(ve_WOPE=<3Rp5BEli6ksXnIWXU$e(wB6qU3SQ5@ZeUdY{QBUhd!ka zSfFqiHF(i#JeJb*GMZA{3DtQYC%_#VQ9B^tTOYN24w*EhYz^>ml~V`L47>z#bVKtPk(fr5-4H~FgB*Rjw6wZi$jq|Q0_iug zY=da@;Ev`C9jW!#4%B=mYQFB4EZcE|QvJ5k zQ4?=#>{L3`b}FgeyOCA$tGEZLg zwWUfKWDDcR%|+snXG+ z8qhHYgnNft4bAbY#yX{=jrvv8x~ateS=m`sTU;R2z6;AF4z+bk(b1v$yO;4Ux%^j7 zl4yX16GvxF3sIY(qiG58?`zWEcg62D#w8tU9X+(CY3sp- z0Y^)Z17Vsc0byeg?aWd=HiUINR)jS?7KDi&GeVmOpF|FmCmy-D!!rrt7SBY44|paZ zT;~~&(Cfj8*~EK1V-YU(j9HGq7I;P@tniFNINdW6VVP$H!U>+?2uFEvoj$S9GYsKS zPa(qoo&touJ^3Ju@n9#>5#@ znrb#WP&v7_Zky(I5J-n%lZi+!k4EE^{_BuqA~kxXUzXn{Vn)sxk$gO1aw58uY3vt$ za-xZ&NBS>{DQHKLx;H^@KY(1FHTh<=bos8_nWXoEbQl44AcGwvHGLM2+v=F4&yFP4 zdnSJ#NiMIZT?NX^F;?^1IMr+NsIYGGWpF)|+g06_kHL!*H7`z5y(pW&q(+Bd6r#x7 zIqAQ%y=KhGt9)GhxNMOHJffOKzK{y$WY#du3?u{7GT0+rUV@?e9qKZL5*48A#qzZ*YX zMd24psUr+gWO+vUDsVW1I7U`wvUj@DckaPE9!(0oK|dc%e$6Sz6|<=IriFshgZowc zEz-(Y^U7n^Y>o2Zj+b`8b_4Lyby{1urIEt@l5FaBQ8`TAdRnnB$5_V(FyhLU%;-0D`+;D%53H3cRsvS7rCSG_ z&M1~{r$v$xYs>dx=XhwYL;4EN0O-%(p!>e^{E(XG|3<32+j&Vk`9WTkBHHdVI+?Y*d>JOQxE>YAgr@}Qm4nXS(p4!vO1d>RH|4e%Cixhu zs!%uv4=z6OAZOerWQ7a~JBhY#(Awp#@`I>|kK~=y2wakDl(MFp>ob+KunOsRdwu_E z-)bqZ*kYAdTxr&U{_BM5nRHfk?2@u(nupLVIuva&M0AS~ZU`QsM#P?oZgkNgEoyVL zrxP{6JKgX!q8;VvUPL>{(cOr)XVKWl9$w(VeJD~vPF+Yp#d7N4gCNbaV z{T(ShA)EX?pSK_yXJeyGQ(y9zz%I_$A+;|BTK7IEP-hD~)?#rro_0?>;*{T(3wQb6)kz|QEKT$L~UIfZv z4a#dO6bWo`ugOxDsJ2N<>ed5S@d5ttQZ$NPa>E}Hvc zm4z77)=k4&qNk_&y3N6qy|`!Wco)3Y&6mo&%zi0&VI#OGVxVFp*l}8`0A_U^JZq+Y zZrJ(CuPNEG4XLupWXA`f{g__p$sj%cnerB@HM3%>B=S?4Lb=fF&=@dPn+0uMK#dcw z&WF`e$45Y{Zpu_n2(x9XV4w40=S+nKI>%R>Y^$Q!(xsjG8Pf660WCF_t{k6(tGb0# znTwe?Rk*&^a`DWYK3BLM*CcyQ?IXgn7xF2{P`2X&=)MnJ{ZiZIcKi^yZ05Ku(?vSR zXORsB$+M_IZ^w_k1m-4S{p;c>9lr1I+7%ApFA5*(L~p;{XvbAwLYb)-$FM9UjcWs8XU7j?fBadCpe@7 zPa3|Wo&Gbv%J#2XJ2Eh$0}=kb_kK1(oLQCaeN!NB-d|8plrGgQ$dF*9H%c)X?f46` z`-mV;*)lBM`qyXl{tsE*<_fTBGx(6Q}{nSg)(!o4+ zlR~p7I8oM@C}akF7g>sq7T~i>ZKygC%La+*`UEWk1b)Zb^8}rQw4z1Wgfu@n?ZsH>;#u8< zUz z5?iQOD4jskL!YFliX>AeLElG>d$*oGN)Qu!QTVy!&h>?}VSu|qAuO$T2U@m1S|1f! zUk%#2!qI}zkAh{A?19sFpeOBG2pg7J02`n-{!KDyWQ_47 z>IlPlh+@$7rb+r3#VQPTB#UCOez=s|IW{3p&P{(6WAuT-Zlun|=`fy>NY}l}^(m&P zDA-{uKgG0A6gL>fyOiQ4qnHeenfes7R21wSm7ih`hXOWH$B}WC8E)7_y+HG52GHl} zqu&ugKQNaXQ!jw?vNfWW)mbgft`K|!7u-I4Q82b_q zdsWjJ7m+0UFeGUqfbZ4^ULF7rc=ny3q--SzdsEXHqsi#Z8LL6ioDwVpfm5Hr6(A7Y z8s#1yIX7jt3kgnB>HTIKANJh2Kst^^bIQXN)7tPkm%bO z`do^BKhQVnqf09E%^LKF_~>5>`=tw+^-jVLz{>50y3z+@<4n@ey$lZN?&9R6s(}TU z1blA{Lnr$nn78UPKcZsZreWS5f?4c%K-zh^X&YuLPbS()i5>>gE`6d$RYZ?zh#n6` z)Tkb0_C4KalRp{)( ztRMYVKKeK0n~TGNeyL^=zGM@zhLLzgAO2_no_VpQBU-Yrr~Ds>p{oB(+E=wJ!iQ1f zYXE;sAN=hAxbTjqI=#z5-o$K6PMAsil0gg}%NU8r_2J)F!Jp8;f53xBB_bCV%*0pG z#bO5k9^g;w!+)rPKcj*FhzGxTH4Mof8;on`8O0Q^;b_-iWo>l*l9dGM&6 zk*_sx9^9>7V^qI@>V`hmA1bOpHB^7`sE!RsN{q7%$f(%iw4MD9_E=J1m4;4|jAGp>?`-mavBi=8<`htPSz*=(d zEZUO04o4q{ujix~eS%mOf$z#9HF?Ge;yDCW<+ErfR6wz@lbU4F$F>HrNx}XlxN!mX zLltb;8Pr`IK{o`etD9y4e;UO%13yt8KPiAOB>VE72~XjHpS~AG`x5NP;!A;|JAhtG zAHB8;y^aRGE)RXz>~>O{G09KKrdp+oj|}fhYVWmQ5{yYTL6oXb)F414ZCGFTKblMH zlw4|byHtmUXGypb&{(s!nN%OFP4!uu1z0y0lxr(ia}H}|p^+GG%=!Yk_ddyp&-oi9d;No_dLn|95%5nI#Qr-A(q#cl!Y_WIZz0@y-FP04iPqry{ihnn+Cl*AH7}F%*pdRNe#9vNs@ZUEwNFXb@#~CfLu%(0md$1 z%+zP>6=0Mu+?&>bHu9OiHkidHZBN?Ip1mJQYDEcpf}pQHLB9Zj&|j0J0etj!q@8>A z0igGz=zV}bSRZ|e3Vo;sJ%@u{wQDx*KgLtwK>*Iz2QE+n7ixfqaez^aT9ei<&3+!} zcT)5`ppVc;AE`ngr9mIfM@OcdW|?vyMIR3Iar)@vRp=8m=o2~Uijm-F$t#y2MM5tgAAWB7T}n*tD{weB=|K*qQY6bp%KLQ$j%~m8 zyK79^0K&~$LKOd-$+Y+%QZa7PVSG3gBf0n>tzHuFw`uWFJS_LNtKfHNa&IRG7}jWE zw{&`i7rFPeetI4O-(&iGkE{5e(D3c%^ED^U@2PkZjpa?6nn!`YHwb;BHTxHGE3;M< z%HSy##Xb$i({w?23)%KSMPKX`d^xfSiSAbG4@{o+0CIl_$O9_K=QNN9707)I^7jDb zvw*CUuxGuHEP0{AgP94b%x+53U#a*M@fRd)%s(uhJip|d4f!Ul(Z3@|qyAU1S4?`5 zM7>dQ4)V;S{PGR~>lKRi5;=UbqA%Wml|-GX!1<1(!#*`8*}yot@d8ySuaG`{S4Q&2^Z}JkPmh z?#$dd=Q$O5D0^4Hr8Tu%1s-ftJ5&runO!jqWo89DLsJ`93_N5WO(iIMZz@LFZ4;dJk~?f-H=yiID^O-`T8^^uCg%2jcspS>yxx}<-Apreab+0k4#c92b_xUDy){C#<_nm9BuGwf6T@UA;*PD`$m9lTlxUNr2 z={OaY-sE?EY?u}lmEPpz0ZLw_x6Z=GCVFm+kCK9NxIeZvAkaHG?i%_^m;68co?sJ+ zA{3l_Qp1E(p(cEwWkNH_gn5xon8wEN`}qBs}XwP!BJ*Po?K9u%bE!x{9+JoA( zXF&TsNBe^Y?T?|f7qw_NNwn{c!!zZJxp2Wtz5tq^IhtQIXnqZ)xvWJaE}Uf$D(p;+ zLzX*BG3+x`*i<``Z(xU2z2k4}u=oT#l7FLTz8lw5@@1%=ddH}6LxRn?KjHVPwt9mk z^ppI1h<3x9rgpf?{=q5~s_*gmy9>t)$$v8C2FQEQ>IVV9Xu7|e)x&=&oHThrJisL4O9!@SwqS{ZHx2kw!Y|6iqbFX;t(n1J4C)eD>iWFUl z75yf*7w%4qliVeqrDc1H*Rl7*fRF{#0bDdjND*X1>=Usjmi};gu#km#uu-HpGXwAtAC2i7Fd>S#5)dgm~~7 zGz06Mx>35n0&&J4lNt2N>GDsuj7(tHK_fQG5heUj?=)Ka=;Su0l-AhWFl29Y>`hng zom{gB$2P*=G`6=RJudBVV24Y+BNaQGY=?63C1Hmnup>T&^;Er^wNm}Ctt9FPjti?2 z$3|>Qvbv3=)z;uPq6atiYc2d&O7lK3Sr46@2;DsM%`CBmwZ!Lx6?z2+ghW$pvN@kE z!eyKytOpQa9Kq!vf}R{fZ==}l zfyEE#g^DH$IC}%@tqIIN-+OYA`?{!Pm`raZ8z?$uN;)m=(k@nPV7a zq`h9OZw>8-OoaLEy7F z@F7OAU;ia{1H7dIjwOtgxtiefIPiTz;J0(&!_Wm&mas0!QowHm_##d4#T@wmg20z@ z;G>M<&^wmg0dUAY`1%*`z9}m-!B=wNXM(^X)UvnuD0>rXf2d!<7^67i(IsAhw^qRM z4xX|`6TFlI|2qhLEeAf{NJl0LvEt-kmaGOtw!(mwfRu7gh7BA;-3k0ev58}tW)vrw zmX-lLM*&|CaE~UqmjllT022LeBSMX4?2 z$q(!w|e4Lf{;l zN5p-9EzJ~!imnRHVbHv#N%OXfMik89c-{%&NnFORfNl!In_xJu$?zV>kR6WUL7aZi?QC!-e^dw-^r|xdiG8=avX(5k|E~B7T?Of z74(<+QrS0-XidHto=@>Po5%6RaeQpfZMB?DBm)!zCBj5d0|;{vZXvKJcxY_%;q-THxUE9U=J3B>ce& zz6JPcn)vA|eDu5Gc(zg9M2$iyoI_bR3}F<4K)-o%d73HJ1)ipwJk2;BWle$~Ud=fk zb_u?^oLz!Lm8#&IUTRBCiY$&ob~k%?DcsFcTXV?l;`?MdyZDAF$Sr`}MiaTM3Ry^% zRt@-0XwTuZf$D3a;Ytg|tw0OqfTWWqNoS5kayjEkx@wS&P)Hgvl8zwhp-IwHMS|{D z+{}u&%PyBAV$a?kRv$UlM2!G@1jP6DRm6sCuzb@=HMl_Gai0w2>jEM`C}CG@m)8yKoh@E zg^xj`c%60T2GR5oj<+O^TNRFcaLm%=n62UvQYD`=z7DsA;Ny}bd%pN<1)gQcDkL*O zGGCMAb`=R;Cnj_6x2X$57!p^qVLDC$p9k`f|cygmehyE*XoMzQtAl}`eEk^;T~;FX%-RUCMB5cr)OxU_1zlC7FfR=~Xg->L~- z&4CXL0>7IB?`sr$99oIYE)`Q0@GSt}t_i+_1D_TIelG{!&nWhMf91UZpQ?aUfIpxK zzEcG*q)Pr{{I#^3!)J@I7gn-G*l7y>{lI@%6aNtoU-B2@@%M1}Y|Pw{#!S9~{}Aw> z(8Pa|!Je0{6eERIb{`F<|q%#1}dI=h;U{9{&Xn-}m^ik%-?7SoH@HDvA`AgJ5}CljRkTMe;b~Sq^h74UM9G z%BojUi|GpfOTd3k6aRG%|BcXEyvgCWHHulwRy_s$84CVU;Qvn({~ZqhSSbFxA^2M* zd?YE5)?!oN2LAh+_$O5OkieT7x zEn@3m4Y|AGryK**uYYaTMlj4)7(N8U7n%%Tsu)CJR=7HR%`vdG%`aB5wN2zI@YUgS zFr3k3ILk4Vg=09+F|g74+bVWnM8*Oi!)Y*F5R(SR#_DO}^;N$Mso#r9Lu0S#>EV7+ z38JuFM(v=yWYiVtEAN>ghpS8dQA{!qeJD!Y6Ia|6H}bjSiGOZ}N99dFh|Y&|emB;uLm;)a4K?2`#P^90iIztW_Sn&q&?x0l4r z_Tn?qriyvcP|BtY?{9LuIAYP_rwDx}D=`+1P^p*j`x`|@1h-g~QM?o{5?B4rvr7;U zw<_*Kgw)?fLw4~EeO&4vjkrsPMeUJEWXdYY#8V?nzTLB!nWRG9wy5Kvx!~275;%AFL6cD_`SuLBYa;wrecy_ zSG*R(W}$dyL$OmZne||b)vA>_PPU<4KGLMbt7nJK`Sk^o5Hcu_6&LI27fbV(iX+}f zO=8S3z^_YoHHM^Dfq{r|r;7g)1alHidMq|wZ1Pd@*Qi@P2HXqH(kZLGGI-z}xcbZD z4T8Bob?q(Qvh8a3TetPYP3-bl#TTRL7ghNds7^+Wq%9vPZYIvTP<$6Lnd^WnMYAq= z@sbu>ev;bL9H?2_`bLGe9L?mfFq5NW9{m@g+kr0$$0_7rUmEK)%sz12hzz zAB)`_xZt3stur?gllI1bDPL=X&g@T5H`CwYzUx^!x`~+dTx_)-jW){X4l$r$f*=ma zEU7@(FB4B?m1H5iUpjCz$S$&tct{CZMn;Qu2gVK(#PMxP9!E`@(^GGnI*MJ}mAs8g zWK#6eX1e*M38KgX0xmz7-58!L(x0X}~+lFvv2{H@Jh zYlGfR6MdV6UJ?$y3($Mk2EA8U^ifjIjr$2%NB0*O_c?S|+(lxnSRKUlKmqCjKXWq{ z25#O;eZw;Kh6?SW5|<#jAU(cl1dYo=!$g;B=w*a>+v*3`FR zQ}5e^3%hwNvm;L&({eQ)56ut_o|6f6q1>F+M@@oxf@CDEdAX!BsT4b>7k)*gh*oxi z&tg-EB!y4wZp&z>*O@1>^dBzLndWWFu#*%qSBQI(kjZpy%Y<(rIX+B}+c906)8eHD zZ|HXDDs`o#H|b6?aF1T0%SoX)JjIBA=(5?I(uih1kZB=n=-Rh3+Ud)1=GiF;^~q(r z@ZshZ4*l$>I0> zA@2_d25iO#=Md{q;uh90n$PF{f8li%kIh25hbBVtX7V= zUpk^R^oTO$h@;XG>$oG%N`|ag4*714lnBSXfmLOn_}ss1hNCJQl|Pfxsq$rN^|jAE zXex_ulVa2C+q?^#slLrE*i4Z&$sKfyScp~RDTQr~UhHn*JECH{$z7k_0#j(&`cPPd- z<%mIO3-&;=J@l9z$}yJGB!NIJVn_T!mYFPjO4c%QSKZQu(u3<&!F+G%x%VmOj+ZQW zAoPfx$`Rd5+Y0&|T{_L_k}xb3|H`(#Lrk$P{cggvuD#Gsf50Xo3ohILFeHlGi z5}(V2)*LS2HSFIgXe)^AFP0vJ>iEK(#)u6VRfS$8~dzk&u;ix!K5p^(+EOBt)- ze(=^EoSDWF#e7NVjXH%1oT7h&!W-n!gfga@f3&Exa+Iskq-u1*{I0sgpxoRa3ZG@y zan32_9FzGS*ztbgEV-*ssL$lP+MjQy3e9=8sFRP}WX4*F`GWvZf?)no4I-tGxd#@D z7q1jS=GhE~3iBu2@t>-X2k9cHXq27631oT$A<_IXyL0=3B`rUS@eQWyNojXCqS~w- z-Nh(#+=yzkws2#y+uFp9s5Yz1y&R>*y$of2_fnJzZUnViquf|+w-Psk+AP=I3sL^z zUV!pf_w6Wubk9e*+C35FO7{emE8OEzE_Wkn&$7%t7Ufbmg7z#+O5OM}V_EDTjdGFu z7L*I!c;c}vaOa_%>qgL?Wx5;TdX{`Q0`)AD-9u20cOy{GGRBRMQkFdTK$OGW15gff z_ea^!-4A81yD!S_Zae{7I=k`YX=(4yMVaI7g)+;HXK+h%cPSo{Elu3rQKq{QjA?PW z@#t@{xbc{7Np^QendI(-GQo`(4oi$1F9#N*yFE(cZif!|&)pW~Kkhat|8VD^yyDJA z`Lnw<${*dWP=4pmLV4ER66M$K7AQY+XQKSb-Mke4IqAmZmHD`vy*vHS-4x{;?j|UY zxErH<+1&``^X`TypL4VKzJ2aAl)Kz6l$+dEl=I#7P>yjUh{4>?Ex@?1-E&cX>c-Q6 z<&=94%6HwfQNHP(h4Qd_CdwDwGZ3t3IpCg-e>~+bLb=CXh;p~P0Oh^ze3W;)r=h&l zJr$+fJq6_k_hgi7-IG9;Td^8t_X><5bLR?-A#=+Lj3IN=3XB+YS_MXo*;;`SV{TA^ z5o1oQz=$zNS75}Lg$j(A($s$|Fl18ytiX^-y`bozl zZq0m&JN~DT zEM#fQR!Ms{NPEspdpy`fFWx=9v)E`&ODuidxLPQfo=s^)#76h7ecL2nd_+1}UleN+ zqhDNm4kQPsL(8eAeo;Nsfut0tAWqxt$;PtMF=6+ER^iag1(%Tf?#=0)eEChp%Z-Za znht#-)#u~s$OLloQbIJH_E1J^@kZOC1d|vSyY4hlzmrh=6vbnY6?^E#Kc*u$SwTG3 zs4jn*6;1!UrKpZ*>6ZDUua!*}Gv-Kxxc{Bzi^Jq1TgSBOjWd{~g+&b|^Q6$T;A~@9 zYA&*a;pB*K=;p7>PtY?{5|)a+Ca!zJL@y@K@ZEf+e27ZEmc>OWs(dn{u%Za}r#8cz z8^q@G*BwQUz9uvBSZg#8&+N{41}(b2D8_)iE#VDaH~o@cywrXM)URr)i%Qrd%W5ff zB-GID$fG7+*|Co0I_W3X?4hCzL2PDPkA4##V`f;_vtc$y`r`rBAD?G`%)}p!?q164 zzAu}ac;oe==6;a>vEwF4$K?he_o3>z&)9Kuq~m%AA9r4L+z;%yRnl>Nf{(kZI___F z+&wrB*)V3DBy=Cm>?_{TPp@yHX>D3e+%gicRowIK1BYH+&wBVNRQi>dVA3 zP<5FEQX~9m5D%SL-wwGDUJ0Dc?nV&*4P3*Ppx&cI&e_%x$G{?B`dOE-NB!%h^4W>xfbc%!NKRU zTRWGr$fC|z6lkETOrJSk|GTdeJh!{1hOD21Br$6_>ck zqE1}IYJkVNmF1ODf_pe!J$=TU=o$AJ+{1!l*u4ambEG^s?6T9&HX~SWqiE3XzJxP}wv`)@dnY4tIT73=S%#F^F_w9-XN20GCsiq3 zOcr)SpHB_P%d^F9$IIW)(*<=CqVa-fx!srZBs;OpC?vy}w9%M+fcwP1-vqXz!oW-dltAUX%7BHj>N4azolXE@-c? zfmt>_Xm6~vcY=CvmN+zV!yzJAin-ygPP-Hsb~^;R{X(pbO{b-Yu4NG-65EC!A=5ii z-PQ;Ox8PaEqE5*qSjtovK?Fofrp|0eGi)1nh({-GXb$X2!Pskny`HmHoxmwPwv?M| z@CGbhyC!K9?}HS1ARC<&Ho&ypc;c@ct}(ygNUB7E~N99$;??!rpUz$L#`Aqv~`5 z{<>AgP|Y*k6`5h7#IP9{G>Ab21G9d+3VR2SeUBPjB-tC!8pU(&SrE3gYy;x`8i)_b zh+M)L%T6A9ml|80h{4w~yCu8t1It4^OJn5H_?9Hapk>$(d!b`3^suTHkMK;7%1r+* z-FP7isa0m-y%;Gi4!At0F~A?h$&Uw7h;^hCA(kgppilCkd$r70QiC`IWL5D|C5X}6 zHvS2&$H4WB2G>3n*M6Ss*~nb93*-7xu9oPE9mVSPG`J3iaLt(gBTEUdV*^W%BM$k~ zkO&r$XMJ9a^_ST!GYFZjq&<0SBjbAxXfFlvg`_>Pyu7t{cQLoYrlWen@(R!QYGgi( zpRada#`hxljt24h5}yc`*Cdvf63gp6%Nvnda)MZnfaPrsmj9{h@(#~(EHcZW*_}oE z{7q2ux4Z>{_ksv~&9*}4&lY2OUqy9-r#cylN<5!Go6RuC!SZ1!%T?SiKJt${VnO2H zrd44waacZK>Qg<%KEH3;3H7O!v%_SsuzUcH&%<+k;pY%6Un=IS@$(Q=RTj!W@)_QTCRj=`c1`jm1p{0i%Ak{{-Ak3pkboOHOZN^HqL>JvVlR1zvj$pz*Ljv zdpm8@FPu7_5=&>sFI1W8NB6@#G3_XvbM+3c1c=WmfbegoM zxG{SgpN&To$^3d+1pVip5ziF31(-jZ5hQ{jIXpp1fPkcO=9@Lp53O>a1Mpe~+yKC~ z@W6Hzu!943Y5;GORNS|^nMU~zhHeFVdU*7PD)dGidgF-bJ_Yps3_T6#&BCK+1kh>H z%O*2xb*76gwR)x&fz;}+Nv-}4BWMbOtndV_0tBQrXMT1>^xuF^&z+qUtYOARP)q!_ z4NuojMc1CA>kyGH*2C!j2}{=obe+S~by3lE<>F=(!BNFVKgCM<2@2tAFjcNX%d6 z*-ZrNFpgq)M2dA1#dt=6Wff~)5Cv{Ow-8$3_3RR?qqg?GRh&@ic}y=@Z=sm-hB0r7 z1aZn{&%^pU*3sl|a+&-<&XCVYX^oh)nIP@Xh+UbPY@kmk;s?}I*Cd`>cv}ZT-#KEO zNJmbMZBBRYsXv@v-05jxvW^7**dTtfjx^hjQ#Igtu67f&YPYO2blH!2*geV3YKN5< z>*Vn0Q&i|vIrM1}(d&5``fi4fC4Xxn#hn6zpV?jrep-vR_TDS*Yv&z>?dei$iFuv8 z`|+=yLw$fbg~w6}L2E|3>)`;nG(%t8RtF+pl8q#PdL zU2U=!fNFO5ip)_}q>FfZ zPBO!{%*FG76^kC$wc!cYsR-6{1mzk8vO4!ZL#OO)op@BJOb1Vn#8U>IP2qVeR6K5u z$D_?7CJ2=u1AUN$jwK6gRe1C}ROokd=$p0CX~Gv{p)qc)Wb)tn5=A8_s>4&aQcJnEGqydC(9Ekv^Rqe+|nwI_qor<%MUh8p5;IcYU=} zQ)>#(&XlP0B2xbk)F=2_YY5I-Lj`B8nu4>X67}rx)IO-(VQq-L$5QnOW6NrGVg zG_=y1QnSxU%xl9k$I(4ItHzqFAAwm>o0W8at)XhOKIX4OnKjjB-ahnjDNR=Bzk1XPvDV+P!x}h3u>M5Pyfd#WONqQD%$4Hnxp?aZ)Z*ux=mT1R3DF0X zL}9Ix%57LlNhWV;y)5ekGC@|sdWE%rus$F?s9%($|Ml!DN**w#9+CuNtv3^?wQ7je zS~Wy!Wr0|$B2(+L=dW<~hzDmbsw2?n4;E&y$Ihwr%!j5lnte~PNlHN@A_Yx5LXS_K z+JXH!HP$MN+3Hq^dBY2KLDRZ*iJe~FSsX9A78Fa8x>gN2TkCaZfOhL~a<*1&Iop{` z#npN%J6)wA_=qG7Er(221&e15oTbb-wj_KR6t z{kDxI2GOu64j;2TPUWkUKMvzll4xU=;Y-KODPkj1+!)FzkPQ2Ix^QxA8b^V*e_KLr zC=#_P>X7a9)C=)f=#fP;F4E0!nxg401n2oeGdzlOCeItszTEg+@$7CnZ-M=5Z#|vP z{;4+!u_*U=(MI;&UR1??uQv+i z-Ch&QJH6nryS->ddzuGsRCc>(4ob5J-;M1JJa`AP*Y&^=%pUKVfwDB(Gadgic#2T! zJa7cF{p-PNnC)*59KmeAd#0hh?13Yg?I+I^ls|aj2xj}%gSSH484sNOY+rdMp#01O zXFuCVo^dEodf@D5JMO`IsqKFr`1;x2@Qg-z!~mqHN%SJDshLCk?%Bdc>(Ag(?O4zQk9{AANM|$uIX7A-$j^mzT<>KE^>M>e z>;Hkns10ps(8C&C6mukgO`vHl65gS^^v%1m8MrYWF)1-lu+`VT1e1}T>*)Q%E)w~o zOAmXoqmyjt#+%P4soG2_L?@<~WLn|ewP?nRAy<3Du*4WOHfwE&Z5qUfHkPy{s$0asA$$qL~H-yTy=Laew>7>&nPz8bo(T0lU+%`2jP?&6!$6V(P*% zH4DqcW+=>IH)m?C&6Gg4i%C5aKE#tq=Y%A>^F33d+*KK2IoWL4rZ${yH8?T+J|RNQ zHM-UqXI1kx56hPWz7DnF>!{85HTY`isROa;a@8`!Qn4FEm)cNu)uuX04FCM|?|*dd zd#08$S&Oh_@CLW_s0~?94Kj?!RMK6{YnhNp=&nI6Q)#cZGhY*Hs^cyZqo-w9((WMb zT^rIq8l>pFuZg|}t-0S@TwncYk`-cyfYlbT5?6&(s(hyxg-FO{lEZtb$Al+!)K#G@{=Ym5@ZDYCErz<7#gfyv6vbFHV^1j>r z9KJ_)%IZh6KP?_40yvJ)zei_T8Ap|18!v}ZydV;Gzwq;+*xm$Lk#=8v(Cv@V|yNHDx++_njFDq(PG~Kdeob z)7R=I*crmVf^8D3(Bq&uyC~i&=nU04x3^~v{2!hF{D@*!>&-O#{$bLVE2MgpS@nL! zlU(43=DePftG6VS()_u({iVu^sBAAn{t^}IuJ5ojaWrpm1^Mc&%rVml|Z2O*2;mJ?aG(_O6- zr-=*3#oq&`n1`CbD9-4$8VXIe0(Q<{#&)_^IzrRG9D&TCV}^Ys2)4q&Ku`tlN+GVE z?$U5H*_LBy;;9ZJ+GJaTZA4c}+Y7PXMc$r|?auP{ZP@N4ZzICm(^1|=h_wgr=hC_P z7|2ri?sZ!8#_G;ur~6kQgE`@2c;9V~IAWVGh?gQPxU;dPZiud>*nP~fH*r$r#duFYfM0=JPW2oi#8U4kP zbrY7Njdx_csSHVV%%yD+hp{+-F@<47(YI%2brH+vCiEA=p1zbjeVOlcBfFm4(k=UA zr?C;07YM%h*}Z~0X{G9G9SQxf3Hw4_rrLbK@pW6Hp z%Cpy`L1lLNnp_OaiZBNvve*|;owp`hATgA*ic3|F_o|Mkk9IC>PgneyktR*yY^J^2 zAM?>#Pp<1|PKSiXF<5m>XK&P%6t(?>bg9luwN;lD4r7y2Z~E}UVXx@PuR40FTjDI* ztKXUiw0};EH|Zm{tZ8Auy|$F*Ud$XxTTRJY!KTg5#>3=U@(8_hD1M$EewAXr7{8L- zy&xe86X2=SQl#gR543&q%qu3rI zZ$E_X!SePlY!8yR@5lB)dHbI2QJw(|wJUArY~B*HwT)uL_E$#ibd#+b`?j-zvXa>7 z{*yBr9k`rnB&?4b)3x6$7)kG#n1wkGistmIdyK8vRu2kMnTdW~1S@xMa73s3x@`v& zaIlcn>V@^1v!+8{kv?=w-Gu+@u{&0duAQzyygrKbJc%1f^_Jw@#7F*GgDE|croWxh zWJ_;b^`e@^x37QX1f0|V=BpJixwH?PT9@%Xy-z93PQDg<9$%6 zS1{m=8gb#O`2GSL(3KcT4|C^8q1-maZu`!eUYepOS>p4vN(bXkwI|G>k12<;NOyy- z3?pXu*X8q-nUf9bL~-w|(pz!<6RZO#vPm|MKDi^I14Woctm!rBho1Uk#GfMi6OJBu zTA9Rp&=m-0-ZC;;=|2m7wXn3WV0)4c)tB{UkjcouEn)YTk+E_813&CJq6NGBhLIr$ z@{0}-`u?dAG4$y7%};L0txvbiDxFCLI<#xiour&5wJe*$+9Qqlhf7^aS_6R|g6*j= z)qXlq?Ro-yEE1jKshOql|75-^%=Q7>tQ}3U_sX&Nx_g;D-Y7ggB3eXx{r5$ev!FFI zF`;1++KAIKGan!{?RY$%KM&#h7%5#Jv9<%a7!bFz56&DP$Khhwhrc0zqcrXA#f7n- zGtk%V&ngDylv)Jhr8#pFXG@*(K;}Sk!IIKJBq#vi_MAKqmls03!gkPiz7&B^5rH2^ zqS>mfo#+na79|Se8E+xG@r&w+3)}PRr*DKjR*LQKDSg+7r6}8r+<`9z9q5bP7mHsl zbnC^-lZ(a>y5OY|1$5e*rcUZtECkimrtw|?;j0|s;jo1M*#7}yrByd>B;Q2(fLt9!Pt}I*6zDkJ02`+p zz+OUGBDrg&KjPsGu~#ZgrY(WEDBH(?_=0QqFEuTmPdd?4=i(RA1#iY1#HrUyy=WN( zZ-s&V9I)STu%|U)m$8|8zJjMjZUrW(Bty-Q2;|KfoOzs7Uv80TvV9Hoa~%44H9G3e z{1nUTWAVaMz&;uIL$=r_qXx1}gY7I}E^sj42f;`x5q}ZVN!-7(g+-8i#~-l8p?wFm ziyYdeaA+2TAP8dmizD`vkU7R5vc&=a2;g5h;9u3ixHO8z#-6gb(8p8d&X7J)H6TX1 z@MuO0U!1YY_A_vP<8ZD9;jA*6uIqHy=&6SaZwU#g^I0muN*0L`#imm|q&j7S9 znBMkR5d18PVEX$Eqx+2;E$%;7))@xpD{$iFvzcr>{sE+G0VG_e*Mm{827e{mOV*Hu z#6}Vc(fwXyu4zI~JXAQwKdZL!g{K=m1;GUWfZzs4P!mKjF-f|jWYHM^CAwA~D{4^|UY6`vCfX#u2D1u58Fs$LERc6QVg zvuJ#J-FFyqw*`YZ0Md{HX%rTux4zEv-jyZ`CuB&@$4MGB>+x@n6(`};d>2)VyF79g5Jt0lLs_jjH zn#oWb$x;G>y@eW9x>Kcz#Iv5=spbctj)hBmEB@Dg)+VsSTFX@7o3A@A+Px)X%GH802gvs&?gGJ0; zFypAczP+EM0vJWG4w}zGKFhM$YmJK!m$&yzs&Yxg_rpG(gP5R#2#iy8i2k-VanTTd z7GpCvoWVulS5;Lo;b&r>%wbMZVM=Bl>aYQ;Fa5+8J7*q-S$?@x2BE~x+u_Gz&ku2x z-MRsibIiA#vR#M& z~w`EymTS%xaa*H!hnw8r8tNhg`c4_sO-J+llVW{3xe}?#1`&n`5>XOLhSWyaY z2$_5Z$V;`!%lzbmeXUYoDTdd+E;1z?XEZ38>&^yk%8e?@O$w!NKv!r`K09hB5qCZ_ zr;lLt8Z>#!!5gF&(O9grD*FscW?$jh5Bo2B!eqljB_Lt1;_bLY!;V9~VTXkpjjF?i z$sQys0TcY!vZ5#vBbaieaVFmAvuJ>{@;OAgsI{dfq#+L_O%3kN;0}_TP;&B2VxV>JzU z3@1OMeeneZFGS&G&Hw{%fTsL~&ww~h1D=Kfp%NJW7C7X;`bFU*#Qur~jXd{vAKPkzR>SXv$XO zyD5{vvB(D0(KO&K7!WM2p_&2Tmkr=lYV0TY=~q)-!`JwAHOY^IJXmow&F6Z2-X6Ttq5p=h{9L?CZ7vIjsKR8GUA!?no3{B=uOoo`4c3;A|NtJ zKmB!WChc7%PE)CuCR@1;uVfgFlgN~Fc}gv15>OhyhtBU|n)iw6f>`(T zoDcBs0L}J5&DHGil6M5@miXBls-~`Tp1rZgY^AX8q|l?GUaievV(U0naC6yZV1Q-rkuhgryO`7bOdXm$XA)9g(5S4 z%QI?

    S$Y6lze{qYGLVU?o`BlrGFqX?W;l;yGgUB1|J-4tG0obb>)WDaQXY(w?pz zm69*$kdbC+N&bnCo|&UlT9AhH)RLTMgnxC_n}^MfO{lA^b!^SvuFVI&obW+Ws9Nos~#l{8DCGb?TH3sNFLq&tfRe+ea1@b+pmA#n4zQ7nq}v- zY1^(n^NUN%&Z*u%DwQ4?+{{V8eE+uIB#EZK)N~X{t6q4E8L1=6;)u9TC4WL*pEmr@#AH4 z6L2LW07h%*j|6S7G>u$;Nt#Bk|0JGPQ=0~wR3t|{vuv&aT13NW(cTK$V9gqtR?@7I zX_xS{nxZvQUo$N!qZi>YTBKO)brgmlU`47XuH;E&Q5%f`#$=L=Uc|&`krse7Sky+Y zsU&J6*YshYG=i!PMm1AUGI}u+XpznWX|UFfOe$&J$fPgxq>;sLnBtJpizpc_()l0_ zmcWroB?%mv^dp{BQv(MwM-(zgF(fP8m4v_-uQA5Xc3ozcvJY=N{Tvi zZS6dJr<+Erc&Hv-q1N;Aq8m2h)#EvigGIkyrX3$7WJc=mTqtAs~|YeHo` zl%p%*9N`*X2|DLj-qk2S@s^-G=`BWi%!`5Ue8amE<*VKmC`+IBB4*k7talm8z22oL zANArAbnfylMtP5S5z4!~3sHK#3s7$IVxn-a_s&CE>c#gVXR-G-l*_$yP%ie)MtQpz zGnn%>?@W|4y)#f2dZ(kD>McS!(OZaetQS+O^OjO?KK|3iI}K&JcO1%SFT1Jz?H!2n zcW)n*m%Y7F{^ZR?`GdC?%5S|rQJ(R#XO6GD`1tJj%-ap+``)f7U-ROVxZ`DSN0f)W z9Z>G`;%mF(32!@;4}069yx-dfCH0o#lfGk%Hyfqbi+FX%25&2rrCzuWI97Vu1 z3zYM`nJ8y^@nGu6_hz7+=xv5_jF-ItjPSzq!7<3&7-b)CBXmLUO1u!dx>Y8i>`)nx zGP@F=Ph6Rmu_zl?#-MaoMk8X|Wv+}uS+CNBGQJXH#AT|)W1>q}sYiQUtHj&1^Y==E z@)ul0I_D2woaH>{T?4Z2-i9bUdec$nc+*g}@VZbo@nTdtTwaVShsBFg<*4t)sB$ED zF{&Icz0K|LA4IYG5UNf9&VI7+n7sItPwj8hiia=GXEQ-NZSqGzzBfGiQ!4VOdGco>k)!Uk zbwTC51}PNgR1fC`reT;QzIiyP7rY#6ux z?0Akh@t}r@@*-#ll@<8L{r)(7<96%^INX)g>lf0;$Dc@y!u^8G%|0}ju{bFCL$l*W zp8loC^c};|i=cm%r?2Z%vsc&;hpqV$p8BW;^|Pb!X-Xgqbr7JG)Cs2(!#;zzGZO_$ zrI-KdjrYRylUl_%Uf*l*b_z8x-th_yeB&l!K#n)Vivc;_VpeL(**M--ivcC`zhjs|a2yLt!u%U;UBCEkOjM3{K6^-)qDC8IyJZHt@Q8Wf&|f6*Exd--mU@JB$MOB-gs{pn)b4@86lK(S=3YP z_bRfX*CmgG{~i3EyjcUC(rBO$A~(>7TmyX+u7Q})P8;FB35w3n8>IG1MUGEu5pwKM zdwT~wZX`jTM5b=hEint~7N3;AacFzVC1U8NxM#`2IRSwN$H!=@FKR=n_70Ckd57We zYyaM$M?Y-V#z)>gh+L9uaC{ElZ)(G#f9FkLcDoMH={3D*7lyxT|9qFkl3FTt1)^SG!gv!@Ptjp1u zxMU&yf|xUKSd!HAyAnU=e(0G#1u4E3>B(8f;?GWy@9C9w@ne0e8IH3s@`Bn(4Lucy z+HF0kab!J}BTNb8=#yBNkpzvT;n0iY7n}Kdv7y2ObB=VMcYT=B7Dlvnj2V!%!A~n3>`H~hy z4smn}+oQb$d?8zo8f^EMxBta4jVHUE#Vac8i6!FC}_>j}_D3ZQfc>2fvl!V4uVxPXGY{ zwv|iQJm#p&wuaDoj}>oZTlECTe~e)?3xgX}eK~UqqiPe=q~`q5KR$Y}PJ-Aay>Olo z{~7M}fES!bY0x5f|G>l`;&NM#NwI3r<6XGg&-d{MDH0x@UDupjn_$Zdr}6d}mbH6R(y$X`pw#zIu+yX+xim@b$0L zjBPno&zX#EC^NILJ!d^^%i*%lI@p%OWu5WZmcwP8G1!*FWu18OaKSoHS75q~MX{jxu@?9VUkg$2x~?H+m6|ri2bV z2V-PRkw!+Wa{&H^C_4P@Z09H!;?#D399Lh~j4(O-ZZ~-+`NSd4{1~53k@z_qD<#fc zoQ3c}A7Wbs!b=hp&K}r}C`7jVU|}KN;hkMUHC`TsSnY9k3xps*wLy|BaCWC?OGUE4 z*)z-$y|^P(VGJ@xU1uLjStdsppQa~{wCpXpR=W1JcpD4mZ!QR}FIJx|YL2glr_RJz zkX|%ra#k5d4F50sU-8-T)cnlDENq|2yyV8l_1cs6QM?pPKT&Y@3u8@x&YFST5mMZ> zbC7SU5_dN#MV42gl!`-2mxhMjJBNfhcc^l1n3!#fnCgkK}QNS#0R2AI(Ug=MIgAz{|h#oc5H$FCH$T5&ktRXtN zzz1h=;KO)5R@CT~@kKwADDmv7_)nzxrjF#$`=yukh64GiNQECJgx)zCG~?;nFGe(G z0ju=nmm})Xw0#+pOhhrnj+)0ENGxeAeblx1|Y*&_}42r*1=(o@yVvkxpN zsKPujVM}fU|6G1xzy@Ejv*Vd+!&jYcu z0kxtB4n4r)_r1X(kxsVSzcc_C9j{}tpw49hR1v5bV9Ok(d*t{YC;Nb~GH_~w;9M2d zY6UE=bp#=6XntyoT{OF8Sx+{y-y*U#{y<2Ic%R?l>6kPm^Cu}N+{r#$tmeSi1cOt6 zf2-FuZ9tQ5OPr-i5*!riWM4|ws-R8Ib*QaY%H}ZPuioH@NM{)!H>e;5=SG#afmc0$ z$e@>tibTjDyY}^XIM+GL@$2TWJQ1)?5E4sI_bGsWcibwXkMb^%g34l?m3Zs(hf1m< z&{LfiAgBtCnR|*dpA$a#&3T6sYPK{=aBk*TPgRi%&MkqZ(_DXekaH_rM)L<_Ijc36 zPUS^o#865f^Q5_03Xd|Aaz28=c_%F2rfmidYsPloj2)59K;UJF8GVDyxEp5Nr)|dl zVa<4eH)CgHGZ1?jVn*X2Gwy{M4{Dq7klzfGuT#Vun^t+4U$yMY?R+G%4TuK~wn4OQ zY>yZ@=Wb9xrcM2LfI3eONX(+WXe89N}%uj1GKNDacATx_R^Zv-p%QTsv z0`qg)%m)L^y=CSTJhK>?8Lnu-%`MmY0GMCYW_~HataSAEK4vV>8wn)d0>MkpS0Wp+ zLeq#BV8jt^BaQ})=pt9YX4Pux5hYm}Z?8w@Ua84_7~F4#a7%$}m@%ave7jNt*PL(5 zwy;1db8(4eL_NibcOn~s5Z<6(P@*)QZ^DY>wYTCuzZHV>eg5J<5!nVr=LXpjCTi39 zF3kC$_U3#jo0BMz&%_%8in*EK02ak5L*; z7j93OD#utjzl?0nYE5fCg*D&Q-kQ@YYgR}NVo*lOSq&4O9R(F`liFp~A4MDpv6b5f zYnje(Yj4eWDr+_u-!8R{OR?vB4SVF9XJ~A(S+qTo#HQ-=u;OCvt+*sxfe1`Nx{m3M zJ;goPQ`=}ItlIgrmN5-CA*?z~%(2`c_(0&iTzgZls2b!*u@b)!90};W8qpe}Iaq#$ zHGkILn!i-md{*3B>Yky9P`Yvb#xib({U@S5_%Nk$DPb|*`EQ6lQgog?$Em|Jo&Txq zx$J8lWw1bGH>|tuA*p}RLmC!bhd&6!j6y!qBR(*U1unhHg6I<2XHJS!b{VxS5H@0j z7_=;K;bq+wU3&{+R2HO_1f~-M&3QSqP@Ya)aazVm%>f7T@Xg_3{yK@ZH>Qr?7%Frs z*-CNA{L5~@A+dw5q=*J-1~9vrmr;Y-8NTiF5W%E-v^wxzcKHO}gJ2;-XtNJ8D>e-ND)i z?($Z;XnVpyW&AXXXpv^9vkM+tuBNrOsF}*5>bx1f*_=Csz@jKgV~cg!B*moW5lxEK z9MVl-Qp?(#l%+C>ChaSCh-u|1%ZbuL{S|XsM>Iz>6xs!sJ6D_V=3pj}epJtOuC{)2 z1XnxX2$H8fSNn(-@Nv;<=?zy7Oz2d56FRF*=;AX$Up_gPu3a8qq_jrYh_+}(M!T@K z?dnl`Q+oPM!3aL<%}8ehW-e~hk_(+HH=-4q0n)DSu%d76t?1{sLU8r>U)6|jDtx+>@+BFDvjO6WLkwvPw zKUbcLdz8ZM>x)}7YA?lpO{jQPZ&1RfrI15k;GGnQ@rx6u7C>f!K4J)$z|QQoLMk&OCc?7k@0LRwA4MQ8KYJOpc=2ye}kDr@%g);ty2 znrDr$Mx(p9SZ&^x$6?F9@V4w%+43xJ%YjI?2$jznBvba^Q#?r-ITTL+Jwu(&D;qMG z>J|{CKYD&r_ZZi~y@ty4@Pms5uRMd_LpO1&c8THLs$I{sI%xWxyIxScRl6iF{$Rgz zU;fey#Gi!r|HrS|^>Qt|E?uvL{e0&0tB%%vMovLc^%P4}c!U^guKoQl^CmR=vZ;+M zy97a#h3mSB%~q9sMiO2^V;!jt=TU9W5Kqri>i6_yiKQwtX!i3ZbBxEgM^`rUZN7ue zroPR$w%aP3uyj&QSTexq1Pi_Et6~Hf^ec&qe*Hc}Wn<+lt?U)f%&w31bJrV^3tm0= z?vXy^6?h`HOIXkRHRI_|w;Hw$Q%$Rhc=E9a-GYfg|p&vJH9K{eB7LD-q zHf{U0??7`i6H@58)+N?$pJaB$Q>W`qntyA2T2h)$Pp06<;q>LpxQ#BHlQ~|vkwVvQ zi|>MuoM{~sG6Vs0IL#PCzr8=J0efTblaiw=IA@h|DM@KI^2?-u(A>ER+erhOe{uv2 z7$4sN+hNY$=1F)zZ@TJ_+b!LXq)mjZXJ7-5r-;tMl)xJ_z60 zbK!|ZUS-5{>EMM0?OYSpKf1a)o%-JsC(``Ngs${Rd<#m22Bqh1y`$2TlgZjaOZ;6t zT^H>6`LQ7C&7}_#I&xCt$bfI7tu)mblNR>q#-T?yE6p-MA4u^G^=EL(hkvN3&kjAI zZD~sbhHBexgc*q58bU+S0n$O4=H~!&TB+x=LcsZ6}q8$K7XQ zi7uwbyQI`IuG2Um%Xb-lh0T_}&Cjvf!ngSeHZy&jA7Zn)Z}S8O=|_@3o!Uq_I~6mM zd>q!T^!1WPhL}%%p0B!xXx_SntIWG}4+gQB=4B>~hZj%j!XOvZI5w*7e&--xt~Q25 z_0vlK6>Boq81$mPs8sEDIF=31h$*X@1pE-o2^Hp+{-+=<;E*D^sUrU;e7Ij??_BEu zvZC}qit4;c9;H`yB~-?@(RI`{lP^ROgSD?e$q}5dw`DXGNl9ssaNd$#qE7gJs<&7t z659bXeK=wT-))}j7p;dg72Nkm8EtgImJFj@ZwB1;VsA!*0<#dzl2Mpbx)xIRIUsN|H=7Cp8 z^eoR#COz{|VPC)CzRD4=dl6y5G_K1W%oQ~Z^uGOmc2+n*k~=a}19*a-_q>~5c1e$W z>UwiXWz>0VT=+cW`d!5t<-!LNo#ZX`7umLMII=-pTl;+!y|i{c?#?%mF4p9_igW(v z&iRKwhj~aPk$Y+W{Dky?g=#mc#I=|7;-xL?>kB5=Ux52J04MuKx&GrZeRhbKcHUs}YlU)CiI+~XQ}9_MEk1Bcf{>OF z)R|+^ym2@6uJX0iSq2#g$hsV4k_s~5{?rjk7nsU9h01xR;!OXd0$DMHx_K<25xA*Q)BUIu*2ln8`lX#bl8%iZA){%E$X((WOt5ApB+)W9W5f-(M!{gX0W4`wjHg*+99P} zlk6};cuD0zla>?Fj9g7KvS3C#Z8O^Y&EUIcNhC9pX3ODi$Iswjg8&m)IMcZT{^Pg8pMwr6TXl?!lZSNXcJ=Rf^G7B zx=ZT};9lC6JroXl|1N_#g$E}otS8A6! z(!w+|?7Y%0gCbhePt%fquw-b6C6e1yR2l0IDP&)9drBJ?u*~PW!460p?z^HCTSi2* zrN5>vLjX0Z_O{$2+X7Mkw9)=+I*QUA*@~2E+L(x@4A3+s52lO@Zwjk1`%!&0OdGE< zWrE)ngOJFndZ$f{Xw5)PYsSKwDYds|s>+&aDr-!TnGLwelVMF!?X8)v zvSxeyzDQ18Ie@ZBFfNyG>==T%T=B5ZJhpw{2cT+lGYL z=F_20Oq*@g@6ydDGcZ~j&YWqn0|C|T9Cv{9p~eEel}6=EkE>8ozlKdKv8g$R&_ zSE_D7`E%7M{a#&%s^Qo^Sv3sh@hW^AY`Cv#Aj&7I`k;Kcs<-}CUA?NV*j`iB1?8$L z%yH@OR^d@3{mrU+C=XX9p?skVZ|~^`s_@8@{!|r~=WOK^lwVe| z;q-AOf;`er{6FH}1HP&1{U6V{Y0@@LN(-fBlby7*rDbm@OIB&i-lJ@gJ*7a4;%=Li zDhCxAZvCKAP_A3ikA4&a01ed>@cd6T%!St5t5I9lJ=Lf!>kZXo@T{+9L$;>6 z6wfQGOYq!Ujry}zRHOc^YpX}$xvZMaFbk_IN8o?u)u>YIv}#nTbwc$;c$QWV#dAb8 zn-T|C55}`!HLBX$qk15oovMrQ%&i`Pr@NX>;MVGXc($tUi)UtaA2dO64Hi6m-6-nk90i*(1i~=R&cplB^#fsWpl@T<@j6^b$pJ}7@tP#3RK$q*k_9kGB%gU*z{7e z*%*~gu_hagAM57W*=z~2K>*FOi!5W9c->nRYmJGDnZ7D2qtTj-Hi6M)N=AX0u-0us zc+PscSQ(OAi1i8$IOZ6T_@xjO7YDQ-F@46TO}*+3E}=vs5N@WoUJCrHHSn(q;zQ~z zyDFz9V4}BHM}d!s$tw^j)go{e2>3Jz_=5yEYn`$Jwnt$gc}A3}LB38f)Nxgnf&58M z;##s}fUm{R^-2notAcfhi~&_L*r~-pbW%ikCbsoE9JZ@I< z*saB5=*7%kqM#rmK&rrFtTvAu!DF8~k6R87yoZoX+AuZ~Aq}=0R`8YMj8`D2%C~(} zIqR)TX19fyy(n(OvFqr>?rlE2t6wR{jo(Y_reyYFVF4}VIeKJFVv)hyzo4Lt6xFnP zoSb8Q$J){Ciu98V!~_-hOj9*bIpoNV1j0p%090*5QJwY3JKadZpBR?QReo%>gSPL0t zHXZPG%JsO=bF)=kN+xPkIS48bt5bPIM&(f@mB*q`LG^daS>C)JUk zk|7^aB0n7k*>s@L+d12nr(OxTuvggrM%wqSPk_p^>QtVSQTd;e%JYp=>DE14tvztO zUW>|qLFGktDlf^XysV`1N)#$7%)6$G>u~oT`Fq3sFL3%_jR#~~>rwphWJD%zcKf~v z=ijZb%h2CYqQ9wy4%d$qrw}3A)xUFOP5gVL=i@c3Gt$2W2wD|eamS$)h5*2k$RJj}sv0V2v?Nk4rn zg2Y!Kaax_knIH+ydREyneu#xYp$dWTA_#mB0za!0_(ewGS0#bpVj<8;g@ECT@NW4N z2>hu|;IAM7bW7X3x$iLD*WrM?c}|0a;1UHdB>kN73|cTH^BQ$WB*Di85wMEvT=fFE zUyIS!^gu%OeB~=MUd>a!GUC--`72_h$J<`fMmFqHQMNy@fg{>pFfX%H)~9=x&tSW3 zPSqKP*m&D*+i)(Z>duNwSx*$S=?m$ZG85K6oh?D`3uD7goRKjY|A{Y5k}Xl2elD}% z*^)GP)AWlr`&pwM)Z%VZa8J?Z{^iLF@#9IdSsLS>s>+?SHDO#d9gu8kGU90X^gAn@ ztZA+h?W*S{X8t7_sS(?;Q2)ix7e>BWW8^bb$%D_4hPH^bbd)=zRq>fJ{+umKz2dJN zl9yO@{;TgV%!w+=*0M4Ftu*-aWd0=W4&O%LPS3q$Jj6E)nO4Sewzld85GwydJiwZ> zErDnrH&h2hTS%TyEC8a>)*j=3p?v(O+L-#r8iNy;&8BJ|6dcDAG81(tb>t`VH3GiA zi~G36JGo!r3m+-jN9e3)jpig=MwvS8Q`MYTdJW%DrCi<7GEMR}2d!aSD5{PM*7 z^bwv~G(*5D{v5Icqx^1zc50WdzWKVo!h4hVXNG})CX*TE? zZQX;>_(INFfpB?}ThsXBXE9!TsInAd0or;AndpgLj0K2&dVSGymprVWtv7R`d6HaC zZ5P3V5bh9)$chCV)o;_Ug{w^zr3GDeg7f`bzm1Y3JYX!t>{Bh~Op06%3R- z7$|TdNB?^E(rJ2~tw^){oNZ8)zefnPvMH&E4+Xa;WHUHQHbaGMSWHZ3t28TIFmrXK zh+CMeE5=VSej)8UzIXw`bDo$pw;e6$kvfGt|0TuBH-qZO={wPq*{Mxv)%PAa!X4!< zp_PL+cV{yrEuE4o`d)#=MXa(aDTgR8JC5ZU>GKoj?n_7CT&G*4TaBOPxQjjAOjj10 zn$`Q8t>zEhoBc5%KhVNumLgaobdq!A{d{3B%Ot|RucNj{%pP(NElfyp;+pqkJ}<(D zerI;E1$G856=eJta<<{DfcKCllnk zbxd8(ub5=MkYBw0*^J+Cy2yvwml~=56!DU?4dAjuxbJ32TmSwzkdR`jBsw4!xr)J_{ zO<7ho|N8QrWYYeF=pVKuj%KkN5pk~?!2|*>jVyMn$u=7!8u1R~FAcUC7|*oH-=@Vz z+f*bgq+vb@>5Wo)Jkpm)=`l!e5Yi@F$<8*_2sCn_kLVcb5ga3JFumAHgEf^J>Uig| zhVcW&7vpGkr&Bp!MAS3wiqiQ zFc-)>IDLxb1BsqFj%6Z-+BDJ$o62oX|&Bn4_*|;dLw}|GDcUGqT9AjvbD7p;OmQn z1!@D=&$$)7>PizOS5FF8&nsZMD13j*W|A%jW)odEZ-)bl;rfE?mi)WFZplGaT`Y4{ zGuoD-g%C(=ZHGUIM&Q9a`pp$KW6NcK$JtiMggy#)$|3aouGtwHSs*MRLb=r-o2YdN ziSrlGu`R>TYTEEYNq#VB;UfCliHgrzYfKB)4R2kXvlaAa4L) zb+P4P5>AXFsNxwWh=l?dX0pJAh*HR5lWUg36pl{1X+aGlPw-<{n8FTp&k?hM4fC`f zc}^D1v5q9_Y^%U@y`o+=gw@LwR~7tj=jz^Lp0wDr|G`4VlPzQ=X-!fIi5|vKtTqIn z5UR~8#zYe%0NP;RvsEadH_4&lC_4jvOa^;yO?X9e)`SFdf=A^1Q{=G73^5y& zSzduGuMJZsg}f$h)sjL<@|x7`1fI@T!-lfxVMPSTnS3lSTQ6VDky;HElMow+esb^C zg4?thQjTxE?()xw;TmLEr_Eryk^#m%V^GhIzF>S5GKaG!VI;1LPU2Y=5`N@KwMpz$ zC2@mhHQcDdVEdRvoUv%z&+tyYb!8uLdWnX?|9zm0e(Pt2Tq%LJYcu7~HPO;Ew1FEZ0PKj$6RsZfyqlgcuZ&v1Owc zt(k{E_z!*3)K|58?vKvErNZDYWO%rd>8nEJK2Uj3o62ETD!kAfX=5=tubHR8<)P?Y#;b6709+o`=JJ>-m&X-d$~j5Zp3*kOJbxT)`wYwrNVjSD$9I_|uy&&){%c18pR^ zHybUIAIPH1%^dk}bRL(h@OTQD|1WkP&&zncAo5W9(+NC|M(1&}3XkW&L}(4YNpGNgXJ%UI>HZL?x6ICLepsB+9=s-UN_z?P-iV<0$d$PG z{>>;(3DD=K4|X%pm3>!Wk$F4BC(I?`VCfB9m=nUrtMz*N>B}-QBaovnJs`{rj5MoYD3%P(N2k{X&NNrJ|HyX`u?GEcE7Nt9TrUsLiissGkA# zTXob^GSu%BsNZX$3T0JAt>gDp6b|C}Px7v91K4i>dsZFx2N~>-3fP~tU}42Jcaf~v zsAK3|0znMKK0oBzub3o%m%^{bb_N`NRp;C=Tu$EL&fw>t7U8FJx%OIHDT67PTEs@2fe%$U@f@cqXdpX1o3?P~PTLJu zN*yg5o9GG(F#M-$1-!rDtErE`d-^Jj?*tL=-m5V63Klokp&1x4Mk%JnaR6tPySVzp zks}hc22IS)5ZRN}F-W zs#I=gRItR@o2XMs3sDK0z7_>)plK|yJ=JR9aRv*cslB;6Y-R|S2qvpwt+$8)69E_G zwZ45Ey8sF1-x{afiet3r9!RKhC||kpN)i0PXt&~(P5v#;-ikl**0t@qlnj)hbt9%P zdmB~L7iSkNS(3zWc4bly|prPkLyIjqAv)$Vgr?EnKRSQAvH2pCn zJQt2~Ia+3Tdyay92W|2}Q+Av!kk=Ubd{y$Cy`yFeF#iF2fr5CUI`Ifoa9rd~cKD(< zYN51uk!eOkXFFpxizW+NTf_PDxF+V>3Wr>U;R+}UWTwUxJ1kcA?tTVGeco74SOUpVJVdhty;)b_VUaA;YG3*r#DgBEtOEKU9{ z@L|S}2iTpA)7f=5OD(Rv2K7&6a)LgYBqan?)>XzTogq;O+`rvxB%kx7I&rYD9Nw6? zE3wASY9hTRyN7g-AEVt3KfV9WdgybZ^^lO7q%eN}pHxbM*`UkTkf7x5cR>Hw}l`Yym>_td>g>i$lLbhtM$}l-LvZ zi&jBC`|Hi`ah!eB1!L_NjcGNw7FuB>u+Kt==p=QH=|~q!=_yDTNa=}4cNEel`#AJB z7DYttZzg*g{+%cL_h|e(H~8-~JB}{dOQcdhCO2CLOX;QFyg3=tjd}Lc3ohbbvwcj| z>J)(}uIB4SHqav<R17bH#5+eOiL{b1=M*lTXxYJ%!u~cVMeQI==$Z1T?`gLnA#{zZIra3 z4WF1>N=88Y+>o|jGAP)gq14F?3he}yeNVzv_6LbhcQ#38MA3Z)_|)d=;W30;glcf- zxk96FpM##iFcKCg4dt*b`bJx#mi?oI?z-C0icLGcq|1S7x`u<`#G+khZVQx++1zAh zQvunX<4Kr{Z}DX}GB>FzPlvY{(%b+N?kiUoX9>-Y{-R}YO3Wg6@kdC? z*Tk&Dc}AUmrIG}T3Gxbo+Wkm{`4{$=-O2V=&06ZUK73KRPrnoq6R&r$Bs&g<9_W;q?170U5|6wEZ-}J4`;EeVP5Uh%e;8rEUc)Og? zvibp5D{a_a{D;)G2*{>vTXr0FTU@j*7iiVn=DJw?6u$7(yf+A|yp~z_tABXwl)1a* zW2GbM!nOy)v zS>Gfxm)^1?M{IR@v>>FNdS0caaNQfFGM7Ze{VO@mE4>?6-@C74sUY5G>waC;T znQ5IeQ?tw(dk>%X$JX~@)J2dMWwZK_*L4xvo9&mMA%Z^XdZxiSbb1IZu=znFn|%jc z&?FPrM7IBA7FglF2RqeJ?1|Jj-vB0i)tT&*F}X#-kx7`&HesMPjXj`ohdPZr zWi;+m(70QRMo4Adzhn5(Jf^cv2n1zOsgT>jWPccwLrn%ACz%Fp$%PLybFp#C)S>q> zcF<`ile9Zp!6@yh_|A!DOp|GY#`!mq&U8H>VI9?4^ zzT)v}i15l1Ad79EE{Uf1T2+{AZ`hwu6Nm&8Rs~GK`5*ioY)qeXNJF3V04utNMlDIH zQF~CK+d0hs@ZVJnKGawt9@Z#?5VJM5LOiM{#A7iO;!WdB=;-TUm z$8Gx?p>2B-!DUjfnKvpTZ>|*X$^DVDza?#*SwK|g%uBvPBYi|(5}kSNZ?nDhG6F&H zJnRoPb8241P8#=|+uv2$KEEeypDC{G{=42bLC_WVQpE5KbEK8F(aRLBwDu3;l6rAm zRxUj6Oj5cE>d4z0I3isy+Dc^UO*exmHa8~s1Qp; z$?6NR`Zg|Br;N_H5e zV{%b;Zz}W;h9Wt?A5U|i)@lbXHCh> zp|4FbrCPilq|HRG; zI4ySAO$0VIa4wRan-_R!2OP1VLnt+aIuB!r2Q)TPB?&Z=v}jJpm6!ip4={Om}TOK1+^U~?mz046`vnMH0lz5MQr2E;5mCpyyqMR~~4^qAnk(o=+VvLge+5Tdt)3qy`Hbd2Uqiup0Q zKyf;h;!x25BeY+-&QR&)cKDoa8HNRQ$AKexj?9p(q&OJ~!N$=-Gh>KEIH*Rqnk>02 zVtM;020KT~Ch)*KPif1GKW=g+;2yww;W!d^ zNLSAab6FzB{%mRNhi;zFU`h>=pbVJn$U&c&CG`&v(le#B6X_XJ+KN8miq6>0ioKK= ze$ugegr9+WJ$j?(k}c)(lpyYGphL+3Rppws#$Ernjxpd@fOvty4 z!BHfgqd*&~FbI_*gQBFyQWAESLRgp`oi&i8g}FSU!J4y9R29}<9YLy_HmUAGQf3*c z9@^#a8J*Rf2v#jfS{Nn7eRTBErqoxJQa^1<{i9Qwt3nB<+6Ee43|q)H{X;S*3&&)DD{d*L)nhKFVck z9z78I*U0D`=SOgCt|t3AE&`L$N}kS;JnAS3l9XxD9i>9mF@ihQ&PIp?%c2up5F^22 z5FDpXaD0%Uq81z8HI)eb$hDDYH$;9DHTWGIlfW@|O)FbtrO*(vZ7sgnsu_)CPHan{M>=ftCYqbIg61e0O}cqAsCBs-(Tf7k5cw;uv%5qYZQB7PH_Cr|I#R#oMVS z-~{haY`k9@a!wRuLO7N%xdk#6ZAi6r=Kfkwk1Wpd5qJbqZ?A;)_^>}4!z8SHy$-<^ z&OU5DhG+ww5DS4X%u5*|1{~O(lZL1eMKki|F{@-Bl2#e^2?n2ij&P2pVzYIK6jm`r zIt04&GSy}g{M#HWSPp-(BmB2;t(cHxQVNb?65dKCq%6a&YEdP|)xk{f96Y zLQhrn4A;e+;d&{S2{AjYbQ@WhxG53cY_2ZPOvyy^i=mopYUGZP zN68`bA94$!A)qaS#;I+o+8Hf70$7V74XMI9ejZ>Wzb_!dfRcG9^>1MFU};id|v8s zwu5mBJD7}!CYMC|Vc02bKD4s@;!t~gaW@n$VtWsLw4plZEAkz!>%6HuNuX!*QpU5I z>`4oD=NJi&;wDt$k|%5Z)>dPw^-Xh2n(>V#O*kda7?#t$DHbbBt*0+uHSt-NYC}(u zY;2|AmBTqIBNn-h1*b@IGU}X(3su2|PA=+g)fQqd)m-295Pr}7iwALr8ieK%R0g4K zgSwP}bJ&i{Blrcy@GC;xWTMQKu}BG5X|R;Um!(|SLHPzseNqQAv?A$BPeY2MmIuGaeSL6Z>FC#7-}}e zNDBwK9oh%E9kPSmLqi)a@gR32w6xB2OD%j!j0AD2+o64`+aWvEEvq;2RCj>j^zZ}4 zq9CYsz*{B=8f&)5SM2}nOsv^VSH4>^f)-qAHq*slR9MW?@_rY7w@Liniu&UAM#t?~ zp2hGs$&OnfB5sVaz&J$ixRuRm>LOyks@M{v=yh9^_3;jdIhj_tss^()BIbqiPI~MI zbDsW|TW;YCIh;cX&igqkIu^{ccQc&W*Wr8E%CeE3Ott(N%vsPnSh#P$XE&4m4&TFD zv-grxzVNne4sJbxxIHxx8}>7>5!BiwJEcB#)3BHe)`?iD?FvgX@V%E2xP=}$Xg;bW zz+7W<^()9iTGuD_cUahGPoDcUkIVlG;T3+Lw|RZtg5~v3waQ?NLI&Sv;ATSj-#Vub z1+Dvob8%!ozE`dlX~~QXtGW9IRxzhX=J6B(31v2gmHet&I0Ch7L>Tcu0Gdd02Io zc_fxq=24ARX8V}#e6OcHn}L64Gq>z0_G_u15JN3O{DjpSR-aX+>Z=bA_D^WDe=@{= zWM~Ez)REG}K3!|4dPIZ0ID^(ga}~xia^+!q-p38x3Ed3gwix&4?6#Qp^nZJ|wWm3o zHda#0rj2ds7kjr^EAb`aV5E2b^q;Khv%<8xbC{o`Vfl8{jCo^w(ie;tMEMTgRims1K$cf-|;QS z^9|oJJYVuH#pNOHXMIcXk0*R^y>{R3gUhsgkFOlh8+^0ztoO~rv&J_Q&nta1@Z9Rd zr6TSM-!wee`ljN!+&2Z!CBDgcF7QplbB=E!o+Eq{@GSI|;Mu|l-G}SEuRoq&_`2iy zvJdLEO4kEE5B_nJuRWfZ`m*p`&2mC)5JK*|!z|PG>Fhcc#=Lf5#8C$lvi^E%JA~P>cK>l~32g z%ggatEh^m6P>ZH;?5kn&*G)C3WXJV2sAPw)2JnunYf#CK%W6=`j)gU-WXGhMi}4&& z1452bHS_TtS~CyN0X1{+>{T-d+0FM4)aks`Uxa6!e*m7>`a#iqxxXKtm6iU!_}?Y| zK6tM7L$l^x>hFc;0)J0DXZw5LIn|HSc*py@;aTE`LeM+h-v!S>{?2&z^>+eTml`w~ zyNC$SX6)7%M{?jgB3ShPt{IQ#ugXh_@aF59$};@#^O{mTPu8Fs?H@IEPZ7Sey9TAP z@2o*-?AvQl8hdRGN@KsK28FR-QG>$RFAcxT$iA)yg|V-yL1FC6YET&aV&<{0b3Cg( zj03^!6>g=D|H&pHHjG)&5Lw_7QO?i`b}y4Nl4=vB2^e?x)*4w_bZ9Yy)oVMwwFtp< zV4Sq?e;Hp%5Wb%5IEp!5AHzJrb`t-^&x_F(o|ohnj+fZN166<3xyooJlUITn_TuRH zzg!EMwjeWNpQSLKyc#v@H?1X&eCUzsc{odl4^6+(+auv5cEJ4XjpnU{e8iueIyXh| z)9K1Njs?jzw#>dRQQ957wBl9DOf*u-P*Htv1Un2bLA8kRH zS?CDdoa4)Aq!m^16-8C-OQ^(uU!-#;| z8{ITpzAt^1Cg#sy6VN*{O?0Ya=s9(vhh=3xi0OK}0CU6=g8R48R!?$wRs~2G`zT zTI?r|&-QE(Wd-kJ&j^e#XFH6rc45C1F3?V-$0|GI8J(^1g|=Z|2>x{o{IU)E{GjL=GA zU-iAF$Q#DKP0V?>4dfl`RO)OWbKcfK-ao{~+vKzh2k<%Ft+eb?%a1Y0vrb0b*>_v5aB2j_HVBd~)-FKShth4@3K+8?qpmXBXL zw0_wEzqD)p(u-f(!hiYXv^kxOP8WU!b4?^whG@f&JLY!r#8+o-&Y2xO?~pL#%!xbi z+~|3SLQA{ z99=ob+>Fm3U)-8YcCdXQK7#XCiTdtSvF3EvthsCSh_i6$?A#edWsU9{EaEi6LQwB# zc2c;89OXL30NPCxREWVsArrh|yS9hUYu2|VLbL~6cb&)lw(fb|Bf9;%-8#SSQXNju zFVESS`I+j6?pvNS43XN7zU#SzHr!=6&Zx~{Tk@qQXOFnYdry&YO0bnG1+$*FvDvnF zu$mg#Av^noBUHtJAk8acloO+~6oWON4c6{344y14E;Kre@hXqK!oocQ>0Bv|fIGDv zq%%p(4YNWMrn(hu-rFcV^^^J`lLh!(!2~>pZOD zy(M((AWJiT;P_$}(OY%nSjBFp#}}EKR?!1fQrjHz zmyaT{GJF%(UIR#{`npy=Vz0NgZq1@Gv6%qJ#iUD7%tEXNu|!Pz>q~c6TT;m96cH%D zroFE-&u7%0;GCnwtNR7#mzLrcMx`|Rtmx7MA)TT zDFl-fVV7#95KK<^_c_HFK{BCAvn?j8l;e}e%KZkjFQ?|s?fK@&YsM&Esm5Y^UxGLto#@sj&<}rjRq{UNA zzEFN*ufYXzf-Yn=csJaMNV8|+s6D~?FOCkegq1Cyq=`Y`gBD0A3!m|Jj00Ej%Zmed z8Ng1d|;e(%JqA?#H*dgiit$2C(5RMW+^hWAqWq6n4=NeWc z|I_PH+;njc-JvK5Ymj%|MuYFL`BzXTihP1Q zHD4kBC6AB;X2sbXfrT$kWYMvH?!t~YYd8ui9h*$&jk*qBVF+(69q z$PCMM^#ih=l$n-HPJi56!#c4RWK!*wI>Dc%Q9XBkuxL{``b&?zes!hEk@B?AOfq|+ z^E!%7yPq5vgclj?`7mLcZKb!7jQS(33nN{MLqhZl+T9G*3K$!9H3_Hy~Zi z(%s2vX~ww^uY_u5a~?B$U@8Jcj1F1Sb!MjyB@1r6BF!xxP4kPJgG`bCt3>_O%FM5hG2m@A#Q{1w$}*G$uMf&0r2dyh$IK zGeRbx%S)s{dnWc0jV9?iqz&#C)aicEeWnw1$+RfFaw!u&M$uIj=1d+}>dqiEotmwT z?mEu-tWfTVDPD8G@Epb3e79j9jxIh(&pz#aGLF6D^KoLmAYkd|LDzqFo%u){NTSN-%^4bEwi4c@62ggSK6ep78M=hVuzBP;X->lvtBS|G`gn~o!epul3d)BWxBJ% z$pq8zK+h_o|4cRj!zFblZZkJBA%uY1FPUGN6tBX`{K}+w6;9??HdPwZ?;|}$N+Y&c z?PMv9*j}}hr1Wb55~FU#USJ^%*HR*{*~FN3%kRe7FW(c#q#UR%J=$$^qfMycGIuI+ zTQ0fGCC0P0jp{$Am{bJ+xuwJ?<}Mi4nO-?9YQMlF8P%6gfgt(PCEkr&nPI$-Y4a>P z*0D*kjAO2SW#L-|l^t5ZwQjG%Ox>28t1p~ePuA8qwCc&7*YR~M=g78DoHOK|7dz3f#6AX@Ge@~{DSZa%*(|L#)qICv3L#F^e)%HMvrBh^VZ;^Js`4#BDMUnIe~LN1Q+sAXJ|zoX31Cv-W*su!<1 z#wEH!vWkd{i{uO`=W;!||AljTnTYO%%f+e3#ry%6v2=HmCh8Ad%q>ueztBCP{d6(! zKq+*Hi+KmaKZH$mF6JF5g${8gBQ1swF}jRMFOS4ii8x}<@_3x^2_A1D7rXB%f?nV$uCl_?~4hMbBSJ& zjUa{g)h@|5@&b@V&&UXoRBSJ{6J=W4kY|-k@{f#b8Fh0m(Md9P7|B&KUKr6+G71b6 zOl75!{3YXs5uGNZz=Tzrj<7HcNNt&;=`pt36&xAzECmF>bBuI|j{uU=v4Eyfx>D6UHgR$ZGD@ z#%m7!O>}XLy@dov$DV|{{Bc@H&7I;cmgw~uJDlYEC@WSBo?|GM=m8l!P99~t4bc=I zZ<$1o$QZFWoh#@U87h^yJ&E4UQL2zi(sZTv2`CnyB@mU-)lIC~dGRzI~g8w86!E z`)HHDO^b~#=Gs>weTBL9ZIsfzk-kJq_dt4sl*Un3S5NgJCf_P3O43UxNdoj=@%q-d z`osy zZ&Q*Z2;V;8P&C{PZXC_d%(>v0=QB!U6^?m6gOrA2o=-dwZFIpg&!?B(!!gf?6O@0O zdece!a?48(DG0z1i5K+c@Vu3BYLoa0}tg05moX@j2lP8BQaE-FyV391(rv{BQb;%COrxl z8!jcX^4t`I3}kZ6ju;NY@*428)WnnA5@mR?wUdT(q9%^uoTw;QY&aVJh?+PH#deYl z28B1bZQaN=z?pWPdJY*SJdIMumr^@h0~r-IH|52 zyzt-iNr%>5@Za;LNP`#tdp_aNy7KEw@me^)-klUkvioAZN|OExkuqFM;v9$iJpz>NJM4wl>8en07>+6j2%hxb-Vy1(c`fZB$;+Z@_URI zNtytp!0s1nfQ3oeLpLBfQ1t&nCbbQ`bjkIulUO9&0?B~O|jqqjs3cMB$)hoY! z8D0wq>y@u7G19liIsPseN4jh(|AWq&m)hu(du5zBSBW@sTS{*~nCPV7C zHm!^sOms+$y=d2oMVohFMH5{OV@IPxdl{K;Mc3o;pQvz&Zij*%ltP>A;BT_cF*T-A zmOK#6A(is(b1V{X^xi0q_V#R;b|*>lV@l^+Q!+WCvy#znuFra-G3Uq69pokJlj*4+MFiIr)DazIAMrOPdB}WlP zp&pjJ72^jIofYLkhNwW2%VPXMqQ{~fNYI#RmMGx2DC-Ob8`xD4jd=jOM8Cy|p|2@* zM|v;*8KaOXcrP9#MKt|M?=S(7DdzeiaB5P3jqB4uyd?`wR3%-FqHyiM!Ky)*m+mq(Yj%cDBh3qr9(5#Rz2Rl2ktAJy?*Vt8>Yf2DCOoyvE?(a$HG%EwrQ zqn}SYj_-n_pHDiD?}DSBPdbk8f}@{LI*#u;hIFJ|5ffEBj@s_oOL4)eCyK6!EP(6xOU)q&mFVQK1F;e zRNRGF0Yv}C*pZG0km9xih<=Vykc6F3$h`H5fE0IU5FH+)z=W+zpNlYY9Tk>_s&oe4 z1+P0_H))8$>&_>gfp@{{&L^CK@62MN&?A#`IvZVZzw-%);X@)dobG(WnfTDFZ}3Vu z8XtP~C0ogOQK%_73Lb@ua%_vO9A{2u-0(&7NhjmodZeY3@opW`(#d$&U-%x0ucU5HD5<`OEDdi})hI5Pldnyx~s4EU_q1;J)_{0|5Xmtl1 z_rf~0*39FU9QR~1=oK-|Jno1HhMEwPr(XOJ0Y|-1S@eVxTwhg%5_fuN(DaORfVyR_ zdaO5{A;)khUc4apeQi7 z+aO&erCTB`oXE%DHpeW{Dl~ZITVI`|G!CB+-K{UQJgB?2;aGY!B_;VOt?1MB*#kIt zyMK^*glk`Nu%Cz!_HGt9P`PdY07JvCPqXoz0@ejCi@0(bXAWcETDv_Vv>tIU!tMy? zzVOD$31uJu8t;zq>CEyc` z&TKy6}E+Mqi!{^O6LK?SSk%sb*?XlgR zkRB$b^D%}yhj*0lrt1>w^YIEy?r!0kYcyQW{jw3{&>I`$j^1(72HWQ=RC{Cql?{)#6OVy`9q?Gm#XFP_`WJjxBRd2R@B8 zNO0g2$5c;Uw>YJ9cZ3sPc<&Ot_AWU42+uu@{xw|aU&6!?@9gGeVnbS@?pNtvZf-Dn zi_E8Ik8gV$q0bTyB={y!(lZewi+QC38>Nq@~mE z?vY4Kr{CSUSjIgneBcCv)@Za+acBT_XOhA&$k9c|EgLlCT@^#KyChD?(lE%;^vTb? zS@l(Oro{moaK#G=htk5UQO>bpprt4$(Wk7415(2$PkoxlNShD_IR=nt^HZ0_0jc4h zrwKVZ1R3AH(VgU;Y7#;q@g<|naS!K-j+@%hGkYq`eESs@x$GKr_cU5|(DVcCKiS-b zG^72SRUDxOy;2kTSDrO?;W+nn9{Z#sLaXkqxRi(3yph!VhcBdO%1jBQ110xVc&YVu zPY%mz1}(bB^ap?LC1Zk~bI)Xdc&~5;Cx32Y=3hc;$E6h`cf4s_U-|d{zaR2j zzDX7NiF{2?An4OE@*;VYKXP;NH{|ejDc=x-Z(@S(A>p;go)5PeWg{qmS$alUh zUy6KRqO+;DH4l?nQ`uE^-N}wlDT%Ci)#aSr@o35Gbk?)R9(3=^MvDYBDI97ppcW~h z7R#Vm5iCT+y7aXzdXBYcZlfrZ!%-FjWvK!M0sd4gN+M6IcAMP-ZvDU|Ptey!no{J& zm=X?vSbXl4Vb?MpYBKOg!ns#TH>)*6W36UAtQs{|LssFRYcy_7+i_3EWPb9~8CUBK zzNyl+Np0#|Z_hZ?vGy3D-`?3QgQ-H;{bcLaK{v=iFHwSS)BxQ+W-zeU1A2E$5{Qb+9bmk1c z>DnANfx~6$9JU2HaPG^Mb#Mhu?_}see1{6EJ~Ps-ceI^A>;6o1(ph^9&FG$~nJxK8 z_O$QF=+X8SRyG=*5@xCGr8m$A?q~)_v!mPt!IXn; zt@GvwZ}zorAJc($n94`7qXZq_+w6Mo+GHtP(;#D7@c#)xrSF2||wSo<~)^jmal>iSkLuW);U2g2~;i zN2v-XSb=r!dlbURf7qARgptE<8gC{kxy40eCR;}inVhZT?|REPg-deZ+ZeC=G{~a{AALl;IxSi#Ho|SCDh~cAh;oJ}Nv!~?TglHHal(Y{<)ie+xetKQ0 zk#6dqS6o+`LXW3+sD$V&xVjYc_cZM=iBRi9IT`dRY97E3m^613p?5UzFdgy&>1Ej* z2&_TVmZT;h&gwuQg5_4h`hke-Jl~?jL_!h6s*H0#79YOg0;7tbFT~v-^w?5ME5_u5 z*eD2BPw)wQz3Ue=23LZr(|-I(R~DZf&{+dh3wT_(8RD(@RHgM z*{?0%cEaf0L_ff4r44U*2C{DbjO_0@_kUI8uI~CoPIq!H@}}vnI!vQ`b1hHOy~A^} z=zz`(o~Gx|=Oi|7293L}8NR|kHx>DoBEx)rk{Ng8}86~UCrL_8P^Hx^- zZIcG+#z4ni)Qq0|e*PwU>66}^6tH@3SAuV`y!ibI9sNwz0i*kA{PutK`#SWYC+Ey< zOAC6WmeRUzmiC;zkYY$~B3tXpCOchG=QYr(>*gBh*_xa}%IzNuL-hL|czhn^GRbiE z)jBpqCJ?gIKu^AvGmotZi!B%72IjI?whh$7{zFf$Gqd6PMlJKcuP-ff=2dQW>=c!_y$3&d>G8%R}4ls7SO4M(AFb}BvcpxI??|C8=Z z-4Ar-GD`;*x-^4Zqhp?bLi8Yex^8ZPt|0J7opkdNW_E_fSzp*1Ctq&M&c*?lv!9qp zkv_C&dCqW>S-&r<03uD%ZZq`M50#8(0soUQyXT>=>0f^NWyW~{UG|Z;1^s$U`JkZO zk!=u63+&fdqF3~<-I zyFR_Oo%E$AO)1?FvZCnTQN{G3KXZq%&UBP*@qZZi!T-UB7EQFc`8JdDwqreev973f zAgq*&FPfIOL{G`6;yn7+%sd1K>yd{b8%MbuI`jUDHuU(*c^P%324-P%P}l6d#rpH- zafMror4?o<^qct7bYQfr4Q*Cf?bG zlwNet%f?h`bGafs^LLT?M;e)bteW{?J(quu7Ot|~Ob?96-^O>jDgQ9)Vr6*FA0p?I zkuqdD;Z7QY(o|Zqu1cpvz!dilKk#BNKC$=a3N+#lct>o~H z1_$vrZ{KPOE`wcVmqc3(G_>K{_v>^VfL{RcyD&iPfj=YZ$(XB94LYXRVb$@y4F0qd z{)`Auzh7IJ$p1EZ^Y6m;=5TJ4PYed%ny|7a@$F4x81yM*`eRJcKgpnfRzm+GgC>NZ z?Z2iYVMFf)HjPUR)@m{M0StbRiNPN-27f9U{3U0QsLo)W7K7iw;CvVZzR44*Xm5`$ zh)Fzwa9e*%S_luP(c(M)SmETI-*kHdy==W4Rk@uyhg;PRVYs5|!($A>a-Kv*Q9Vgo zp!Z}9<%d4qeF?!TbYN;`K7WEwwHR!?`a}N1J9@HB z)Fs-WCV-}^gEp0cHdBITXn}GQKc*kw(esV4Qg75IkOl%-6uZUc7oLOA|EzROQEw&G=A#Hj8sLV$R*-iJ|fz4Uf>sc?>mtHgntA0b7p(j%- zBntBq@d!~wdG!4?0hJ8|8*DT8)1uB*t!QcIs+90Y(VcBu9ZD;%5N;j&oQ<1mHf|1< zB0$#DyBD?#Y8nJ}LmEx*XmZlmrkK7A+rLTs_X>Hzp?FE6uYEerD=J>Ty0v$v(UXbt zw^eU|cCrR&uWSITRs-CVF_>QT%DPOZc^X6L{WI4a_=W{ph3I;lH&33u!yk|_N&s~!J3%}N84&Du=tV3MuQBuB=igOW*Z6eflNYr1%|`4w*)hmfFV zEQQsKKuV_Cz@FQjpsUwGzq}G|BlQ%k+GQ{-`H8s6_Vhv;aws!0dAeZ3T`8oKJ^9#c zZ&5E(D$3)O*k970yG(tIepFwPMl<$TJkI)e*BwL3n~>3b+K}@81Y@RfQ^m{d z{YgPFqA(y}&yJ0-r>k~Z0vlmZH}#FMr@Lke5`ZnYYIu4`JL0Dju_N~MWPcd0NZ=oQ zV^A>|^^Sp29}Px*V`tQlF=`&XJS~~spceknTPzkj`z7Ob{Ldos{w)8C2-{!a$lXzH zL}b0fFmsyry3&v)DlN}UnMe2DRMCXimXvp*Fp%`1PZ=!J=*Mpu?X=*=3L_n0sz_ra zybGZ(&729B;-eg9$0Gj7v&K&d-SdobHXZPO#Sav^oBy%KA4pH`sc6l&A7%O!RXK<; z+9sHjc$kx#a-0XwNBd!aV%-7SkU0j5%scVEenZxhB)#qr9Skmu=tpRY5FI^xbHxCD#1p22B#qn+HUsc; zk$Q_!Q2doe{5^Ih<#hM#BvcYq%k#UO%j>U?jV{y>&9@8Nr(C52o%JFzM+3 z(TBd;x}uP_+F#KtcthnyqCUwplA@Y>(vrP7IXr83K?IDj$PFTebj6Jo%gL~MGPOA^ z7@K&xI7^l6sTe0($C5n7>a`WLC3;3{)KN)T9m$M{^xhY(<2etk$5JIdx+v@a)rZwg z9p;^Ll)KuS!TJ;?w=%{xe1tQ*r7-Pqp0S$Udz`F$V-`92akKWU#^+02{JmkUi%(E= z@zDl;*z5Mk2%qqn`)$Jc4ZQWQRd&wk8H3I_nP0iG0>Nxf|G6=pTDw^im`!#P(^Pq; z@GI9=^brK=<3ZExY{;flvDFS3XpQv#i6hJSg6$Psp`z>9t~C$a;T6K)Pvci^t~ixI zXB}*7V0z{Abl;Pv)@+cUqfd`X{Bg&Jo&+P&E!XLmvr3wmbl+OPF+umyGP?3+*Ftd= z(KDV3Gd;bh!or5jjHcL*gnek;e$!5z2|xLqaX4FnCgEphV|{3rMjx83)`#ZNJ1%oi z<2>a;_mND`o;gvP@Nz;pT31qT!)E%f^rUGVpRmid09BvFW1e7DKMxZKVulM7$P6%^ zui4-WWDU-F7BW=je6~o@*z-}<+dT=SsD9B-hXYDp*(OFY6b9e}E1wzv-(S*BL z0k<>~4r&zH^vU4v@fZMCIJTtdYxw#-8#uUhvd-c*dc6!-?-?15VQ zjco$05wzgu;H}A~( z1W)$)IGGW z!8D6?rgZw)OWSaa_$c=UlYLk>LJ!^H%|qn$bS`C;e#oS8ht8Ha#YNTTfVR?_Rf&6D zJK;ZjNYRT-H}Pe!m28F);}>({)D{1CADaG0&gKNe`SS)^XiWJ+p9DE(HtVeZ-j=(F zV23|SPz@B-@B~w9TdCoplBT3N-MTUF)@I~AvRsGj$P)Bsl9r&ikSdtUedYrC=z`HB z6PD_TFp11T)m8do8-IjjRp;So!VBJVqh})uTFJ{CVmwtcH6J}N*?bW+J7<5+ebK-_ zmQ|9^8T_eXsy)vZgQC3(mvEj*tqkk7S>e5zIRnVDc7zD742R|Q{;!$E86OP5pyxTS~Z zc@6UPDf0BI=80n7!isqbp{27OiTphml?(vKrs4U)s_v<$4NrS*bpxByLsRlRT-opR z!zp=}B^mUDB;b4i>(?F@`W-X#26IokYg*n*^yx3Nhtblny{*{%)~dNlx>&q3Oa-E) zf=zBm4wqOHrTfO|vEQ~_2H6kuW-ogE%)G3iV!kWga#vdf)qzaURP>p2T#v*wTJUkj zs*s+Z{npEr^w)D=zeA5bY#sw^Q1DZ~b?&X4PEU`mnm>=sr8Yy#MnS>6-D}iWq5udm zGKNPEPLg!pN`JEi-QDw<%6?{Z9ntCJt4bxo3tHy$7GB>p#eV(kDT5OS|IW@?jG@a1 zS@N*e34P4b_eILRQWD*lm)f5locg|gc6knzJT@*RgZ7w`XCqhAvpE)5a$mH>cKqxJ z(+2QO<}do1;MPJx4~w7)9x77|>|~2`H52?6@V_Q^hEd;hgNAZIR0aDpq>Z~m6+AEv z`dH8P$b45AJd{#j5$mdiRzdiiG1!lh7swF=ZD=5OlYQg{C=$yjoh1DEmIeqt-;XpT zbDrHIvw*sCPjpsrVR)B0vkCrEOmW1w7dhPoPPasIf_j>%rr8gc5cYr1t+HylO$mN` zbnwhbaMPHVNeg6*{-86EKgmf}Xn^d)&s{Omxm!l(9wnXsM5mLbO$XXT1)V!V=e|ff zOnH324F7-Eaz5 zTp|B2e`{?PPlCmB>MZ^jWWjl!S2o!TjWEa{L+TsGw2@J0qfOyiPaL>+opj?MTwT9~sbv;NHFON@le)SolbWBuBF5!QDk|0g@=x62ew zt^a76E5^0-e2vYbP5Ra3sbh?uPw~PkfAJAsz@tylQsEoPo_F>q_}j^guA-1Pd)Tb@ zZex4p_r$$&|K8=d^EaIwvH;7>`>aNa)cm!XTa@R6pq}LrDGT>K@_fktSX1|rw6Ra(CKj7==O@&1O*G-dvfY@Q%dkdQJwoG#$PqU_#17;qH6wI4aLYQO`D-O3j-qn6Chj---E1(CA)A`f1CJTYXzp$tZ#Z$YYZqyz zGyh56#5t^I2_{!Bhmq)FBN29!zmRrH>0gj`2x+tDG^*;?#>)MhYPpGrC;6KPstr99 zyZiL9oaYartQ2KEtk_%7m3xYN(KBOBCZ6v(eI(jOuw_RXiGMf7@thV%;Q%y_Dh1Vs z;mTOzrA0?UKsd)iyv)MQ7PWTjiem#cRLvOA-`J~TD*1ap>n#)M@Ke=!^|S;Kh^to^T%G^S-H6FZ{fHB!_5ivO|UFE~jW zVAd@=*tQuzy_07gq5R15;p|&U(EyXx0a4atkCwDx6jq0UrYJz+kTl|pbqL8n@=^+&FKhT2o~yc%4Wx__HI3Ol9Rc$Q<5p3LBwtNc6VS(tmne z%k`h$HVj^&ZuKI(q)h)g59XtGqmuXq<>kYPzFR{W zT0@wb(Dsp473WD3d6Gad^xA@`A2I!G0t`uSRoGY&>_MYSYoYsYL~p9|x1CB8oV~xL z4^ueu;aeUwTn@E1$xf+H-PDOc@m|Hvg!(HgRwR+n2|S;?P)Y5t7->&qk=|FOHE=f!byC?)zHx<-XVTy`p4Tw(-Si+>|VzE_*=TB&cala zeE~o@YCyjc{V+0sDcv?ey_js)M}>t9xXRo`jHLMGxYVpeXL3^Eu<=1j6Z+H{b24Yu z)4Qox2oo}!4k^!kh`B<;>C=#5RQc2uWwAz>rl=BjuFi{N>~H5>3g^vZ>&%1oCOve4 z6V1IiXmT2sSbEc(U3n9jzS6+z%UJnFET5`az7*$o1Wg2?4_;lI%{}}RoL;<>>5&uW z-6Vz9rCXfzztt8*pgPLs3w4kjtb+Q&`R!QL$c}VLtJId+!AfsSn2xG5)4np@>s;X< zg}Opf5xf2jE&O;}KI;pGtSU%vOD0)Q$<(>8(y}XiXVO_$_D)oJ7?Q<&3w3koz8B0b z$X7Idl6eYAsISXfLaR3BZ6a;!%UTbEV=+tzljxq5lr+xUQLfwb7RYpaObt4WKYMoc zT0PzQ1#D<+&>sE+3MAfke8CG?B|3&F_q_RN)6R+vyT~#O=|pef!g8d@aV5X~$pw>; zZ9#aposeyJMYcU+&vq4G|LTH?$hI&%+iu9Vw<6mB75!%sO`M{kmHcB0*bDD z-l3r_toI_34DVmN7^e|u`xfuxyu;W5paQ~oIXQNTk>9hR=^(UB7denZ+v6P!sF9&H zOzC#v9Ti-`;CA6HW_ZeV6X7Og>*hrU+V43mf0B?@YO26_3*nHgv~+frjMUx{fGyL6 z9ixC98wm?nY#D4xP^<&u7-)R?18=xmC4`0I=zrU^5h8!ck{smBQkrRW^vMPu|(gNY}h&EDA^?Jp!=P06Rw$cCG?;USt_@ z$*vacM8ZGdS?5L>dj`PD0k%jJY_S4tNhH|C(ZKY%<#*G{lJZ~?dj(Jz0(H42>Iwzw z%1Bh)(5GEQ)=#^Uz5KV2x=%yM>m9&c2F$gZnCldn>mxBYG=`Z=viXy5xPJ#`p8)0> zU{+{iZc<=wj>N=0XNq#tp-*?u;3G$4-vA!Wb>6L-c$X^hE{nw57J;`hLk+KA0Iv#o zS8C#2rNFy767QM_yzQ!Z{R4Qg+j(m=@oE)#zDPWO7@ll?8%H2qEq}{6G%y?o1Td?C zS+9wCodWavNX#ADnBtt8OL7DKrYL|3Ym@f|P0Sk=m^VdY?owcOHPBpRt5&kYhE3)J z1F$;*yGIjtuL5>oB)|!?)%2wQSMUny4$4Z{DVcvRPSvDm}y3GSeJF)uc`S|UVHk#z1#ZJ=c}5uqu#yS zS}~a2q|*DjpDi^f{UvyQVZs=qs)2tm+|nO!img+HVqt3N?nM3zmn41e^az7q=$-PfNevO+75bg|Y=T2YG<=|awu z?mr5|en~y&TVH-(+bA0BVQk}l&h0z<-uFE3yDVUsNdfkqdWL^DCG9K|*v8-%t$4E4G$bDv0Cg$C`X|UhQnre>J-o z`@Pp#(Pu&0!l8W)C~mR*mg9_~Y~&^LE2@-w{={41;lYQF)rJ<9Ui{sNd{s)05wuTN z;-xltzek3~cBu4{{L*Ayz$@TnT5`;%~r2(q=r{5{@{I#wm}U@FTNH*ZtBf@dJL<((+VmYS~?AN z3QSsLV=q}~jJyCvdqQ$~SAXO8NXy&boAK-+3wycUxyxHPZ{8yXbw8M{r4CiiZpp?)pz@HB zflXh4zuRQhL8JO~CC)m}F7^mdWkU#4vdnA_g^cKHSbA%+q|#nf`v&KAu1%y>He@Sm z{a4;o;0lTUj+{P(q;bk-sfbzalG#8anLuJ-NdhRo?9PFNkHQvgKA= HDt-48n!JFS delta 186559 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 Date: Tue, 2 Jun 2015 15:32:08 +0000 Subject: [PATCH 07/28] Rename SQLITE_AFF_NONE to SQLITE_AFF_BLOB. FossilOrigin-Name: bce3f04186cd2d69414a5a98b5b77dc8f060554a --- manifest | 31 +++++++++++++++++-------------- manifest.uuid | 2 +- src/alter.c | 2 +- src/build.c | 20 ++++++++++---------- src/expr.c | 12 ++++++------ src/insert.c | 10 +++++----- src/select.c | 2 +- src/sqliteInt.h | 4 ++-- src/vdbe.c | 8 ++++---- src/vdbemem.c | 4 ++-- src/where.c | 36 ++++++++++++++++++------------------ 11 files changed, 67 insertions(+), 64 deletions(-) diff --git a/manifest b/manifest index 84ea37edf4..0403efeca2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sfaulty\sassert()\sin\sbtree.c.\s\sUpdate\sthe\sdatabase\sfuzz\stest\sfile\swith\nnew\stest\scases. -D 2015-06-02T14:02:18.322 +C Rename\sSQLITE_AFF_NONE\sto\sSQLITE_AFF_BLOB. +D 2015-06-02T15:32:08.579 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -185,7 +185,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c 8f6dc4a6ddc1ebc0ed5cc470c4e57ff0d1605e90 +F src/alter.c 48e14b8aea28dc58baafe3cfcb8889c086b7744a F src/analyze.c d23790787f80ebed58df7774744b4cf96401498b F src/attach.c c38ac5a520a231d5d0308fd7f2ad95191c867bae F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 @@ -195,14 +195,14 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btree.c c73a170115df068764126a85288cdec092ec180c F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 973a22a6fd61350b454ad614832b1f0a5e25a1e4 -F src/build.c 85a169a0a22f8b80caf513eaf2944d39b979f571 +F src/build.c 73da2b9e9311abc4fcb4e36f76c7800c2d2504a4 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575 F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e -F src/expr.c 5de0af7c63a3722d4eb5335f81841f386daa4c20 +F src/expr.c 52f5c1c2c16bf47234dc276d9f72b5ea85ae14af F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 F src/func.c 5b8b8e77a0fb644eaf8947d413804622e32692b6 @@ -210,7 +210,7 @@ F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c 35b7816918406ec49fbcc6c7fa7ab622597f662e +F src/insert.c d6e1623a97ce33e9af2f1a0c1f0085a2f63327ef F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 @@ -250,12 +250,12 @@ F src/printf.c 13ce37e5574f9b0682fa86dbcf9faf76b9d82a15 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c 5978cc521cb8fc1aa6a0089e35edaf531accb52a +F src/select.c 7bb5c6334128877a30d4644fb948098a3ec41bbc F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 2ebeb634e751a61a6f0eebfa0f4669f46a42f6cd -F src/sqliteInt.h bc8496de6a514ac66a5a938ee0e4f0d17d150c77 +F src/sqliteInt.h bcf51f6ec3ad67dbdf1acf78fcb94884af93c183 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -312,13 +312,13 @@ F src/update.c 487747b328b7216bb7f6af0695d6937d5c9e605f F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c a6431c92803b975b7322724a7b433e538d243539 F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 -F src/vdbe.c 6aee8a041742413ab3113e6682bc7ad1628a2bbe +F src/vdbe.c 0a6a1df5c31415a0e974e74e7bd412616889453d F src/vdbe.h 7e538ecf47dccb307ea2d087c3ddc2dd8d70e79d F src/vdbeInt.h f0ccddac48583d5f762dc554a9f79e85ea8807e0 F src/vdbeapi.c 6a0d7757987018ff6b1b81bc5293219cd26bb299 F src/vdbeaux.c 46f9bc4b32866082eb87a36b461e487a0bbdbe8e F src/vdbeblob.c 4f2e8e075d238392df98c5e03a64342465b03f90 -F src/vdbemem.c 21f9169289a804308f6cdde55e9417fb8336997f +F src/vdbemem.c 67b302dc6df64b4d6785881c5d22bd4f9b17739d F src/vdbesort.c f5009e7a35e3065635d8918b9a31f498a499976b F src/vdbetrace.c 8befe829faff6d9e6f6e4dee5a7d3f85cc85f1a0 F src/vtab.c c535e80259ebe616467181a83a4263555b97c694 @@ -326,7 +326,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c f6f41c2f8b9903854992170ea5178898f9cb6c9c +F src/where.c dcdfee81d35ae9261a4c5bda6289ed5fa6d7e1ae F src/whereInt.h a6f5a762bc1b4b1c76e1cea79976b437ac35a435 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1281,7 +1281,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P f925389eaf5bf8962a28fcaa652b75caa606efba -R ae4a37b7f156067ca4ef803074aa5dc0 +P 4e621af1345a001360938de76e3b0a14deb5e991 +R ee13a8dd8e0014c6c36d8309e414bd72 +T *branch * blob-affinity-rename +T *sym-blob-affinity-rename * +T -sym-trunk * U drh -Z d6aea5d5b820e4f6ddc306cbfe7d28b3 +Z 3dc5f9f8176f1194f0510f7321cda212 diff --git a/manifest.uuid b/manifest.uuid index a97991bf5c..90256eb79a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4e621af1345a001360938de76e3b0a14deb5e991 \ No newline at end of file +bce3f04186cd2d69414a5a98b5b77dc8f060554a \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index 44422ca371..e39d7723b1 100644 --- a/src/alter.c +++ b/src/alter.c @@ -692,7 +692,7 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ if( pDflt ){ sqlite3_value *pVal = 0; int rc; - rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_NONE, &pVal); + rc = sqlite3ValueFromExpr(db, pDflt, SQLITE_UTF8, SQLITE_AFF_BLOB, &pVal); assert( rc==SQLITE_OK || rc==SQLITE_NOMEM ); if( rc!=SQLITE_OK ){ db->mallocFailed = 1; diff --git a/src/build.c b/src/build.c index ac423a2856..ad83a6a7dd 100644 --- a/src/build.c +++ b/src/build.c @@ -1092,10 +1092,10 @@ void sqlite3AddColumn(Parse *pParse, Token *pName){ pCol->zName = z; /* If there is no type specified, columns have the default affinity - ** 'NONE'. If there is a type specified, then sqlite3AddColumnType() will + ** 'BLOB'. If there is a type specified, then sqlite3AddColumnType() will ** be called next to set pCol->affinity correctly. */ - pCol->affinity = SQLITE_AFF_NONE; + pCol->affinity = SQLITE_AFF_BLOB; pCol->szEst = 1; p->nCol++; } @@ -1130,7 +1130,7 @@ void sqlite3AddNotNull(Parse *pParse, int onError){ ** 'CHAR' | SQLITE_AFF_TEXT ** 'CLOB' | SQLITE_AFF_TEXT ** 'TEXT' | SQLITE_AFF_TEXT -** 'BLOB' | SQLITE_AFF_NONE +** 'BLOB' | SQLITE_AFF_BLOB ** 'REAL' | SQLITE_AFF_REAL ** 'FLOA' | SQLITE_AFF_REAL ** 'DOUB' | SQLITE_AFF_REAL @@ -1156,7 +1156,7 @@ char sqlite3AffinityType(const char *zIn, u8 *pszEst){ aff = SQLITE_AFF_TEXT; }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */ && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){ - aff = SQLITE_AFF_NONE; + aff = SQLITE_AFF_BLOB; if( zIn[0]=='(' ) zChar = zIn; #ifndef SQLITE_OMIT_FLOATING_POINT }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */ @@ -1548,7 +1548,7 @@ 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_NONE */ "", + /* SQLITE_AFF_BLOB */ "", /* SQLITE_AFF_TEXT */ " TEXT", /* SQLITE_AFF_NUMERIC */ " NUM", /* SQLITE_AFF_INTEGER */ " INT", @@ -1561,17 +1561,17 @@ static char *createTableStmt(sqlite3 *db, Table *p){ k += sqlite3Strlen30(&zStmt[k]); zSep = zSep2; identPut(zStmt, &k, pCol->zName); - assert( pCol->affinity-SQLITE_AFF_NONE >= 0 ); - assert( pCol->affinity-SQLITE_AFF_NONE < ArraySize(azType) ); - testcase( pCol->affinity==SQLITE_AFF_NONE ); + assert( pCol->affinity-SQLITE_AFF_BLOB >= 0 ); + assert( pCol->affinity-SQLITE_AFF_BLOB < ArraySize(azType) ); + testcase( pCol->affinity==SQLITE_AFF_BLOB ); 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_NONE]; + zType = azType[pCol->affinity - SQLITE_AFF_BLOB]; len = sqlite3Strlen30(zType); - assert( pCol->affinity==SQLITE_AFF_NONE + assert( pCol->affinity==SQLITE_AFF_BLOB || pCol->affinity==sqlite3AffinityType(zType, 0) ); memcpy(&zStmt[k], zType, len); k += len; diff --git a/src/expr.c b/src/expr.c index 6c22f75d09..fa5715c04f 100644 --- a/src/expr.c +++ b/src/expr.c @@ -191,13 +191,13 @@ char sqlite3CompareAffinity(Expr *pExpr, char aff2){ if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){ return SQLITE_AFF_NUMERIC; }else{ - return SQLITE_AFF_NONE; + return SQLITE_AFF_BLOB; } }else if( !aff1 && !aff2 ){ /* Neither side of the comparison is a column. Compare the ** results directly. */ - return SQLITE_AFF_NONE; + return SQLITE_AFF_BLOB; }else{ /* One side is a column, the other is not. Use the columns affinity. */ assert( aff1==0 || aff2==0 ); @@ -221,7 +221,7 @@ static char comparisonAffinity(Expr *pExpr){ }else if( ExprHasProperty(pExpr, EP_xIsSelect) ){ aff = sqlite3CompareAffinity(pExpr->x.pSelect->pEList->a[0].pExpr, aff); }else if( !aff ){ - aff = SQLITE_AFF_NONE; + aff = SQLITE_AFF_BLOB; } return aff; } @@ -235,7 +235,7 @@ static char comparisonAffinity(Expr *pExpr){ int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){ char aff = comparisonAffinity(pExpr); switch( aff ){ - case SQLITE_AFF_NONE: + case SQLITE_AFF_BLOB: return 1; case SQLITE_AFF_TEXT: return idx_affinity==SQLITE_AFF_TEXT; @@ -1482,7 +1482,7 @@ int sqlite3ExprCanBeNull(const Expr *p){ */ int sqlite3ExprNeedsNoAffinityChange(const Expr *p, char aff){ u8 op; - if( aff==SQLITE_AFF_NONE ) return 1; + if( aff==SQLITE_AFF_BLOB ) return 1; while( p->op==TK_UPLUS || p->op==TK_UMINUS ){ p = p->pLeft; } op = p->op; if( op==TK_REGISTER ) op = p->op2; @@ -1933,7 +1933,7 @@ int sqlite3CodeSubselect( int r1, r2, r3; if( !affinity ){ - affinity = SQLITE_AFF_NONE; + affinity = SQLITE_AFF_BLOB; } if( pKeyInfo ){ assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); diff --git a/src/insert.c b/src/insert.c index 18dbfed8b2..7e8741a9a2 100644 --- a/src/insert.c +++ b/src/insert.c @@ -56,7 +56,7 @@ void sqlite3OpenTable( ** ** Character Column affinity ** ------------------------------ -** 'A' NONE +** 'A' BLOB ** 'B' TEXT ** 'C' NUMERIC ** 'D' INTEGER @@ -99,9 +99,9 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ /* ** Compute the affinity string for table pTab, if it has not already been -** computed. As an optimization, omit trailing SQLITE_AFF_NONE affinities. +** computed. As an optimization, omit trailing SQLITE_AFF_BLOB affinities. ** -** If the affinity exists (if it is no entirely SQLITE_AFF_NONE values) and +** If the affinity exists (if it is no entirely SQLITE_AFF_BLOB values) and ** if iReg>0 then code an OP_Affinity opcode that will set the affinities ** for register iReg and following. Or if affinities exists and iReg==0, ** then just set the P4 operand of the previous opcode (which should be @@ -111,7 +111,7 @@ const char *sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ ** ** Character Column affinity ** ------------------------------ -** 'A' NONE +** 'A' BLOB ** 'B' TEXT ** 'C' NUMERIC ** 'D' INTEGER @@ -133,7 +133,7 @@ void sqlite3TableAffinity(Vdbe *v, Table *pTab, int iReg){ } do{ zColAff[i--] = 0; - }while( i>=0 && zColAff[i]==SQLITE_AFF_NONE ); + }while( i>=0 && zColAff[i]==SQLITE_AFF_BLOB ); pTab->zColAff = zColAff; } i = sqlite3Strlen30(zColAff); diff --git a/src/select.c b/src/select.c index e5e1a9988b..a8bd0c31b8 100644 --- a/src/select.c +++ b/src/select.c @@ -1709,7 +1709,7 @@ static void selectAddColumnTypeAndCollation( } szAll += pCol->szEst; pCol->affinity = sqlite3ExprAffinity(p); - if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_NONE; + if( pCol->affinity==0 ) pCol->affinity = SQLITE_AFF_BLOB; pColl = sqlite3ExprCollSeq(pParse, p); if( pColl && pCol->zColl==0 ){ pCol->zColl = sqlite3DbStrDup(db, pColl->zName); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 53a3c7824d..a31f363708 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1501,9 +1501,9 @@ struct CollSeq { ** 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. And the NONE type is first. +** for a numeric type is a single comparison. And the BLOB type is first. */ -#define SQLITE_AFF_NONE 'A' +#define SQLITE_AFF_BLOB 'A' #define SQLITE_AFF_TEXT 'B' #define SQLITE_AFF_NUMERIC 'C' #define SQLITE_AFF_INTEGER 'D' diff --git a/src/vdbe.c b/src/vdbe.c index c076a41edd..962d6fc3e3 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -270,7 +270,7 @@ static void applyNumericAffinity(Mem *pRec, int bTryForInt){ ** SQLITE_AFF_TEXT: ** Convert pRec to a text representation. ** -** SQLITE_AFF_NONE: +** SQLITE_AFF_BLOB: ** No-op. pRec is unchanged. */ static void applyAffinity( @@ -1780,9 +1780,9 @@ case OP_RealAffinity: { /* in1 */ ** A NULL value is not changed by this routine. It remains NULL. */ case OP_Cast: { /* in1 */ - assert( pOp->p2>=SQLITE_AFF_NONE && pOp->p2<=SQLITE_AFF_REAL ); + assert( pOp->p2>=SQLITE_AFF_BLOB && pOp->p2<=SQLITE_AFF_REAL ); testcase( pOp->p2==SQLITE_AFF_TEXT ); - testcase( pOp->p2==SQLITE_AFF_NONE ); + testcase( pOp->p2==SQLITE_AFF_BLOB ); testcase( pOp->p2==SQLITE_AFF_NUMERIC ); testcase( pOp->p2==SQLITE_AFF_INTEGER ); testcase( pOp->p2==SQLITE_AFF_REAL ); @@ -2593,7 +2593,7 @@ case OP_Affinity: { ** The mapping from character to affinity is given by the SQLITE_AFF_ ** macros defined in sqliteInt.h. ** -** If P4 is NULL then all index fields have the affinity NONE. +** If P4 is NULL then all index fields have the affinity BLOB. */ case OP_MakeRecord: { u8 *zNewRecord; /* A buffer to hold the data for the new record */ diff --git a/src/vdbemem.c b/src/vdbemem.c index 1dbdb89895..7f426cf196 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -588,7 +588,7 @@ int sqlite3VdbeMemNumerify(Mem *pMem){ 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 */ + case SQLITE_AFF_BLOB: { /* 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 ); @@ -1311,7 +1311,7 @@ static int valueFromExpr( if( zVal==0 ) goto no_mem; sqlite3ValueSetStr(pVal, -1, zVal, SQLITE_UTF8, SQLITE_DYNAMIC); } - if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_NONE ){ + if( (op==TK_INTEGER || op==TK_FLOAT ) && affinity==SQLITE_AFF_BLOB ){ sqlite3ValueApplyAffinity(pVal, SQLITE_AFF_NUMERIC, SQLITE_UTF8); }else{ sqlite3ValueApplyAffinity(pVal, affinity, SQLITE_UTF8); diff --git a/src/where.c b/src/where.c index bcd3129189..ecd6bd2a8f 100644 --- a/src/where.c +++ b/src/where.c @@ -680,7 +680,7 @@ static int isLikeOrGlob( if( op==TK_VARIABLE ){ Vdbe *pReprepare = pParse->pReprepare; int iCol = pRight->iColumn; - pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_NONE); + pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB); if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ z = (char *)sqlite3_value_text(pVal); } @@ -2824,9 +2824,9 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){ ** Code an OP_Affinity opcode to apply the column affinity string zAff ** to the n registers starting at base. ** -** As an optimization, SQLITE_AFF_NONE entries (which are no-ops) at the +** As an optimization, SQLITE_AFF_BLOB entries (which are no-ops) at the ** beginning and end of zAff are ignored. If all entries in zAff are -** SQLITE_AFF_NONE, then no code gets generated. +** SQLITE_AFF_BLOB, then no code gets generated. ** ** This routine makes its own copy of zAff so that the caller is free ** to modify zAff after this routine returns. @@ -2839,15 +2839,15 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){ } assert( v!=0 ); - /* Adjust base and n to skip over SQLITE_AFF_NONE entries at the beginning + /* Adjust base and n to skip over SQLITE_AFF_BLOB entries at the beginning ** and end of the affinity string. */ - while( n>0 && zAff[0]==SQLITE_AFF_NONE ){ + while( n>0 && zAff[0]==SQLITE_AFF_BLOB ){ n--; base++; zAff++; } - while( n>1 && zAff[n-1]==SQLITE_AFF_NONE ){ + while( n>1 && zAff[n-1]==SQLITE_AFF_BLOB ){ n--; } @@ -2977,17 +2977,17 @@ static int codeEqualityTerm( ** Before returning, *pzAff is set to point to a buffer containing a ** copy of the column affinity string of the index allocated using ** sqlite3DbMalloc(). Except, entries in the copy of the string associated -** with equality constraints that use NONE affinity are set to -** SQLITE_AFF_NONE. This is to deal with SQL such as the following: +** with equality constraints that use BLOB or NONE affinity are set to +** SQLITE_AFF_BLOB. This is to deal with SQL such as the following: ** ** CREATE TABLE t1(a TEXT PRIMARY KEY, b); ** SELECT ... FROM t1 AS t2, t1 WHERE t1.a = t2.b; ** ** In the example above, the index on t1(a) has TEXT affinity. But since -** the right hand side of the equality constraint (t2.b) has NONE affinity, +** the right hand side of the equality constraint (t2.b) has BLOB/NONE affinity, ** no conversion should be attempted before using a t2.b value as part of ** a key to search the index. Hence the first byte in the returned affinity -** string in this example would be set to SQLITE_AFF_NONE. +** string in this example would be set to SQLITE_AFF_BLOB. */ static int codeAllEqualityTerms( Parse *pParse, /* Parsing context */ @@ -3074,11 +3074,11 @@ static int codeAllEqualityTerms( VdbeCoverage(v); } if( zAff ){ - if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_NONE ){ - zAff[j] = SQLITE_AFF_NONE; + if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){ + zAff[j] = SQLITE_AFF_BLOB; } if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){ - zAff[j] = SQLITE_AFF_NONE; + zAff[j] = SQLITE_AFF_BLOB; } } } @@ -3725,14 +3725,14 @@ static Bitmask codeOneLoopStart( VdbeCoverage(v); } if( zStartAff ){ - if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_NONE){ + if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_BLOB){ /* Since the comparison is to be performed with no conversions ** applied to the operands, set the affinity to apply to pRight to - ** SQLITE_AFF_NONE. */ - zStartAff[nEq] = SQLITE_AFF_NONE; + ** SQLITE_AFF_BLOB. */ + zStartAff[nEq] = SQLITE_AFF_BLOB; } if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){ - zStartAff[nEq] = SQLITE_AFF_NONE; + zStartAff[nEq] = SQLITE_AFF_BLOB; } } nConstraint++; @@ -3770,7 +3770,7 @@ static Bitmask codeOneLoopStart( sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); VdbeCoverage(v); } - if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_NONE + if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_BLOB && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff) ){ codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff); From 467c1c70fb519279fe5f806425923417673eb2f1 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 2 Jun 2015 17:25:05 +0000 Subject: [PATCH 08/28] Add test cases for type affinity rules. FossilOrigin-Name: 9678646d9a14ba283a83839be329599a676a537a --- manifest | 11 ++++---- manifest.uuid | 2 +- test/affinity2.test | 61 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 test/affinity2.test diff --git a/manifest b/manifest index 337a86f9f6..75d59c2580 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Rename\sSQLITE_AFF_NONE\sto\sSQLITE_AFF_BLOB\sto\savoid\sconfusion\swith\n"no\saffinity". -D 2015-06-02T16:19:56.840 +C Add\stest\scases\sfor\stype\saffinity\srules. +D 2015-06-02T17:25:05.494 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -329,6 +329,7 @@ F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 F src/where.c dcdfee81d35ae9261a4c5bda6289ed5fa6d7e1ae F src/whereInt.h a6f5a762bc1b4b1c76e1cea79976b437ac35a435 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 +F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test b35b4cd69fc913f90d39a575e171e1116c3a4bb7 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 @@ -1281,7 +1282,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 4e621af1345a001360938de76e3b0a14deb5e991 bce3f04186cd2d69414a5a98b5b77dc8f060554a -R ee13a8dd8e0014c6c36d8309e414bd72 +P 29ad9e917330969810ac1bc685bba4282401bdae +R 5097b9f5eaad8b186d53b7faa7ec8244 U drh -Z 7bcfea926bf6cb138b5a18403403f3f4 +Z 413a5118f0977cbaebf568697e060ab8 diff --git a/manifest.uuid b/manifest.uuid index c4fdc8af1e..eec092373c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -29ad9e917330969810ac1bc685bba4282401bdae \ No newline at end of file +9678646d9a14ba283a83839be329599a676a537a \ No newline at end of file diff --git a/test/affinity2.test b/test/affinity2.test new file mode 100644 index 0000000000..9838bd660a --- /dev/null +++ b/test/affinity2.test @@ -0,0 +1,61 @@ +# 2015-06-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 implements regression tests for SQLite library. The +# focus of this file is type affinity in comparison operations. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test affinity2-100 { + CREATE TABLE t1( + xi INTEGER, + xr REAL, + xb BLOB, + xn NUMERIC, + xt TEXT + ); + INSERT INTO t1(rowid,xi,xr,xb,xn,xt) VALUES(1,1,1,1,1,1); + INSERT INTO t1(rowid,xi,xr,xb,xn,xt) VALUES(2,'2','2','2','2','2'); + INSERT INTO t1(rowid,xi,xr,xb,xn,xt) VALUES(3,'03','03','03','03','03'); + +} {} +do_execsql_test affinity2-110 { + SELECT xi, typeof(xi) FROM t1 ORDER BY rowid; +} {1 integer 2 integer 3 integer} +do_execsql_test affinity2-120 { + SELECT xr, typeof(xr) FROM t1 ORDER BY rowid; +} {1.0 real 2.0 real 3.0 real} +do_execsql_test affinity2-130 { + SELECT xb, typeof(xb) FROM t1 ORDER BY rowid; +} {1 integer 2 text 03 text} +do_execsql_test affinity2-140 { + SELECT xn, typeof(xn) FROM t1 ORDER BY rowid; +} {1 integer 2 integer 3 integer} +do_execsql_test affinity2-150 { + SELECT xt, typeof(xt) FROM t1 ORDER BY rowid; +} {1 text 2 text 03 text} + +do_execsql_test affinity2-200 { + SELECT rowid, xi==xt, xi==xb, xi==+xt FROM t1 ORDER BY rowid; +} {1 1 1 1 2 1 1 1 3 1 1 1} +do_execsql_test affinity2-210 { + SELECT rowid, xr==xt, xr==xb, xr==+xt FROM t1 ORDER BY rowid; +} {1 1 1 1 2 1 1 1 3 1 1 1} +do_execsql_test affinity2-220 { + SELECT rowid, xn==xt, xn==xb, xn==+xt FROM t1 ORDER BY rowid; +} {1 1 1 1 2 1 1 1 3 1 1 1} + +do_execsql_test affinity2-300 { + SELECT rowid, xt==+xi, xt==xi, xt==xb FROM t1 ORDER BY rowid; +} {1 1 1 0 2 1 1 1 3 0 1 1} + +finish_test From 24dee9d2143c9dcc4026c9958f2fa07b155958ab Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 2 Jun 2015 19:36:29 +0000 Subject: [PATCH 09/28] Always check for cell overflow before returning a slot from the pageFindSlot routine in btree.c. FossilOrigin-Name: 9f035c45a4b84203e67b6e1b23cf11691dc43f1e --- manifest | 15 +++++++-------- manifest.uuid | 2 +- src/btree.c | 8 ++++---- test/fuzzdata3.db | Bin 10724352 -> 10728448 bytes 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index eb6aa8009c..31c398c461 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C For\sFROM-clause\ssubqueries\sthat\scannot\sbe\sflattened,\stry\sto\spush\srelevant\nWHERE\sclause\sterms\sof\sthe\souter\squery\sdown\sinto\sthe\ssubquery\sin\sorder\sto\shelp\nthe\ssubquery\srun\sfaster\sand/or\suse\sless\smemory. -D 2015-06-02T18:09:18.284 +C Always\scheck\sfor\scell\soverflow\sbefore\sreturning\sa\sslot\sfrom\sthe\npageFindSlot\sroutine\sin\sbtree.c. +D 2015-06-02T19:36:29.792 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -192,7 +192,7 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c ff743689c4d6c5cb55ad42ed9d174b2b3e71f1e3 F src/bitvec.c 5eb7958c3bf65210211cbcfc44eff86d0ded7c9d F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 -F src/btree.c c73a170115df068764126a85288cdec092ec180c +F src/btree.c 5166c27883c24768c2f7f53479714f03ef34c612 F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 973a22a6fd61350b454ad614832b1f0a5e25a1e4 F src/build.c 73da2b9e9311abc4fcb4e36f76c7800c2d2504a4 @@ -656,7 +656,7 @@ F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26 F test/fuzzcheck.c a60f926e3fa86c8d33908406d75eec868c22b9ca F test/fuzzdata1.db b60254eeb6bc11474071b883059662a73c48da7f F test/fuzzdata2.db f03a420d3b822cc82e4f894ca957618fbe9c4973 -F test/fuzzdata3.db 3632e598ff8574228aadf09897bd040d3c5f5ffb +F test/fuzzdata3.db a6e9bf75b8bfad0b7e60e57038908f4237b9c5d2 F test/fuzzer1.test d4c52aaf3ef923da293a2653cfab33d02f718a36 F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536 F test/genesis.tcl 1e2e2e8e5cc4058549a154ff1892fe5c9de19f98 @@ -1282,8 +1282,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 9678646d9a14ba283a83839be329599a676a537a 297fae7551a2af9e600d833801ff79fca0602ad5 -R 4cb9a66e53feaa59f815d8d8fff07191 -T +closed 297fae7551a2af9e600d833801ff79fca0602ad5 +P 6df18e949d3676290785143993513ea1b917d729 +R df67992b4dca09a3ed79d8f1ab3e61e2 U drh -Z 655d5f5f5a9ad84ec56fa650e3297ec0 +Z ecf49562dd93a4ec8af623b100b6b686 diff --git a/manifest.uuid b/manifest.uuid index 800c657dd8..501e5da639 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6df18e949d3676290785143993513ea1b917d729 \ No newline at end of file +9f035c45a4b84203e67b6e1b23cf11691dc43f1e \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index c81059f5b4..53e0ebbfc1 100644 --- a/src/btree.c +++ b/src/btree.c @@ -1272,7 +1272,10 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc, int *pbDefrag){ int x = size - nByte; testcase( x==4 ); testcase( x==3 ); - if( x<4 ){ + if( pc < pPg->cellOffset+2*pPg->nCell || size+pc > usableSize ){ + *pRc = SQLITE_CORRUPT_BKPT; + return 0; + }else 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 ){ @@ -1283,9 +1286,6 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc, int *pbDefrag){ ** fragmented bytes within the page. */ memcpy(&aData[iAddr], &aData[pc], 2); aData[hdr+7] += (u8)x; - }else if( pc < pPg->cellOffset+2*pPg->nCell || 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. */ diff --git a/test/fuzzdata3.db b/test/fuzzdata3.db index 376459f2d624ff28e69b8f0b3892e89d2fc43c88..29be55e7a6df4ee35ae2d5e27cc0e1a4ed75ea77 100644 GIT binary patch delta 611 zcmW-fS62-H0D!yqwy0EA$SA@!B0DP~JEQEKeD=sD!VRBYZbsLND~^BQ+;?951J7RU zj2Ca6qvP>A-`jV-$ouA$$d~4nXnsn!q@-|1tfeWQA1nWuTGYkGpE4SefCMEZ$&wXq`wT1d>JT%WUvg80x6WCGE9nOxQvjI z5|&XiTE@s&DVA|EUP@$wOq5A7S*FNTnI@$&U1rEknI*HOOy)?r%$0dEUn*pQER;pE zSeD3AStgaTTvo_RStV6cEvsdXtd(`LUN*=^*(94~i)@u`vR!Iqht$eW>1wr0cFP{w zEBj=>9FT)@NDfP#9Fe1POpeP5IVq>)w49N8IVVd5N6nf{sA!_q%v@;M+eYyZ4#^ delta 546 zcmW;K=~j#Z0D$4Cd>KTtGf@;G`<7cE*UaP0?Cxo5|%MC zR>nz|jF$u6tCbe>0PRL0)C8woM&d6CgC+Fp#)djgIm*lcsk*jh| zuFDO%DYv9v8sxS#${o2Y_vF4jkcaX}n&h!Ok!E=+F=>%jc_zbqS zo5bb4v`dG4kWTq1UD7QH>5)(JS-wcGe3d@wm!y3ANh&!Iu1+rt{ST1!J=Hy!Q<2e^ LHW>Yp`t^4N9SGi) From d62fbb50e6a927279856fcd0cb4cff675159dc1d Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 4 Jun 2015 12:08:53 +0000 Subject: [PATCH 10/28] Change the name of SrcList.a[].zIndex to the more descriptive SrcList.a[0].zIndexedBy. FossilOrigin-Name: 6a9cf063379118dbb95c6cdc6d60af50e9867177 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/build.c | 6 +++--- src/expr.c | 2 +- src/select.c | 8 ++++---- src/sqliteInt.h | 2 +- src/where.c | 2 +- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/manifest b/manifest index 31c398c461..eb67a9af5b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Always\scheck\sfor\scell\soverflow\sbefore\sreturning\sa\sslot\sfrom\sthe\npageFindSlot\sroutine\sin\sbtree.c. -D 2015-06-02T19:36:29.792 +C Change\sthe\sname\sof\sSrcList.a[].zIndex\sto\sthe\smore\sdescriptive\nSrcList.a[0].zIndexedBy. +D 2015-06-04T12:08:53.261 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -195,14 +195,14 @@ F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 F src/btree.c 5166c27883c24768c2f7f53479714f03ef34c612 F src/btree.h 969adc948e89e449220ff0ff724c94bb2a52e9f1 F src/btreeInt.h 973a22a6fd61350b454ad614832b1f0a5e25a1e4 -F src/build.c 73da2b9e9311abc4fcb4e36f76c7800c2d2504a4 +F src/build.c 6770b74ccb51cb485e81057c625f77455d5ddc06 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575 F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e -F src/expr.c 52f5c1c2c16bf47234dc276d9f72b5ea85ae14af +F src/expr.c d953b9f03c3c0f701f87a418fcfb9cba8befc6e0 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 F src/func.c 5b8b8e77a0fb644eaf8947d413804622e32692b6 @@ -250,12 +250,12 @@ F src/printf.c 13ce37e5574f9b0682fa86dbcf9faf76b9d82a15 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c 498342ba48543a13804a49f9620c6eba419a1159 +F src/select.c 36416c13e4a156fa7e8f29181e28964612767ddf F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 2ebeb634e751a61a6f0eebfa0f4669f46a42f6cd -F src/sqliteInt.h bcf51f6ec3ad67dbdf1acf78fcb94884af93c183 +F src/sqliteInt.h 851cc2ee6ec9a853f3fbcf1ce582590531fd7528 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -326,7 +326,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c dcdfee81d35ae9261a4c5bda6289ed5fa6d7e1ae +F src/where.c 2db8137f14644e2117c2e2350e08a05e02d6bdab F src/whereInt.h a6f5a762bc1b4b1c76e1cea79976b437ac35a435 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -1282,7 +1282,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 6df18e949d3676290785143993513ea1b917d729 -R df67992b4dca09a3ed79d8f1ab3e61e2 +P 9f035c45a4b84203e67b6e1b23cf11691dc43f1e +R ad5ce5f5b8d17995393297d9ed2a0d0e U drh -Z ecf49562dd93a4ec8af623b100b6b686 +Z de80e81db21512cdc452bca7645bb7ca diff --git a/manifest.uuid b/manifest.uuid index 501e5da639..e2792cff66 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9f035c45a4b84203e67b6e1b23cf11691dc43f1e \ No newline at end of file +6a9cf063379118dbb95c6cdc6d60af50e9867177 \ No newline at end of file diff --git a/src/build.c b/src/build.c index ad83a6a7dd..8c62fd18d5 100644 --- a/src/build.c +++ b/src/build.c @@ -3701,7 +3701,7 @@ void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ sqlite3DbFree(db, pItem->zDatabase); sqlite3DbFree(db, pItem->zName); sqlite3DbFree(db, pItem->zAlias); - sqlite3DbFree(db, pItem->zIndex); + sqlite3DbFree(db, pItem->zIndexedBy); sqlite3DeleteTable(db, pItem->pTab); sqlite3SelectDelete(db, pItem->pSelect); sqlite3ExprDelete(db, pItem->pOn); @@ -3774,13 +3774,13 @@ void sqlite3SrcListIndexedBy(Parse *pParse, SrcList *p, Token *pIndexedBy){ assert( pIndexedBy!=0 ); if( p && ALWAYS(p->nSrc>0) ){ struct SrcList_item *pItem = &p->a[p->nSrc-1]; - assert( pItem->notIndexed==0 && pItem->zIndex==0 ); + assert( pItem->notIndexed==0 && pItem->zIndexedBy==0 ); if( pIndexedBy->n==1 && !pIndexedBy->z ){ /* A "NOT INDEXED" clause was supplied. See parse.y ** construct "indexed_opt" for details. */ pItem->notIndexed = 1; }else{ - pItem->zIndex = sqlite3NameFromToken(pParse->db, pIndexedBy); + pItem->zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); } } } diff --git a/src/expr.c b/src/expr.c index fa5715c04f..56a62e0c3f 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1041,7 +1041,7 @@ SrcList *sqlite3SrcListDup(sqlite3 *db, SrcList *p, int flags){ pNewItem->isCorrelated = pOldItem->isCorrelated; pNewItem->viaCoroutine = pOldItem->viaCoroutine; pNewItem->isRecursive = pOldItem->isRecursive; - pNewItem->zIndex = sqlite3DbStrDup(db, pOldItem->zIndex); + pNewItem->zIndexedBy = sqlite3DbStrDup(db, pOldItem->zIndexedBy); pNewItem->notIndexed = pOldItem->notIndexed; pNewItem->pIndex = pOldItem->pIndex; pTab = pNewItem->pTab = pOldItem->pTab; diff --git a/src/select.c b/src/select.c index 69b7a790c9..d50ff7965e 100644 --- a/src/select.c +++ b/src/select.c @@ -3868,16 +3868,16 @@ static Table *isSimpleCount(Select *p, AggInfo *pAggInfo){ ** pFrom->pIndex and return SQLITE_OK. */ int sqlite3IndexedByLookup(Parse *pParse, struct SrcList_item *pFrom){ - if( pFrom->pTab && pFrom->zIndex ){ + if( pFrom->pTab && pFrom->zIndexedBy ){ Table *pTab = pFrom->pTab; - char *zIndex = pFrom->zIndex; + char *zIndexedBy = pFrom->zIndexedBy; Index *pIdx; for(pIdx=pTab->pIndex; - pIdx && sqlite3StrICmp(pIdx->zName, zIndex); + pIdx && sqlite3StrICmp(pIdx->zName, zIndexedBy); pIdx=pIdx->pNext ); if( !pIdx ){ - sqlite3ErrorMsg(pParse, "no such index: %s", zIndex, 0); + sqlite3ErrorMsg(pParse, "no such index: %s", zIndexedBy, 0); pParse->checkSchema = 1; return SQLITE_ERROR; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a31f363708..5b7fbbc835 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2260,7 +2260,7 @@ struct SrcList { Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ Bitmask colUsed; /* Bit N (1<" clause */ + char *zIndexedBy; /* Identifier from "INDEXED BY " clause */ Index *pIndex; /* Index structure corresponding to zIndex, if any */ } a[1]; /* One entry for each identifier on the list */ }; diff --git a/src/where.c b/src/where.c index ecd6bd2a8f..2dc3b17754 100644 --- a/src/where.c +++ b/src/where.c @@ -6396,7 +6396,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pItem = pWInfo->pTabList->a; pTab = pItem->pTab; if( IsVirtual(pTab) ) return 0; - if( pItem->zIndex ) return 0; + if( pItem->zIndexedBy ) return 0; iCur = pItem->iCursor; pWC = &pWInfo->sWC; pLoop = pBuilder->pNew; From bc8edba10a19a477022353fc34766a3390c8c31d Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 5 Jun 2015 20:27:26 +0000 Subject: [PATCH 11/28] Provide one final Select tree dump prior to WHERE clause analysis when ".selecttrace 0x400" tracing bit is set with SELECTTRACE_ENABLED. Analysis and debug changes only - normal builds are unaffected. FossilOrigin-Name: 283bf0b64da7acc5aa5812fc659954965002d409 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/select.c | 11 +++++++++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index eb67a9af5b..4d3f877745 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sname\sof\sSrcList.a[].zIndex\sto\sthe\smore\sdescriptive\nSrcList.a[0].zIndexedBy. -D 2015-06-04T12:08:53.261 +C Provide\sone\sfinal\sSelect\stree\sdump\sprior\sto\sWHERE\sclause\sanalysis\s\nwhen\s".selecttrace\s0x400"\stracing\sbit\sis\sset\swith\sSELECTTRACE_ENABLED.\nAnalysis\sand\sdebug\schanges\sonly\s-\snormal\sbuilds\sare\sunaffected. +D 2015-06-05T20:27:26.103 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -250,7 +250,7 @@ F src/printf.c 13ce37e5574f9b0682fa86dbcf9faf76b9d82a15 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c 36416c13e4a156fa7e8f29181e28964612767ddf +F src/select.c b2dfbc9ca9e4d04a34c1b4defdfda7867fee0eb8 F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad @@ -1282,7 +1282,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 9f035c45a4b84203e67b6e1b23cf11691dc43f1e -R ad5ce5f5b8d17995393297d9ed2a0d0e +P 6a9cf063379118dbb95c6cdc6d60af50e9867177 +R 7720d4f64678b0c7b4af503d2d9c054f U drh -Z de80e81db21512cdc452bca7645bb7ca +Z 95e994f89cb6168fd34736cd7cbf5b60 diff --git a/manifest.uuid b/manifest.uuid index e2792cff66..c711a8d149 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6a9cf063379118dbb95c6cdc6d60af50e9867177 \ No newline at end of file +283bf0b64da7acc5aa5812fc659954965002d409 \ No newline at end of file diff --git a/src/select.c b/src/select.c index d50ff7965e..a3e92655b1 100644 --- a/src/select.c +++ b/src/select.c @@ -3709,7 +3709,7 @@ static int flattenSubquery( #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ - sqlite3DebugPrintf("After flattening:\n"); + SELECTTRACE(0x100,pParse,p,("After flattening:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif @@ -4889,7 +4889,7 @@ int sqlite3Select( ){ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ - sqlite3DebugPrintf("After WHERE-clause push-down:\n"); + SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif @@ -4964,6 +4964,13 @@ int sqlite3Select( pHaving = p->pHaving; sDistinct.isTnct = (p->selFlags & SF_Distinct)!=0; +#if SELECTTRACE_ENABLED + if( sqlite3SelectTrace & 0x400 ){ + SELECTTRACE(0x400,pParse,p,("After all FROM-clause analysis:\n")); + sqlite3TreeViewSelect(0, p, 0); + } +#endif + #ifndef SQLITE_OMIT_COMPOUND_SELECT /* If there is are a sequence of queries, do the earlier ones first. */ From 4490c40b90039ea48db8c88c81234787ec0ab0ba Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 5 Jun 2015 22:33:39 +0000 Subject: [PATCH 12/28] Split FROM-clause subquery flattening and code generation into separate loops. FossilOrigin-Name: be8e3fc70e4c13b28b07985df3457960f58ffddd --- manifest | 17 +++-- manifest.uuid | 2 +- src/expr.c | 8 --- src/select.c | 188 +++++++++++++++++++++++++++----------------------- 4 files changed, 111 insertions(+), 104 deletions(-) diff --git a/manifest b/manifest index 4d3f877745..d868635d2e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Provide\sone\sfinal\sSelect\stree\sdump\sprior\sto\sWHERE\sclause\sanalysis\s\nwhen\s".selecttrace\s0x400"\stracing\sbit\sis\sset\swith\sSELECTTRACE_ENABLED.\nAnalysis\sand\sdebug\schanges\sonly\s-\snormal\sbuilds\sare\sunaffected. -D 2015-06-05T20:27:26.103 +C Split\sFROM-clause\ssubquery\sflattening\sand\scode\sgeneration\sinto\sseparate\sloops. +D 2015-06-05T22:33:39.408 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -202,7 +202,7 @@ F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e -F src/expr.c d953b9f03c3c0f701f87a418fcfb9cba8befc6e0 +F src/expr.c 12e04f322956076b1f8748ca572568968f8155d9 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 F src/func.c 5b8b8e77a0fb644eaf8947d413804622e32692b6 @@ -250,7 +250,7 @@ F src/printf.c 13ce37e5574f9b0682fa86dbcf9faf76b9d82a15 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c b2dfbc9ca9e4d04a34c1b4defdfda7867fee0eb8 +F src/select.c 6a8f2c442dc69ff343411788e5146b45ddb87609 F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad @@ -1282,7 +1282,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 6a9cf063379118dbb95c6cdc6d60af50e9867177 -R 7720d4f64678b0c7b4af503d2d9c054f +P 283bf0b64da7acc5aa5812fc659954965002d409 +R 7215f59414fcbc308f2938a5f5f79857 +T *branch * view-optimization +T *sym-view-optimization * +T -sym-trunk * U drh -Z 95e994f89cb6168fd34736cd7cbf5b60 +Z b4c3a234d5928895ab25f2763d32a4ad diff --git a/manifest.uuid b/manifest.uuid index c711a8d149..39d8550257 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -283bf0b64da7acc5aa5812fc659954965002d409 \ No newline at end of file +be8e3fc70e4c13b28b07985df3457960f58ffddd \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 56a62e0c3f..d62346e39d 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3559,14 +3559,6 @@ void sqlite3TreeViewExprList( sqlite3TreeViewLine(pView, "%s", zLabel); for(i=0; inExpr; i++){ 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); - } -#endif } } sqlite3TreeViewPop(pView); diff --git a/src/select.c b/src/select.c index a3e92655b1..2341e84509 100644 --- a/src/select.c +++ b/src/select.c @@ -4842,14 +4842,54 @@ int sqlite3Select( } #endif - /* Generate code for all sub-queries in the FROM clause + /* Try to flatten subqueries in the FROM clause into the main query */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && inSrc; i++){ struct SrcList_item *pItem = &pTabList->a[i]; - SelectDest dest; Select *pSub = pItem->pSelect; int isAggSub; + if( pSub==0 ) continue; + isAggSub = (pSub->selFlags & SF_Aggregate)!=0; + if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ + /* This subquery can be absorbed into its parent. */ + if( isAggSub ){ + isAgg = 1; + p->selFlags |= SF_Aggregate; + } + i = -1; + } + pTabList = p->pSrc; + if( db->mallocFailed ) goto select_end; + if( !IgnorableOrderby(pDest) ){ + sSort.pOrderBy = p->pOrderBy; + } + } +#endif + + +#ifndef SQLITE_OMIT_COMPOUND_SELECT + /* Handle compound SELECT statements using the separate multiSelect() + ** procedure. + */ + 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 + + /* Generate code for all sub-queries in the FROM clause + */ +#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) + for(i=0; inSrc; i++){ + struct SrcList_item *pItem = &pTabList->a[i]; + SelectDest dest; + Select *pSub = pItem->pSelect; if( pSub==0 ) continue; @@ -4875,87 +4915,73 @@ int sqlite3Select( */ pParse->nHeight += sqlite3SelectExprHeight(p); - isAggSub = (pSub->selFlags & SF_Aggregate)!=0; - if( flattenSubquery(pParse, p, i, isAgg, isAggSub) ){ - /* This subquery can be absorbed into its parent. */ - if( isAggSub ){ - isAgg = 1; - p->selFlags |= SF_Aggregate; - } - i = -1; - }else{ - if( (pItem->jointype & JT_OUTER)==0 - && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor) - ){ + if( (pItem->jointype & JT_OUTER)==0 + && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor) + ){ #if SELECTTRACE_ENABLED - if( sqlite3SelectTrace & 0x100 ){ - SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n")); - sqlite3TreeViewSelect(0, p, 0); - } + if( sqlite3SelectTrace & 0x100 ){ + SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n")); + sqlite3TreeViewSelect(0, p, 0); + } #endif - } - if( pTabList->nSrc==1 - && (p->selFlags & SF_All)==0 - && OptimizationEnabled(db, SQLITE_SubqCoroutine) - ){ - /* Implement a co-routine that will return a single row of the result - ** set on each invocation. - */ - int addrTop = sqlite3VdbeCurrentAddr(v)+1; - pItem->regReturn = ++pParse->nMem; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); - VdbeComment((v, "%s", pItem->pTab->zName)); - pItem->addrFillSub = addrTop; - sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); - explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); - sqlite3Select(pParse, pSub, &dest); - pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); - pItem->viaCoroutine = 1; - pItem->regResult = dest.iSdst; - sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn); - sqlite3VdbeJumpHere(v, addrTop-1); - sqlite3ClearTempRegCache(pParse); + } + if( pTabList->nSrc==1 + && (p->selFlags & SF_All)==0 + && OptimizationEnabled(db, SQLITE_SubqCoroutine) + ){ + /* Implement a co-routine that will return a single row of the result + ** set on each invocation. + */ + int addrTop = sqlite3VdbeCurrentAddr(v)+1; + pItem->regReturn = ++pParse->nMem; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); + VdbeComment((v, "%s", pItem->pTab->zName)); + pItem->addrFillSub = addrTop; + sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); + explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); + sqlite3Select(pParse, pSub, &dest); + pItem->pTab->nRowLogEst = sqlite3LogEst(pSub->nSelectRow); + pItem->viaCoroutine = 1; + pItem->regResult = dest.iSdst; + sqlite3VdbeAddOp1(v, OP_EndCoroutine, pItem->regReturn); + sqlite3VdbeJumpHere(v, addrTop-1); + sqlite3ClearTempRegCache(pParse); + }else{ + /* Generate a subroutine that will fill an ephemeral table with + ** the content of this subquery. pItem->addrFillSub will point + ** to the address of the generated subroutine. pItem->regReturn + ** is a register allocated to hold the subroutine return address + */ + int topAddr; + int onceAddr = 0; + int retAddr; + assert( pItem->addrFillSub==0 ); + pItem->regReturn = ++pParse->nMem; + topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); + pItem->addrFillSub = topAddr+1; + if( pItem->isCorrelated==0 ){ + /* If the subquery is not correlated and if we are not inside of + ** a trigger, then we only need to compute the value of the subquery + ** once. */ + onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); + VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); }else{ - /* Generate a subroutine that will fill an ephemeral table with - ** the content of this subquery. pItem->addrFillSub will point - ** to the address of the generated subroutine. pItem->regReturn - ** is a register allocated to hold the subroutine return address - */ - int topAddr; - int onceAddr = 0; - int retAddr; - assert( pItem->addrFillSub==0 ); - pItem->regReturn = ++pParse->nMem; - topAddr = sqlite3VdbeAddOp2(v, OP_Integer, 0, pItem->regReturn); - pItem->addrFillSub = topAddr+1; - if( pItem->isCorrelated==0 ){ - /* If the subquery is not correlated and if we are not inside of - ** a trigger, then we only need to compute the value of the subquery - ** once. */ - onceAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v); - VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); - }else{ - VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); - } - sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); - explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); - sqlite3Select(pParse, pSub, &dest); - 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)); - sqlite3VdbeChangeP1(v, topAddr, retAddr); - sqlite3ClearTempRegCache(pParse); + VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); } + sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); + explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); + sqlite3Select(pParse, pSub, &dest); + 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)); + sqlite3VdbeChangeP1(v, topAddr, retAddr); + sqlite3ClearTempRegCache(pParse); } if( db->mallocFailed ){ goto select_end; } pParse->nHeight -= sqlite3SelectExprHeight(p); - pTabList = p->pSrc; - if( !IgnorableOrderby(pDest) ){ - sSort.pOrderBy = p->pOrderBy; - } } pEList = p->pEList; #endif @@ -4971,20 +4997,6 @@ int sqlite3Select( } #endif -#ifndef SQLITE_OMIT_COMPOUND_SELECT - /* If there is are a sequence of queries, do the earlier ones first. - */ - 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 - /* 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: From adc57f6834167cd55e8c4d1129cf2c32ee3cfde0 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 6 Jun 2015 00:18:01 +0000 Subject: [PATCH 13/28] Minor cleanup of the sqlite3Select() procedure. FossilOrigin-Name: f4c90d06bb941453d8110680c7b279e471e8f034 --- manifest | 15 ++++++-------- manifest.uuid | 2 +- src/select.c | 54 ++++++++++++++++++++++++++------------------------- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/manifest b/manifest index d868635d2e..26d43362ba 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Split\sFROM-clause\ssubquery\sflattening\sand\scode\sgeneration\sinto\sseparate\sloops. -D 2015-06-05T22:33:39.408 +C Minor\scleanup\sof\sthe\ssqlite3Select()\sprocedure. +D 2015-06-06T00:18:01.663 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -250,7 +250,7 @@ F src/printf.c 13ce37e5574f9b0682fa86dbcf9faf76b9d82a15 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c 6a8f2c442dc69ff343411788e5146b45ddb87609 +F src/select.c 630623e6536115ec360e07be3cb5e01fab9166f9 F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad @@ -1282,10 +1282,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 283bf0b64da7acc5aa5812fc659954965002d409 -R 7215f59414fcbc308f2938a5f5f79857 -T *branch * view-optimization -T *sym-view-optimization * -T -sym-trunk * +P be8e3fc70e4c13b28b07985df3457960f58ffddd +R c9ba4b66998c994d5a4d88f3868eca18 U drh -Z b4c3a234d5928895ab25f2763d32a4ad +Z f5a7ad6c64c16a42ea0d51c96b63ee57 diff --git a/manifest.uuid b/manifest.uuid index 39d8550257..e0f55059d7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -be8e3fc70e4c13b28b07985df3457960f58ffddd \ No newline at end of file +f4c90d06bb941453d8110680c7b279e471e8f034 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 2341e84509..9dd34dc567 100644 --- a/src/select.c +++ b/src/select.c @@ -4814,12 +4814,11 @@ int sqlite3Select( memset(&sSort, 0, sizeof(sSort)); sSort.pOrderBy = p->pOrderBy; pTabList = p->pSrc; - pEList = p->pEList; if( pParse->nErr || db->mallocFailed ){ goto select_end; } + assert( p->pEList!=0 ); isAgg = (p->selFlags & SF_Aggregate)!=0; - assert( pEList!=0 ); #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x100 ){ SELECTTRACE(0x100,pParse,p, ("after name resolution:\n")); @@ -4828,21 +4827,16 @@ int sqlite3Select( #endif - /* Begin generating code. - */ - v = sqlite3GetVdbe(pParse); - if( v==0 ) goto select_end; - /* If writing to memory or generating a set ** only a single column may be output. */ #ifndef SQLITE_OMIT_SUBQUERY - if( checkForMultiColumnSelectError(pParse, pDest, pEList->nExpr) ){ + if( checkForMultiColumnSelectError(pParse, pDest, p->pEList->nExpr) ){ goto select_end; } #endif - /* Try to flatten subqueries in the FROM clause into the main query + /* Try to flatten subqueries in the FROM clause up into the main query */ #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) for(i=0; !p->pPrior && inSrc; i++){ @@ -4867,6 +4861,10 @@ int sqlite3Select( } #endif + /* Get a pointer the VDBE under construction, allocating a new VDBE if one + ** does not already exist */ + v = sqlite3GetVdbe(pParse); + if( v==0 ) goto select_end; #ifndef SQLITE_OMIT_COMPOUND_SELECT /* Handle compound SELECT statements using the separate multiSelect() @@ -4890,7 +4888,6 @@ int sqlite3Select( struct SrcList_item *pItem = &pTabList->a[i]; SelectDest dest; Select *pSub = pItem->pSelect; - if( pSub==0 ) continue; /* Sometimes the code for a subquery will be generated more than @@ -4915,6 +4912,9 @@ int sqlite3Select( */ pParse->nHeight += sqlite3SelectExprHeight(p); + /* Make copies of constant WHERE-clause terms in the outer query down + ** inside the subquery. This can help the subquery to run more efficiently. + */ if( (pItem->jointype & JT_OUTER)==0 && pushDownWhereTerms(db, pSub, p->pWhere, pItem->iCursor) ){ @@ -4925,6 +4925,9 @@ int sqlite3Select( } #endif } + + /* Generate code to implement the subquery + */ if( pTabList->nSrc==1 && (p->selFlags & SF_All)==0 && OptimizationEnabled(db, SQLITE_SubqCoroutine) @@ -4978,13 +4981,13 @@ int sqlite3Select( sqlite3VdbeChangeP1(v, topAddr, retAddr); sqlite3ClearTempRegCache(pParse); } - if( db->mallocFailed ){ - goto select_end; - } + if( db->mallocFailed ) goto select_end; pParse->nHeight -= sqlite3SelectExprHeight(p); } - pEList = p->pEList; #endif + + /* Various elements of the SELECT copied into local variables for convenience */ + pEList = p->pEList; pWhere = p->pWhere; pGroupBy = p->pGroupBy; pHaving = p->pHaving; @@ -5013,23 +5016,23 @@ 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(sSort.pOrderBy, p->pEList, -1)==0 + && sqlite3ExprListCompare(sSort.pOrderBy, pEList, -1)==0 ){ p->selFlags &= ~SF_Distinct; - p->pGroupBy = sqlite3ExprListDup(db, p->pEList, 0); - pGroupBy = p->pGroupBy; + pGroupBy = p->pGroupBy = sqlite3ExprListDup(db, pEList, 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 */ assert( sDistinct.isTnct ); } - /* If there is an ORDER BY clause, then this sorting - ** index might end up being unused if the data can be - ** extracted in pre-sorted order. If that is the case, then the - ** OP_OpenEphemeral instruction will be changed to an OP_Noop once - ** we figure out that the sorting index is not needed. The addrSortIndex - ** variable is used to facilitate that change. + /* If there is an ORDER BY clause, then create an ephemeral index to + ** do the sorting. But this sorting ephemeral index might end up + ** being unused if the data can be extracted in pre-sorted order. + ** If that is the case, then the OP_OpenEphemeral instruction will be + ** changed to an OP_Noop once we figure out that the sorting index is + ** not needed. The sSort.addrSortIndex variable is used to facilitate + ** that change. */ if( sSort.pOrderBy ){ KeyInfo *pKeyInfo; @@ -5060,7 +5063,7 @@ int sqlite3Select( sSort.sortFlags |= SORTFLAG_UseSorter; } - /* Open a virtual index to use for the distinct set. + /* Open an ephemeral index to use for the distinct set. */ if( p->selFlags & SF_Distinct ){ sDistinct.tabTnct = pParse->nTab++; @@ -5145,11 +5148,10 @@ 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 + ** in the correct order. It also may not - the GROUP BY might 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 From b121dd14ac5a2675f439b72700fd8f9162510fc9 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 6 Jun 2015 18:30:17 +0000 Subject: [PATCH 14/28] Code simplifications in select.c and where.c. FossilOrigin-Name: 4f20ac90bce8bd7ba43ef59af5cc4ef7aa282fe8 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/select.c | 21 ++++++++++----------- src/where.c | 51 +++++++++++++++++++++++---------------------------- 4 files changed, 41 insertions(+), 47 deletions(-) diff --git a/manifest b/manifest index 26d43362ba..056725afea 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Minor\scleanup\sof\sthe\ssqlite3Select()\sprocedure. -D 2015-06-06T00:18:01.663 +C Code\ssimplifications\sin\sselect.c\sand\swhere.c. +D 2015-06-06T18:30:17.822 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -250,7 +250,7 @@ F src/printf.c 13ce37e5574f9b0682fa86dbcf9faf76b9d82a15 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c 630623e6536115ec360e07be3cb5e01fab9166f9 +F src/select.c d507fe715b12e6aba157fa34b0a5680809e59bac F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad @@ -326,7 +326,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 2db8137f14644e2117c2e2350e08a05e02d6bdab +F src/where.c 5cc416ad6d8b6d2027735fcf7c5a6165bb745636 F src/whereInt.h a6f5a762bc1b4b1c76e1cea79976b437ac35a435 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -1282,7 +1282,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P be8e3fc70e4c13b28b07985df3457960f58ffddd -R c9ba4b66998c994d5a4d88f3868eca18 +P f4c90d06bb941453d8110680c7b279e471e8f034 +R 042f84cf941d82ab55744b287e51eff7 U drh -Z f5a7ad6c64c16a42ea0d51c96b63ee57 +Z f6bc4d318934fdab6d55b7066c6ff342 diff --git a/manifest.uuid b/manifest.uuid index e0f55059d7..c2c5ef4ae1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f4c90d06bb941453d8110680c7b279e471e8f034 \ No newline at end of file +4f20ac90bce8bd7ba43ef59af5cc4ef7aa282fe8 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 9dd34dc567..f801d1033a 100644 --- a/src/select.c +++ b/src/select.c @@ -1310,28 +1310,27 @@ static void generateSortTail( */ #ifdef SQLITE_ENABLE_COLUMN_METADATA # define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,C,D,E,F) +#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */ +# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F) +#endif static const char *columnTypeImpl( NameContext *pNC, Expr *pExpr, +#ifdef SQLITE_ENABLE_COLUMN_METADATA const char **pzOrigDb, const char **pzOrigTab, const char **pzOrigCol, +#endif u8 *pEstWidth ){ - char const *zOrigDb = 0; - char const *zOrigTab = 0; - char const *zOrigCol = 0; -#else /* if !defined(SQLITE_ENABLE_COLUMN_METADATA) */ -# define columnType(A,B,C,D,E,F) columnTypeImpl(A,B,F) -static const char *columnTypeImpl( - NameContext *pNC, - Expr *pExpr, - u8 *pEstWidth -){ -#endif /* !defined(SQLITE_ENABLE_COLUMN_METADATA) */ char const *zType = 0; int j; u8 estWidth = 1; +#ifdef SQLITE_ENABLE_COLUMN_METADATA + char const *zOrigDb = 0; + char const *zOrigTab = 0; + char const *zOrigCol = 0; +#endif if( NEVER(pExpr==0) || pNC->pSrcList==0 ) return 0; switch( pExpr->op ){ diff --git a/src/where.c b/src/where.c index 2dc3b17754..f98616f9fc 100644 --- a/src/where.c +++ b/src/where.c @@ -616,6 +616,11 @@ static void exprAnalyze(SrcList*, WhereClause*, int); /* ** Call exprAnalyze on all terms in a WHERE clause. +** +** Note that exprAnalyze() might add new virtual terms onto the +** end of the WHERE clause. We do not want to analyze these new +** virtual terms, so start analyzing at the end and work forward +** so that the added virtual terms are never processed. */ static void exprAnalyzeAll( SrcList *pTabList, /* the FROM clause */ @@ -891,7 +896,7 @@ static void whereCombineDisjuncts( ** ** CASE 2: ** -** If there are exactly two disjuncts one side has x>A and the other side +** If there are exactly two disjuncts and 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: ** @@ -920,22 +925,22 @@ static void whereCombineDisjuncts( ** is decided elsewhere. This analysis only looks at whether subterms ** appropriate for indexing exist. ** -** All examples A through E above satisfy case 2. But if a term +** All examples A through E above satisfy case 3. But if a term ** 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 +** always prefer case 1, so in that case we pretend that case 3 is not ** satisfied. ** ** It might be the case that multiple tables are indexable. For example, ** (E) above is indexable on tables P, Q, and R. ** -** Terms that satisfy case 2 are candidates for lookup by using +** Terms that satisfy case 3 are candidates for lookup by using ** separate indices to find rowids for each subterm and composing ** the union of all rowids using a RowSet object. This is similar ** to "bitmap indices" in other database engines. ** ** OTHERWISE: ** -** If neither case 1 nor case 2 apply, then leave the eOperator set to +** If none of cases 1, 2, or 3 apply, then leave the eOperator set to ** zero. This term is not useful for search. */ static void exprAnalyzeOrTerm( @@ -973,7 +978,7 @@ static void exprAnalyzeOrTerm( assert( pOrWc->nTerm>=2 ); /* - ** Compute the set of tables that might satisfy cases 1 or 2. + ** Compute the set of tables that might satisfy cases 1 or 3. */ indexable = ~(Bitmask)0; chngToIN = ~(Bitmask)0; @@ -1188,7 +1193,7 @@ static void exprAnalyzeOrTerm( ** relation: ** 1. The SQLITE_Transitive optimization must be enabled ** 2. Must be either an == or an IS operator -** 3. Not originating the ON clause of an OUTER JOIN +** 3. Not originating in the ON clause of an OUTER JOIN ** 4. The affinities of A and B must be compatible ** 5a. Both operands use the same collating sequence OR ** 5b. The overall collating sequence is BINARY @@ -1589,8 +1594,8 @@ static int findIndexCol( ** Return true if the DISTINCT expression-list passed as the third argument ** is redundant. ** -** A DISTINCT list is redundant if the database contains some subset of -** columns that are unique and non-null. +** A DISTINCT list is redundant if any subset of the columns in the +** DISTINCT list are collectively unique and individually non-null. */ static int isDistinctRedundant( Parse *pParse, /* Parsing context */ @@ -6689,15 +6694,9 @@ WhereInfo *sqlite3WhereBegin( } #endif - /* Analyze all of the subexpressions. Note that exprAnalyze() might - ** add new virtual terms onto the end of the WHERE clause. We do not - ** want to analyze these virtual terms, so start analyzing at the end - ** and work forward so that the added virtual terms are never processed. - */ + /* Analyze all of the subexpressions. */ exprAnalyzeAll(pTabList, &pWInfo->sWC); - if( db->mallocFailed ){ - goto whereBeginError; - } + if( db->mallocFailed ) goto whereBeginError; if( wctrlFlags & WHERE_WANT_DISTINCT ){ if( isDistinctRedundant(pParse, pTabList, &pWInfo->sWC, pResultSet) ){ @@ -6713,8 +6712,7 @@ WhereInfo *sqlite3WhereBegin( /* Construct the WhereLoop objects */ WHERETRACE(0xffff,("*** Optimizer Start ***\n")); #if defined(WHERETRACE_ENABLED) - /* Display all terms of the WHERE clause */ - if( sqlite3WhereTrace & 0x100 ){ + if( sqlite3WhereTrace & 0x100 ){ /* Display all terms of the WHERE clause */ int i; for(i=0; inTerm; i++){ whereTermPrint(&sWLB.pWC->a[i], i); @@ -6726,13 +6724,12 @@ WhereInfo *sqlite3WhereBegin( rc = whereLoopAddAll(&sWLB); if( rc ) goto whereBeginError; - /* Display all of the WhereLoop objects if wheretrace is enabled */ -#ifdef WHERETRACE_ENABLED /* !=0 */ - if( sqlite3WhereTrace ){ +#ifdef WHERETRACE_ENABLED + if( sqlite3WhereTrace ){ /* Display all of the WhereLoop objects */ WhereLoop *p; int i; - static char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" - "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; + static const char zLabel[] = "0123456789abcdefghijklmnopqrstuvwyxz" + "ABCDEFGHIJKLMNOPQRSTUVWYXZ"; for(p=pWInfo->pLoops, i=0; p; p=p->pNextLoop, i++){ p->cId = zLabel[i%sizeof(zLabel)]; whereLoopPrint(p, sWLB.pWC); @@ -6753,7 +6750,7 @@ WhereInfo *sqlite3WhereBegin( if( pParse->nErr || NEVER(db->mallocFailed) ){ goto whereBeginError; } -#ifdef WHERETRACE_ENABLED /* !=0 */ +#ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); if( pWInfo->nOBSat>0 ){ @@ -6816,7 +6813,7 @@ WhereInfo *sqlite3WhereBegin( /* If the caller is an UPDATE or DELETE statement that is requesting ** to use a one-pass algorithm, determine if this is appropriate. ** The one-pass algorithm only works if the WHERE clause constrains - ** the statement to update a single row. + ** the statement to update or delete a single row. */ assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 ); if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 @@ -6830,7 +6827,6 @@ WhereInfo *sqlite3WhereBegin( /* Open all tables in the pTabList and any indices selected for ** searching those tables. */ - notReady = ~(Bitmask)0; for(ii=0, pLevel=pWInfo->a; ii=0 ) sqlite3CodeVerifySchema(pParse, iDb); - notReady &= ~getMask(&pWInfo->sMaskSet, pTabItem->iCursor); } pWInfo->iTop = sqlite3VdbeCurrentAddr(v); if( db->mallocFailed ) goto whereBeginError; From 6f82e85a802742c347275e529202a7fd22cdfcbe Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 6 Jun 2015 20:12:09 +0000 Subject: [PATCH 15/28] Split out the bulk of the actual VDBE code generation logic from where.c into a new file, leaving behind the analysis logic. This makes the original where.c smaller and hopefully easier to edit. FossilOrigin-Name: faa0e420e93a2bc1c84df9eb9fef4748d29ce339 --- Makefile.in | 7 +- Makefile.msc | 7 +- main.mk | 4 +- manifest | 23 +- manifest.uuid | 2 +- src/where.c | 1528 +------------------------------------------ src/whereInt.h | 52 +- src/wherecode.c | 1501 ++++++++++++++++++++++++++++++++++++++++++ tool/mksqlite3c.tcl | 1 + 9 files changed, 1605 insertions(+), 1520 deletions(-) create mode 100644 src/wherecode.c diff --git a/Makefile.in b/Makefile.in index 1d06c40e12..48dba42e63 100644 --- a/Makefile.in +++ b/Makefile.in @@ -184,7 +184,7 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.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 + vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo utf.lo vtab.lo # Object files for the amalgamation. # @@ -293,6 +293,7 @@ SRC = \ $(TOP)/src/wal.h \ $(TOP)/src/walker.c \ $(TOP)/src/where.c \ + $(TOP)/src/wherecode.c \ $(TOP)/src/whereInt.h # Source code for extensions @@ -454,6 +455,7 @@ TESTSRC2 = \ $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbetrace.c \ $(TOP)/src/where.c \ + $(TOP)/src/wherecode.c \ parse.c \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ @@ -849,6 +851,9 @@ 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 + tclsqlite.lo: $(TOP)/src/tclsqlite.c $(HDR) $(LTCOMPILE) -DUSE_TCL_STUBS=1 -c $(TOP)/src/tclsqlite.c diff --git a/Makefile.msc b/Makefile.msc index 642616e935..6cd1f37b81 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -838,7 +838,7 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.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 + vdbetrace.lo wal.lo walker.lo where.lo wherecode.lo utf.lo vtab.lo # Object files for the amalgamation. # @@ -959,6 +959,7 @@ SRC2 = \ $(TOP)\src\wal.h \ $(TOP)\src\walker.c \ $(TOP)\src\where.c \ + $(TOP)\src\wherecode.c \ $(TOP)\src\whereInt.h # Source code for extensions @@ -1121,6 +1122,7 @@ TESTSRC2 = \ $(TOP)\src\vdbesort.c \ $(TOP)\src\vdbetrace.c \ $(TOP)\src\where.c \ + $(TOP)\src\wherecode.c \ parse.c \ $(TOP)\ext\fts3\fts3.c \ $(TOP)\ext\fts3\fts3_aux.c \ @@ -1530,6 +1532,9 @@ 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 + tclsqlite.lo: $(TOP)\src\tclsqlite.c $(HDR) $(LTCOMPILE) $(NO_WARN) -DUSE_TCL_STUBS=1 -DBUILD_sqlite -I$(TCLINCDIR) -c $(TOP)\src\tclsqlite.c diff --git a/main.mk b/main.mk index 49f78c3ad4..71ce38ad32 100644 --- a/main.mk +++ b/main.mk @@ -69,7 +69,7 @@ LIBOBJ+= vdbe.o parse.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 + vdbetrace.o wal.o walker.o where.o wherecode.o utf.o vtab.o @@ -171,6 +171,7 @@ SRC = \ $(TOP)/src/wal.h \ $(TOP)/src/walker.c \ $(TOP)/src/where.c \ + $(TOP)/src/wherecode.c \ $(TOP)/src/whereInt.h # Source code for extensions @@ -337,6 +338,7 @@ TESTSRC2 = \ $(TOP)/src/vdbe.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/where.c \ + $(TOP)/src/wherecode.c \ parse.c \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ diff --git a/manifest b/manifest index 056725afea..e7b9ade388 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Code\ssimplifications\sin\sselect.c\sand\swhere.c. -D 2015-06-06T18:30:17.822 +C Split\sout\sthe\sbulk\sof\sthe\sactual\sVDBE\scode\sgeneration\slogic\sfrom\swhere.c\ninto\sa\snew\sfile,\sleaving\sbehind\sthe\sanalysis\slogic.\s\sThis\smakes\sthe\soriginal\nwhere.c\ssmaller\sand\shopefully\seasier\sto\sedit. +D 2015-06-06T20:12:09.183 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in 994bab32a3a69e0c35bd148b65cde49879772964 +F Makefile.in 64136f59edd49b389b5c5d24388e204929b807e5 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc d37d2c2323df3acae6e24c71a478889421c17264 +F Makefile.msc e2f1f95dc4a0af0b9ac3c2ee66878700b71ad93f F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858 F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7 F VERSION ce0ae95abd7121c534f6917c1c8f2b70d9acd4db @@ -171,7 +171,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 8d418497da6a152a59b00d64ae3d66f3c665974c +F main.mk b9e0c806c04739b20f281680f8771bc2e20acd54 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk d5e22023b5238985bb54a72d33e0ac71fe4f8a32 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -326,8 +326,9 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 5cc416ad6d8b6d2027735fcf7c5a6165bb745636 -F src/whereInt.h a6f5a762bc1b4b1c76e1cea79976b437ac35a435 +F src/where.c c9d804dcf02388207096e4da19487d9a2a7a9a67 +F src/whereInt.h 40e1d060b6aa02edbb7b8a1f3dfc0cc4ff140881 +F src/wherecode.c 0669481cabaf5caf934b6bb825df15bc57f60d40 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1247,7 +1248,7 @@ F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e F tool/mkpragmatab.tcl 40c287d3f929ece67da6e9e7c49885789960accf F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl 69bae8ce4aa52d2ff82d4a8a856bf283ec035b2e -F tool/mksqlite3c.tcl fdeab4c1eed90b7ab741ec12a7bc5c2fb60188bd +F tool/mksqlite3c.tcl 9f60238b2273048a4089077a43716d3b33a67c51 F tool/mksqlite3h.tcl 44730d586c9031638cdd2eb443b801c0d2dbd9f8 F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b F tool/mkvsix.tcl 3b58b9398f91c7dbf18d49eb87cefeee9efdbce1 @@ -1282,7 +1283,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P f4c90d06bb941453d8110680c7b279e471e8f034 -R 042f84cf941d82ab55744b287e51eff7 +P 4f20ac90bce8bd7ba43ef59af5cc4ef7aa282fe8 +R f7b66d3e1070ad2d563a494aba699c70 U drh -Z f6bc4d318934fdab6d55b7066c6ff342 +Z 85351aea272e066665037522f98406f9 diff --git a/manifest.uuid b/manifest.uuid index c2c5ef4ae1..a3541920e7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4f20ac90bce8bd7ba43ef59af5cc4ef7aa282fe8 \ No newline at end of file +faa0e420e93a2bc1c84df9eb9fef4748d29ce339 \ No newline at end of file diff --git a/src/where.c b/src/where.c index f98616f9fc..e446f6db8c 100644 --- a/src/where.c +++ b/src/where.c @@ -19,6 +19,15 @@ #include "sqliteInt.h" #include "whereInt.h" +/* Forward declaration of methods */ +static int whereLoopResize(sqlite3*, WhereLoop*, int); + +/* Test variable that can be set to enable WHERE tracing */ +#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) +/***/ int sqlite3WhereTrace = 0; +#endif + + /* ** Return the estimated number of output rows from a WHERE clause */ @@ -275,7 +284,7 @@ static void whereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ ** Return the bitmask for the given cursor number. Return 0 if ** iCursor is not in the set. */ -static Bitmask getMask(WhereMaskSet *pMaskSet, int iCursor){ +Bitmask sqlite3WhereGetMask(WhereMaskSet *pMaskSet, int iCursor){ int i; assert( pMaskSet->n<=(int)sizeof(Bitmask)*8 ); for(i=0; in; i++){ @@ -310,7 +319,7 @@ static Bitmask exprTableUsage(WhereMaskSet *pMaskSet, Expr *p){ Bitmask mask = 0; if( p==0 ) return 0; if( p->op==TK_COLUMN ){ - mask = getMask(pMaskSet, p->iTable); + mask = sqlite3WhereGetMask(pMaskSet, p->iTable); return mask; } mask = exprTableUsage(pMaskSet, p->pRight); @@ -584,7 +593,7 @@ static WhereTerm *whereScanInit( ** the form "X " exist. If no terms with a constant RHS ** exist, try to return a term that does not use WO_EQUIV. */ -static WhereTerm *findTerm( +WhereTerm *sqlite3WhereFindTerm( WhereClause *pWC, /* The WHERE clause to be searched */ int iCur, /* Cursor number of LHS */ int iColumn, /* Column number of LHS */ @@ -1006,7 +1015,7 @@ static void exprAnalyzeOrTerm( for(j=0, pAndTerm=pAndWC->a; jnTerm; j++, pAndTerm++){ assert( pAndTerm->pExpr ); if( allowedOp(pAndTerm->pExpr->op) ){ - b |= getMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); + b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); } } } @@ -1017,10 +1026,10 @@ static void exprAnalyzeOrTerm( ** corresponding TERM_VIRTUAL term */ }else{ Bitmask b; - b = getMask(&pWInfo->sMaskSet, pOrTerm->leftCursor); + b = sqlite3WhereGetMask(&pWInfo->sMaskSet, pOrTerm->leftCursor); if( pOrTerm->wtFlags & TERM_VIRTUAL ){ WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent]; - b |= getMask(&pWInfo->sMaskSet, pOther->leftCursor); + b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pOther->leftCursor); } indexable &= b; if( (pOrTerm->eOperator & WO_EQ)==0 ){ @@ -1096,7 +1105,7 @@ static void exprAnalyzeOrTerm( assert( j==1 ); continue; } - if( (chngToIN & getMask(&pWInfo->sMaskSet, pOrTerm->leftCursor))==0 ){ + if( (chngToIN & sqlite3WhereGetMask(&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 preceded ** or follwed by an inverted copy (t2.b==t1.a). Skip this term @@ -1115,7 +1124,7 @@ static void exprAnalyzeOrTerm( ** on the second iteration */ assert( j==1 ); assert( IsPowerOfTwo(chngToIN) ); - assert( chngToIN==getMask(&pWInfo->sMaskSet, iCursor) ); + assert( chngToIN==sqlite3WhereGetMask(&pWInfo->sMaskSet, iCursor) ); break; } testcase( j==1 ); @@ -1287,7 +1296,7 @@ static void exprAnalyze( } prereqAll = exprTableUsage(pMaskSet, pExpr); if( ExprHasProperty(pExpr, EP_FromJoin) ){ - Bitmask x = getMask(pMaskSet, pExpr->iRightJoinTable); + Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable); prereqAll |= x; extraRight = x-1; /* ON clause terms may not be used with an index ** on left table of a LEFT JOIN. Ticket #3015 */ @@ -1641,7 +1650,7 @@ static int isDistinctRedundant( 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) ){ + if( 0==sqlite3WhereFindTerm(pWC, iBase, iCol, ~(Bitmask)0, WO_EQ, pIdx) ){ int iIdxCol = findIndexCol(pParse, pDistinct, iBase, pIdx, i); if( iIdxCol<0 || pTab->aCol[iCol].notNull==0 ){ break; @@ -2763,1487 +2772,6 @@ static int whereInScanEst( } #endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ -/* -** Disable a term in the WHERE clause. Except, do not disable the term -** if it controls a LEFT OUTER JOIN and it did not originate in the ON -** or USING clause of that join. -** -** Consider the term t2.z='ok' in the following queries: -** -** (1) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x WHERE t2.z='ok' -** (2) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x AND t2.z='ok' -** (3) SELECT * FROM t1, t2 WHERE t1.a=t2.x AND t2.z='ok' -** -** The t2.z='ok' is disabled in the in (2) because it originates -** in the ON clause. The term is disabled in (3) because it is not part -** of a LEFT OUTER JOIN. In (1), the term is not disabled. -** -** Disabling a term causes that term to not be tested in the inner loop -** of the join. Disabling is an optimization. When terms are satisfied -** by indices, we disable them to prevent redundant tests in the inner -** loop. We would get the correct results if nothing were ever disabled, -** 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){ - int nLoop = 0; - while( pTerm - && (pTerm->wtFlags & TERM_CODED)==0 - && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) - && (pLevel->notReady & pTerm->prereqAll)==0 - ){ - 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++; - } -} - -/* -** Code an OP_Affinity opcode to apply the column affinity string zAff -** to the n registers starting at base. -** -** As an optimization, SQLITE_AFF_BLOB entries (which are no-ops) at the -** beginning and end of zAff are ignored. If all entries in zAff are -** SQLITE_AFF_BLOB, then no code gets generated. -** -** This routine makes its own copy of zAff so that the caller is free -** to modify zAff after this routine returns. -*/ -static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){ - Vdbe *v = pParse->pVdbe; - if( zAff==0 ){ - assert( pParse->db->mallocFailed ); - return; - } - assert( v!=0 ); - - /* Adjust base and n to skip over SQLITE_AFF_BLOB entries at the beginning - ** and end of the affinity string. - */ - while( n>0 && zAff[0]==SQLITE_AFF_BLOB ){ - n--; - base++; - zAff++; - } - while( n>1 && zAff[n-1]==SQLITE_AFF_BLOB ){ - n--; - } - - /* Code the OP_Affinity opcode if there is anything left to do. */ - if( n>0 ){ - sqlite3VdbeAddOp2(v, OP_Affinity, base, n); - sqlite3VdbeChangeP4(v, -1, zAff, n); - sqlite3ExprCacheAffinityChange(pParse, base, n); - } -} - - -/* -** Generate code for a single equality term of the WHERE clause. An equality -** term can be either X=expr or X IN (...). pTerm is the term to be -** coded. -** -** The current value for the constraint is left in register iReg. -** -** For a constraint of the form X=expr, the expression is evaluated and its -** result is left on the stack. For constraints of the form X IN (...) -** this routine sets up a loop that will iterate over all values of X. -*/ -static int codeEqualityTerm( - Parse *pParse, /* The parsing context */ - WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ - WhereLevel *pLevel, /* The level of the FROM clause we are working on */ - int iEq, /* Index of the equality term within this level */ - int bRev, /* True for reverse-order IN operations */ - int iTarget /* Attempt to leave results in this register */ -){ - Expr *pX = pTerm->pExpr; - Vdbe *v = pParse->pVdbe; - int iReg; /* Register holding results */ - - assert( iTarget>0 ); - if( pX->op==TK_EQ || pX->op==TK_IS ){ - iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); - }else if( pX->op==TK_ISNULL ){ - iReg = iTarget; - sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); -#ifndef SQLITE_OMIT_SUBQUERY - }else{ - int eType; - int iTab; - struct InLoop *pIn; - WhereLoop *pLoop = pLevel->pWLoop; - - if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 - && pLoop->u.btree.pIndex!=0 - && pLoop->u.btree.pIndex->aSortOrder[iEq] - ){ - testcase( iEq==0 ); - testcase( bRev ); - bRev = !bRev; - } - assert( pX->op==TK_IN ); - iReg = iTarget; - eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0); - if( eType==IN_INDEX_INDEX_DESC ){ - testcase( bRev ); - bRev = !bRev; - } - iTab = pX->iTable; - sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); - VdbeCoverageIf(v, bRev); - VdbeCoverageIf(v, !bRev); - assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); - pLoop->wsFlags |= WHERE_IN_ABLE; - if( pLevel->u.in.nIn==0 ){ - pLevel->addrNxt = sqlite3VdbeMakeLabel(v); - } - pLevel->u.in.nIn++; - pLevel->u.in.aInLoop = - sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop, - sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn); - pIn = pLevel->u.in.aInLoop; - if( pIn ){ - pIn += pLevel->u.in.nIn - 1; - pIn->iCur = iTab; - if( eType==IN_INDEX_ROWID ){ - pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg); - }else{ - pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg); - } - pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen; - sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v); - }else{ - pLevel->u.in.nIn = 0; - } -#endif - } - disableTerm(pLevel, pTerm); - return iReg; -} - -/* -** Generate code that will evaluate all == and IN constraints for an -** index scan. -** -** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c). -** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10 -** The index has as many as three equality constraints, but in this -** example, the third "c" value is an inequality. So only two -** constraints are coded. This routine will generate code to evaluate -** a==5 and b IN (1,2,3). The current values for a and b will be stored -** in consecutive registers and the index of the first register is returned. -** -** In the example above nEq==2. But this subroutine works for any value -** of nEq including 0. If nEq==0, this routine is nearly a no-op. -** The only thing it does is allocate the pLevel->iMem memory cell and -** compute the affinity string. -** -** The nExtraReg parameter is 0 or 1. It is 0 if all WHERE clause constraints -** are == or IN and are covered by the nEq. nExtraReg is 1 if there is -** an inequality constraint (such as the "c>=5 AND c<10" in the example) that -** occurs after the nEq quality constraints. -** -** This routine allocates a range of nEq+nExtraReg memory cells and returns -** the index of the first memory cell in that range. The code that -** calls this routine will use that memory range to store keys for -** start and termination conditions of the loop. -** key value of the loop. If one or more IN operators appear, then -** this routine allocates an additional nEq memory cells for internal -** use. -** -** Before returning, *pzAff is set to point to a buffer containing a -** copy of the column affinity string of the index allocated using -** sqlite3DbMalloc(). Except, entries in the copy of the string associated -** with equality constraints that use BLOB or NONE affinity are set to -** SQLITE_AFF_BLOB. This is to deal with SQL such as the following: -** -** CREATE TABLE t1(a TEXT PRIMARY KEY, b); -** SELECT ... FROM t1 AS t2, t1 WHERE t1.a = t2.b; -** -** In the example above, the index on t1(a) has TEXT affinity. But since -** the right hand side of the equality constraint (t2.b) has BLOB/NONE affinity, -** no conversion should be attempted before using a t2.b value as part of -** a key to search the index. Hence the first byte in the returned affinity -** string in this example would be set to SQLITE_AFF_BLOB. -*/ -static int codeAllEqualityTerms( - Parse *pParse, /* Parsing context */ - WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ - int bRev, /* Reverse the order of IN operators */ - int nExtraReg, /* Number of extra registers to allocate */ - char **pzAff /* OUT: Set to point to affinity string */ -){ - u16 nEq; /* The number of == or IN constraints to code */ - u16 nSkip; /* Number of left-most columns to skip */ - Vdbe *v = pParse->pVdbe; /* The vm under construction */ - Index *pIdx; /* The index being used for this loop */ - WhereTerm *pTerm; /* A single constraint term */ - WhereLoop *pLoop; /* The WhereLoop object */ - int j; /* Loop counter */ - int regBase; /* Base register */ - int nReg; /* Number of registers to allocate */ - char *zAff; /* Affinity string to return */ - - /* This module is only called on query plans that use an index. */ - pLoop = pLevel->pWLoop; - assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); - nEq = pLoop->u.btree.nEq; - nSkip = pLoop->nSkip; - pIdx = pLoop->u.btree.pIndex; - assert( pIdx!=0 ); - - /* Figure out how many memory cells we will need then allocate them. - */ - regBase = pParse->nMem + 1; - nReg = pLoop->u.btree.nEq + nExtraReg; - pParse->nMem += nReg; - - zAff = sqlite3DbStrDup(pParse->db, sqlite3IndexAffinityStr(v, pIdx)); - if( !zAff ){ - pParse->db->mallocFailed = 1; - } - - if( nSkip ){ - int iIdxCur = pLevel->iIdxCur; - sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur); - VdbeCoverageIf(v, bRev==0); - VdbeCoverageIf(v, bRev!=0); - VdbeComment((v, "begin skip-scan on %s", pIdx->zName)); - j = sqlite3VdbeAddOp0(v, OP_Goto); - pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT), - iIdxCur, 0, regBase, nSkip); - VdbeCoverageIf(v, bRev==0); - VdbeCoverageIf(v, bRev!=0); - sqlite3VdbeJumpHere(v, j); - for(j=0; jaiColumn[j]>=0 ); - VdbeComment((v, "%s", pIdx->pTable->aCol[pIdx->aiColumn[j]].zName)); - } - } - - /* Evaluate the equality constraints - */ - assert( zAff==0 || (int)strlen(zAff)>=nEq ); - for(j=nSkip; jaLTerm[j]; - assert( pTerm!=0 ); - /* The following testcase is true for indices with redundant columns. - ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ - testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); - testcase( pTerm->wtFlags & TERM_VIRTUAL ); - r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j); - if( r1!=regBase+j ){ - if( nReg==1 ){ - sqlite3ReleaseTempReg(pParse, regBase); - regBase = r1; - }else{ - sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); - } - } - testcase( pTerm->eOperator & WO_ISNULL ); - testcase( pTerm->eOperator & WO_IN ); - if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ - Expr *pRight = pTerm->pExpr->pRight; - if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){ - sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); - VdbeCoverage(v); - } - if( zAff ){ - if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){ - zAff[j] = SQLITE_AFF_BLOB; - } - if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){ - zAff[j] = SQLITE_AFF_BLOB; - } - } - } - } - *pzAff = zAff; - return regBase; -} - -#ifndef SQLITE_OMIT_EXPLAIN -/* -** This routine is a helper for explainIndexRange() below -** -** pStr holds the text of an expression that we are building up one term -** at a time. This routine adds a new term to the end of the expression. -** Terms are separated by AND so add the "AND" text for second and subsequent -** terms only. -*/ -static void explainAppendTerm( - StrAccum *pStr, /* The text expression being built */ - int iTerm, /* Index of this term. First is zero */ - const char *zColumn, /* Name of the column */ - const char *zOp /* Name of the operator */ -){ - if( iTerm ) sqlite3StrAccumAppend(pStr, " AND ", 5); - sqlite3StrAccumAppendAll(pStr, zColumn); - sqlite3StrAccumAppend(pStr, zOp, 1); - sqlite3StrAccumAppend(pStr, "?", 1); -} - -/* -** Argument pLevel describes a strategy for scanning table pTab. This -** 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: -** -** SELECT * FROM t1 WHERE a=1 AND b>2; -** -** is run and there is an index on (a, b), then this function returns a -** string similar to: -** -** "a=? AND b>?" -*/ -static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ - Index *pIndex = pLoop->u.btree.pIndex; - u16 nEq = pLoop->u.btree.nEq; - u16 nSkip = pLoop->nSkip; - int i, j; - Column *aCol = pTab->aCol; - i16 *aiColumn = pIndex->aiColumn; - - if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; - sqlite3StrAccumAppend(pStr, " (", 2); - for(i=0; i=nSkip ){ - explainAppendTerm(pStr, i, z, "="); - }else{ - 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(pStr, i++, z, ">"); - } - if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ - char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; - explainAppendTerm(pStr, i, z, "<"); - } - sqlite3StrAccumAppend(pStr, ")", 1); -} - -/* -** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN -** 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 int explainOneScan( - Parse *pParse, /* Parse context */ - SrcList *pTabList, /* Table list this loop refers to */ - WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ - int iLevel, /* Value for "level" column of output */ - int iFrom, /* Value for "from" column of output */ - u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ -){ - 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 */ - 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 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)); - - sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); - sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); - if( pItem->pSelect ){ - sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); - }else{ - sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); - } - - if( pItem->zAlias ){ - sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias); - } - 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) ){ - if( isSearch ){ - zFmt = "PRIMARY KEY"; - } - }else if( flags & WHERE_PARTIALIDX ){ - zFmt = "AUTOMATIC PARTIAL COVERING INDEX"; - }else if( flags & WHERE_AUTO_INDEX ){ - zFmt = "AUTOMATIC COVERING INDEX"; - }else if( flags & WHERE_IDX_ONLY ){ - zFmt = "COVERING INDEX %s"; - }else{ - zFmt = "INDEX %s"; - } - if( zFmt ){ - sqlite3StrAccumAppend(&str, " USING ", 7); - sqlite3XPrintf(&str, 0, zFmt, pIdx->zName); - explainIndexRange(&str, pLoop, pItem->pTab); - } - }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ - const char *zRange; - if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ - zRange = "(rowid=?)"; - }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ - zRange = "(rowid>? AND rowid?)"; - }else{ - assert( flags&WHERE_TOP_LIMIT); - zRange = "(rowidu.vtab.idxNum, pLoop->u.vtab.idxStr); - } -#endif -#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) 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 - -/* -** 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 -** implementation described by pWInfo. -*/ -static Bitmask codeOneLoopStart( - WhereInfo *pWInfo, /* Complete information about the WHERE clause */ - int iLevel, /* Which level of pWInfo->a[] should be coded */ - Bitmask notReady /* Which tables are currently available */ -){ - int j, k; /* Loop counters */ - int iCur; /* The VDBE cursor for the table */ - int addrNxt; /* Where to jump to continue with the next IN case */ - int omitTable; /* True if we use the index only */ - int bRev; /* True if we need to scan in reverse order */ - WhereLevel *pLevel; /* The where level to be coded */ - WhereLoop *pLoop; /* The WhereLoop object being coded */ - WhereClause *pWC; /* Decomposition of the entire WHERE clause */ - WhereTerm *pTerm; /* A WHERE clause term */ - Parse *pParse; /* Parsing context */ - sqlite3 *db; /* Database connection */ - Vdbe *v; /* The prepared stmt under constructions */ - struct SrcList_item *pTabItem; /* FROM clause term being coded */ - int addrBrk; /* Jump here to break out of the loop */ - int addrCont; /* Jump here to continue with next cycle */ - int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ - int iReleaseReg = 0; /* Temp register to free before returning */ - - pParse = pWInfo->pParse; - v = pParse->pVdbe; - pWC = &pWInfo->sWC; - db = pParse->db; - pLevel = &pWInfo->a[iLevel]; - pLoop = pLevel->pWLoop; - pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; - iCur = pTabItem->iCursor; - pLevel->notReady = notReady & ~getMask(&pWInfo->sMaskSet, iCur); - bRev = (pWInfo->revMask>>iLevel)&1; - omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 - && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0; - VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); - - /* Create labels for the "break" and "continue" instructions - ** for the current loop. Jump to addrBrk to break out of a loop. - ** Jump to cont to go immediately to the next iteration of the - ** loop. - ** - ** When there is an IN operator, we also have a "addrNxt" label that - ** means to continue with the next IN value combination. When - ** there are no IN operators in the constraints, the "addrNxt" label - ** is the same as "addrBrk". - */ - addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(v); - addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(v); - - /* If this is the right table of a LEFT OUTER JOIN, allocate and - ** initialize a memory cell that records if this table matches any - ** row of the left table of the join. - */ - if( pLevel->iFrom>0 && (pTabItem[0].jointype & JT_LEFT)!=0 ){ - pLevel->iLeftJoin = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin); - VdbeComment((v, "init LEFT JOIN no-match flag")); - } - - /* Special case of a FROM clause subquery implemented as a co-routine */ - if( pTabItem->viaCoroutine ){ - int regYield = pTabItem->regReturn; - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); - pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); - VdbeCoverage(v); - VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); - pLevel->op = OP_Goto; - }else - -#ifndef SQLITE_OMIT_VIRTUALTABLE - if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ - /* Case 1: The table is a virtual-table. Use the VFilter and VNext - ** to access the data. - */ - int iReg; /* P3 Value for OP_VFilter */ - int addrNotFound; - int nConstraint = pLoop->nLTerm; - - sqlite3ExprCachePush(pParse); - iReg = sqlite3GetTempRange(pParse, nConstraint+2); - addrNotFound = pLevel->addrBrk; - for(j=0; jaLTerm[j]; - if( pTerm==0 ) continue; - if( pTerm->eOperator & WO_IN ){ - codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); - addrNotFound = pLevel->addrNxt; - }else{ - sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); - } - } - sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); - sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); - sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, - pLoop->u.vtab.idxStr, - pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC); - VdbeCoverage(v); - pLoop->u.vtab.needFree = 0; - for(j=0; ju.vtab.omitMask>>j)&1 ){ - disableTerm(pLevel, pLoop->aLTerm[j]); - } - } - pLevel->op = OP_VNext; - pLevel->p1 = iCur; - pLevel->p2 = sqlite3VdbeCurrentAddr(v); - sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); - sqlite3ExprCachePop(pParse); - }else -#endif /* SQLITE_OMIT_VIRTUALTABLE */ - - if( (pLoop->wsFlags & WHERE_IPK)!=0 - && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0 - ){ - /* Case 2: We can directly reference a single row using an - ** equality comparison against the ROWID field. Or - ** we reference multiple rows using a "rowid IN (...)" - ** construct. - */ - assert( pLoop->u.btree.nEq==1 ); - pTerm = pLoop->aLTerm[0]; - assert( pTerm!=0 ); - assert( pTerm->pExpr!=0 ); - assert( omitTable==0 ); - testcase( pTerm->wtFlags & TERM_VIRTUAL ); - iReleaseReg = ++pParse->nMem; - iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); - if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); - addrNxt = pLevel->addrNxt; - sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v); - sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); - VdbeCoverage(v); - sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); - sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); - VdbeComment((v, "pk")); - pLevel->op = OP_Noop; - }else if( (pLoop->wsFlags & WHERE_IPK)!=0 - && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 - ){ - /* Case 3: We have an inequality comparison against the ROWID field. - */ - int testOp = OP_Noop; - int start; - int memEndValue = 0; - WhereTerm *pStart, *pEnd; - - assert( omitTable==0 ); - j = 0; - pStart = pEnd = 0; - if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++]; - if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; - assert( pStart!=0 || pEnd!=0 ); - if( bRev ){ - pTerm = pStart; - pStart = pEnd; - pEnd = pTerm; - } - if( pStart ){ - Expr *pX; /* The expression that defines the start bound */ - int r1, rTemp; /* Registers for holding the start boundary */ - - /* The following constant maps TK_xx codes into corresponding - ** seek opcodes. It depends on a particular ordering of TK_xx - */ - const u8 aMoveOp[] = { - /* TK_GT */ OP_SeekGT, - /* TK_LE */ OP_SeekLE, - /* TK_LT */ OP_SeekLT, - /* TK_GE */ OP_SeekGE - }; - assert( TK_LE==TK_GT+1 ); /* Make sure the ordering.. */ - assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */ - assert( TK_GE==TK_GT+3 ); /* ... is correcct. */ - - assert( (pStart->wtFlags & TERM_VNULL)==0 ); - testcase( pStart->wtFlags & TERM_VIRTUAL ); - pX = pStart->pExpr; - assert( pX!=0 ); - testcase( pStart->leftCursor!=iCur ); /* transitive constraints */ - r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); - sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1); - VdbeComment((v, "pk")); - VdbeCoverageIf(v, pX->op==TK_GT); - VdbeCoverageIf(v, pX->op==TK_LE); - VdbeCoverageIf(v, pX->op==TK_LT); - VdbeCoverageIf(v, pX->op==TK_GE); - sqlite3ExprCacheAffinityChange(pParse, r1, 1); - sqlite3ReleaseTempReg(pParse, rTemp); - disableTerm(pLevel, pStart); - }else{ - sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk); - VdbeCoverageIf(v, bRev==0); - VdbeCoverageIf(v, bRev!=0); - } - if( pEnd ){ - Expr *pX; - pX = pEnd->pExpr; - assert( pX!=0 ); - assert( (pEnd->wtFlags & TERM_VNULL)==0 ); - testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */ - testcase( pEnd->wtFlags & TERM_VIRTUAL ); - memEndValue = ++pParse->nMem; - sqlite3ExprCode(pParse, pX->pRight, memEndValue); - if( pX->op==TK_LT || pX->op==TK_GT ){ - testOp = bRev ? OP_Le : OP_Ge; - }else{ - testOp = bRev ? OP_Lt : OP_Gt; - } - disableTerm(pLevel, pEnd); - } - start = sqlite3VdbeCurrentAddr(v); - pLevel->op = bRev ? OP_Prev : OP_Next; - pLevel->p1 = iCur; - pLevel->p2 = start; - assert( pLevel->p5==0 ); - if( testOp!=OP_Noop ){ - iRowidReg = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); - sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); - sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); - VdbeCoverageIf(v, testOp==OP_Le); - VdbeCoverageIf(v, testOp==OP_Lt); - VdbeCoverageIf(v, testOp==OP_Ge); - VdbeCoverageIf(v, testOp==OP_Gt); - sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); - } - }else if( pLoop->wsFlags & WHERE_INDEXED ){ - /* Case 4: A scan using an index. - ** - ** The WHERE clause may contain zero or more equality - ** terms ("==" or "IN" operators) that refer to the N - ** left-most columns of the index. It may also contain - ** inequality constraints (>, <, >= or <=) on the indexed - ** column that immediately follows the N equalities. Only - ** the right-most column can be an inequality - the rest must - ** use the "==" and "IN" operators. For example, if the - ** index is on (x,y,z), then the following clauses are all - ** optimized: - ** - ** x=5 - ** x=5 AND y=10 - ** x=5 AND y<10 - ** x=5 AND y>5 AND y<10 - ** x=5 AND y=5 AND z<=10 - ** - ** The z<10 term of the following cannot be used, only - ** the x=5 term: - ** - ** x=5 AND z<10 - ** - ** N may be zero if there are inequality constraints. - ** If there are no inequality constraints, then N is at - ** least one. - ** - ** This case is also used when there are no WHERE clause - ** constraints but an index is selected anyway, in order - ** to force the output order to conform to an ORDER BY. - */ - static const u8 aStartOp[] = { - 0, - 0, - OP_Rewind, /* 2: (!start_constraints && startEq && !bRev) */ - OP_Last, /* 3: (!start_constraints && startEq && bRev) */ - OP_SeekGT, /* 4: (start_constraints && !startEq && !bRev) */ - OP_SeekLT, /* 5: (start_constraints && !startEq && bRev) */ - OP_SeekGE, /* 6: (start_constraints && startEq && !bRev) */ - OP_SeekLE /* 7: (start_constraints && startEq && bRev) */ - }; - static const u8 aEndOp[] = { - OP_IdxGE, /* 0: (end_constraints && !bRev && !endEq) */ - OP_IdxGT, /* 1: (end_constraints && !bRev && endEq) */ - OP_IdxLE, /* 2: (end_constraints && bRev && !endEq) */ - OP_IdxLT, /* 3: (end_constraints && bRev && endEq) */ - }; - u16 nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */ - int regBase; /* Base register holding constraint values */ - WhereTerm *pRangeStart = 0; /* Inequality constraint at range start */ - WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */ - int startEq; /* True if range start uses ==, >= or <= */ - int endEq; /* True if range end uses ==, >= or <= */ - int start_constraints; /* Start of range is constrained */ - int nConstraint; /* Number of constraint terms */ - Index *pIdx; /* The index we will be using */ - int iIdxCur; /* The VDBE cursor for the index */ - int nExtraReg = 0; /* Number of extra registers needed */ - int op; /* Instruction opcode */ - char *zStartAff; /* Affinity for start of range constraint */ - char cEndAff = 0; /* Affinity for end of range constraint */ - u8 bSeekPastNull = 0; /* True to seek past initial nulls */ - u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ - - pIdx = pLoop->u.btree.pIndex; - iIdxCur = pLevel->iIdxCur; - 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) ..." - ** query, then the caller will only allow the loop to run for - ** a single iteration. This means that the first row returned - ** should not have a NULL value stored in 'x'. If column 'x' is - ** 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->nOBSat>0 - && (pIdx->nKeyCol>nEq) - ){ - assert( pLoop->nSkip==0 ); - bSeekPastNull = 1; - nExtraReg = 1; - } - - /* Find any inequality constraint terms for the start and end - ** of the range. - */ - j = nEq; - 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 - ){ - bSeekPastNull = 1; - } - } - assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); - - /* Generate code to evaluate all constraint terms using == or IN - ** and store the values of those terms in an array of registers - ** starting at regBase. - */ - regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); - assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq ); - if( zStartAff ) cEndAff = zStartAff[nEq]; - addrNxt = pLevel->addrNxt; - - /* If we are doing a reverse order scan on an ascending index, or - ** a forward order scan on a descending index, interchange the - ** start and end terms (pRangeStart and pRangeEnd). - */ - if( (nEqnKeyCol && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) - || (bRev && pIdx->nKeyCol==nEq) - ){ - SWAP(WhereTerm *, pRangeEnd, pRangeStart); - SWAP(u8, bSeekPastNull, bStopAtNull); - } - - testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); - testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 ); - testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 ); - testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 ); - startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE); - endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE); - start_constraints = pRangeStart || nEq>0; - - /* Seek the index cursor to the start of the range. */ - nConstraint = nEq; - if( pRangeStart ){ - Expr *pRight = pRangeStart->pExpr->pRight; - sqlite3ExprCode(pParse, pRight, regBase+nEq); - whereLikeOptimizationStringFixup(v, pLevel, pRangeStart); - if( (pRangeStart->wtFlags & TERM_VNULL)==0 - && sqlite3ExprCanBeNull(pRight) - ){ - sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); - VdbeCoverage(v); - } - if( zStartAff ){ - if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_BLOB){ - /* Since the comparison is to be performed with no conversions - ** applied to the operands, set the affinity to apply to pRight to - ** SQLITE_AFF_BLOB. */ - zStartAff[nEq] = SQLITE_AFF_BLOB; - } - if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){ - zStartAff[nEq] = SQLITE_AFF_BLOB; - } - } - nConstraint++; - testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); - }else if( bSeekPastNull ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); - nConstraint++; - startEq = 0; - start_constraints = 1; - } - codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); - op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; - assert( op!=0 ); - sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); - VdbeCoverage(v); - VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); - VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); - VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT ); - VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); - VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); - VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); - - /* Load the value for the inequality constraint at the end of the - ** range (if any). - */ - nConstraint = nEq; - if( pRangeEnd ){ - 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) - ){ - sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); - VdbeCoverage(v); - } - if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_BLOB - && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff) - ){ - codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff); - } - nConstraint++; - testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); - }else if( bStopAtNull ){ - sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); - endEq = 0; - nConstraint++; - } - sqlite3DbFree(db, zStartAff); - - /* Top of the loop body */ - pLevel->p2 = sqlite3VdbeCurrentAddr(v); - - /* Check if the index cursor is past the end of the range. */ - if( nConstraint ){ - op = aEndOp[bRev*2 + endEq]; - sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); - testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); - testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); - testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); - testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); - } - - /* Seek the table cursor, if required */ - disableTerm(pLevel, pRangeStart); - disableTerm(pLevel, pRangeEnd); - if( omitTable ){ - /* pIdx is a covering index. No need to access the main table. */ - }else if( HasRowid(pIdx->pTable) ){ - iRowidReg = ++pParse->nMem; - sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); - sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); - sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */ - }else if( iCur!=iIdxCur ){ - Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); - iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); - for(j=0; jnKeyCol; j++){ - k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); - sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j); - } - sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont, - iRowidReg, pPk->nKeyCol); VdbeCoverage(v); - } - - /* Record the instruction used to terminate the loop. Disable - ** WHERE clause terms made redundant by the index range scan. - */ - if( pLoop->wsFlags & WHERE_ONEROW ){ - pLevel->op = OP_Noop; - }else if( bRev ){ - pLevel->op = OP_Prev; - }else{ - pLevel->op = OP_Next; - } - pLevel->p1 = iIdxCur; - pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0; - if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){ - pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; - }else{ - assert( pLevel->p5==0 ); - } - }else - -#ifndef SQLITE_OMIT_OR_OPTIMIZATION - if( pLoop->wsFlags & WHERE_MULTI_OR ){ - /* Case 5: Two or more separately indexed terms connected by OR - ** - ** Example: - ** - ** CREATE TABLE t1(a,b,c,d); - ** CREATE INDEX i1 ON t1(a); - ** CREATE INDEX i2 ON t1(b); - ** CREATE INDEX i3 ON t1(c); - ** - ** SELECT * FROM t1 WHERE a=5 OR b=7 OR (c=11 AND d=13) - ** - ** In the example, there are three indexed terms connected by OR. - ** The top of the loop looks like this: - ** - ** Null 1 # Zero the rowset in reg 1 - ** - ** Then, for each indexed term, the following. The arguments to - ** RowSetTest are such that the rowid of the current row is inserted - ** into the RowSet. If it is already present, control skips the - ** Gosub opcode and jumps straight to the code generated by WhereEnd(). - ** - ** sqlite3WhereBegin() - ** RowSetTest # Insert rowid into rowset - ** Gosub 2 A - ** sqlite3WhereEnd() - ** - ** Following the above, code to terminate the loop. Label A, the target - ** of the Gosub above, jumps to the instruction right after the Goto. - ** - ** Null 1 # Zero the rowset in reg 1 - ** Goto B # The loop is finished. - ** - ** A: # Return data, whatever. - ** - ** Return 2 # Jump back to the Gosub - ** - ** B: - ** - ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then - ** use an ephemeral 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 */ - Index *pCov = 0; /* Potential covering index (or NULL) */ - int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */ - - int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ - int regRowset = 0; /* Register for RowSet object */ - int regRowid = 0; /* Register holding rowid */ - int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */ - 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 ); - assert( pTerm->eOperator & WO_OR ); - assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); - pOrWc = &pTerm->u.pOrInfo->wc; - pLevel->op = OP_Return; - pLevel->p1 = regReturn; - - /* Set up a new SrcList in pOrTab containing the table being scanned - ** by this loop in the a[0] slot and all notReady tables in a[1..] slots. - ** This becomes the SrcList in the recursive call to sqlite3WhereBegin(). - */ - if( pWInfo->nLevel>1 ){ - int nNotReady; /* The number of notReady tables */ - struct SrcList_item *origSrc; /* Original list of tables */ - nNotReady = pWInfo->nLevel - iLevel - 1; - pOrTab = sqlite3StackAllocRaw(db, - sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); - if( pOrTab==0 ) return notReady; - pOrTab->nAlloc = (u8)(nNotReady + 1); - pOrTab->nSrc = pOrTab->nAlloc; - memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem)); - origSrc = pWInfo->pTabList->a; - for(k=1; k<=nNotReady; k++){ - memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k])); - } - }else{ - pOrTab = pWInfo->pTabList; - } - - /* Initialize the rowset register to contain NULL. An SQL NULL is - ** 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 - ** immediately following the OP_Return at the bottom of the loop. This - ** is required in a few obscure LEFT JOIN cases where control jumps - ** over the top of the loop into the body of it. In this case the - ** correct response for the end-of-loop code (the OP_Return) is to - ** fall through to the next instruction, just as an OP_Next does if - ** called on an uninitialized cursor. - */ - if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ - 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; - } - iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); - - /* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y - ** Then for every term xN, evaluate as the subexpression: xN AND z - ** That way, terms in y that are factored into the disjunction will - ** be picked up by the recursive calls to sqlite3WhereBegin() below. - ** - ** Actually, each subexpression is converted to "xN AND w" where w is - ** the "interesting" terms of z - terms that did not originate in the - ** ON or USING clause of a LEFT JOIN, and terms that are usable as - ** indices. - ** - ** This optimization also only applies if the (x1 OR x2 OR ...) term - ** is not contained in the ON clause of a LEFT JOIN. - ** See ticket http://www.sqlite.org/src/info/f2369304e4 - */ - if( pWC->nTerm>1 ){ - int iTerm; - for(iTerm=0; iTermnTerm; iTerm++){ - Expr *pExpr = pWC->a[iTerm].pExpr; - if( &pWC->a[iTerm] == pTerm ) continue; - if( ExprHasProperty(pExpr, EP_FromJoin) ) 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); - } - if( pAndExpr ){ - pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0); - } - } - - /* 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_FORCE_TABLE - | 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 ){ - 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. */ - 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; - 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 - ** row will be skipped in subsequent sub-WHERE clauses. - */ - if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ - int r; - 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 - ** need to be tested later. - */ - if( pSubWInfo->untestedTerms ) untestedTerms = 1; - - /* If all of the OR-connected terms are optimized using the same - ** index, and the index is opened using the same cursor number - ** by each call to sqlite3WhereBegin() made by this loop, it may - ** be possible to use that index as a covering index. - ** - ** If the call to sqlite3WhereBegin() above resulted in a scan that - ** uses an index, and this is either the first OR-connected term - ** processed or the index is the same as that used by all previous - ** terms, set pCov to the candidate covering index. Otherwise, set - ** pCov to NULL to indicate that no candidate covering index will - ** be available. - */ - pSubLoop = pSubWInfo->a[0].pWLoop; - 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; - } - - /* Finish the loop through table entries that match term pOrTerm. */ - sqlite3WhereEnd(pSubWInfo); - } - } - } - pLevel->u.pCovidx = pCov; - if( pCov ) pLevel->iIdxCur = iCovCur; - if( pAndExpr ){ - pAndExpr->pLeft = 0; - sqlite3ExprDelete(db, pAndExpr); - } - sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v)); - sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk); - sqlite3VdbeResolveLabel(v, iLoopBody); - - if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab); - if( !untestedTerms ) disableTerm(pLevel, pTerm); - }else -#endif /* SQLITE_OMIT_OR_OPTIMIZATION */ - - { - /* Case 6: There is no usable index. We must do a complete - ** scan of the entire table. - */ - static const u8 aStep[] = { OP_Next, OP_Prev }; - static const u8 aStart[] = { OP_Rewind, OP_Last }; - assert( bRev==0 || bRev==1 ); - if( pTabItem->isRecursive ){ - /* Tables marked isRecursive have only a single row that is stored in - ** a pseudo-cursor. No need to Rewind or Next such cursors. */ - pLevel->op = OP_Noop; - }else{ - pLevel->op = aStep[bRev]; - pLevel->p1 = iCur; - pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); - VdbeCoverageIf(v, bRev==0); - VdbeCoverageIf(v, bRev!=0); - pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; - } - } - -#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. - */ - 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; - if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ - testcase( pWInfo->untestedTerms==0 - && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ); - pWInfo->untestedTerms = 1; - continue; - } - pE = pTerm->pExpr; - assert( pE!=0 ); - 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; - } - - /* Insert code to test for implied constraints based on transitivity - ** of the "==" operator. - ** - ** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123" - ** and we are coding the t1 loop and the t2 loop has not yet coded, - ** then we cannot use the "t1.a=t2.b" constraint, but we can code - ** the implied "t1.a=123" constraint. - */ - for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ - Expr *pE, *pEAlt; - WhereTerm *pAlt; - if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue; - if( (pTerm->eOperator & WO_EQUIV)==0 ) continue; - if( pTerm->leftCursor!=iCur ) continue; - if( pLevel->iLeftJoin ) continue; - pE = pTerm->pExpr; - assert( !ExprHasProperty(pE, EP_FromJoin) ); - assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); - pAlt = findTerm(pWC, iCur, pTerm->u.leftColumn, notReady, - WO_EQ|WO_IN|WO_IS, 0); - if( pAlt==0 ) continue; - if( pAlt->wtFlags & (TERM_CODED) ) continue; - testcase( pAlt->eOperator & WO_EQ ); - testcase( pAlt->eOperator & WO_IS ); - testcase( pAlt->eOperator & WO_IN ); - VdbeModuleComment((v, "begin transitive constraint")); - pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt)); - if( pEAlt ){ - *pEAlt = *pAlt->pExpr; - pEAlt->pLeft = pE->pLeft; - sqlite3ExprIfFalse(pParse, pEAlt, addrCont, SQLITE_JUMPIFNULL); - sqlite3StackFree(db, pEAlt); - } - } - - /* For a LEFT OUTER JOIN, generate code that will record the fact that - ** at least one row of the right table has matched the left table. - */ - if( pLevel->iLeftJoin ){ - pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); - VdbeComment((v, "record LEFT JOIN hit")); - sqlite3ExprCacheClear(pParse); - for(pTerm=pWC->a, j=0; jnTerm; j++, pTerm++){ - testcase( pTerm->wtFlags & TERM_VIRTUAL ); - testcase( pTerm->wtFlags & TERM_CODED ); - if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; - if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ - assert( pWInfo->untestedTerms ); - continue; - } - assert( pTerm->pExpr ); - sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); - pTerm->wtFlags |= TERM_CODED; - } - } - - return pLevel->notReady; -} #ifdef WHERETRACE_ENABLED /* @@ -5670,7 +4198,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ whereLoopInit(pNew); for(iTab=0, pItem=pTabList->a; iTabiTab = iTab; - pNew->maskSelf = getMask(&pWInfo->sMaskSet, pItem->iCursor); + pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); if( ((pItem->jointype|priorJoinType) & (JT_LEFT|JT_CROSS))!=0 ){ mExtra = mPrior; } @@ -5791,7 +4319,7 @@ static i8 wherePathSatisfiesOrderBy( pOBExpr = sqlite3ExprSkipCollate(pOrderBy->a[i].pExpr); if( pOBExpr->op!=TK_COLUMN ) continue; if( pOBExpr->iTable!=iCur ) continue; - pTerm = findTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, + pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, ~ready, WO_EQ|WO_ISNULL|WO_IS, 0); if( pTerm==0 ) continue; if( (pTerm->eOperator&(WO_EQ|WO_IS))!=0 && pOBExpr->iColumn>=0 ){ @@ -6407,7 +4935,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ pLoop = pBuilder->pNew; pLoop->wsFlags = 0; pLoop->nSkip = 0; - pTerm = findTerm(pWC, iCur, -1, 0, WO_EQ|WO_IS, 0); + pTerm = sqlite3WhereFindTerm(pWC, iCur, -1, 0, WO_EQ|WO_IS, 0); if( pTerm ){ testcase( pTerm->eOperator & WO_IS ); pLoop->wsFlags = WHERE_COLUMN_EQ|WHERE_IPK|WHERE_ONEROW; @@ -6426,7 +4954,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ ) continue; opMask = pIdx->uniqNotNull ? (WO_EQ|WO_IS) : WO_EQ; for(j=0; jnKeyCol; j++){ - pTerm = findTerm(pWC, iCur, pIdx->aiColumn[j], 0, opMask, pIdx); + pTerm = sqlite3WhereFindTerm(pWC, iCur, pIdx->aiColumn[j], 0, opMask, pIdx); if( pTerm==0 ) break; testcase( pTerm->eOperator & WO_IS ); pLoop->aLTerm[j] = pTerm; @@ -6447,7 +4975,7 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ if( pLoop->wsFlags ){ pLoop->nOut = (LogEst)1; pWInfo->a[0].pWLoop = pLoop; - pLoop->maskSelf = getMask(&pWInfo->sMaskSet, iCur); + pLoop->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); pWInfo->a[0].iTabCur = iCur; pWInfo->nRowOut = 1; if( pWInfo->pOrderBy ) pWInfo->nOBSat = pWInfo->pOrderBy->nExpr; @@ -6687,7 +5215,7 @@ WhereInfo *sqlite3WhereBegin( { Bitmask toTheLeft = 0; for(ii=0; iinSrc; ii++){ - Bitmask m = getMask(pMaskSet, pTabList->a[ii].iCursor); + Bitmask m = sqlite3WhereGetMask(pMaskSet, pTabList->a[ii].iCursor); assert( (m-1)==toTheLeft ); toTheLeft |= m; } @@ -6936,14 +5464,14 @@ WhereInfo *sqlite3WhereBegin( if( db->mallocFailed ) goto whereBeginError; } #endif - addrExplain = explainOneScan( + addrExplain = sqlite3WhereExplainOneScan( pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); - notReady = codeOneLoopStart(pWInfo, ii, notReady); + notReady = sqlite3WhereCodeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){ - addScanStatus(v, pTabList, pLevel, addrExplain); + sqlite3WhereAddScanStatus(v, pTabList, pLevel, addrExplain); } } diff --git a/src/whereInt.h b/src/whereInt.h index 3a5a48e840..075deed4a2 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -19,7 +19,7 @@ ** Trace output macros */ #if defined(SQLITE_TEST) || defined(SQLITE_DEBUG) -/***/ int sqlite3WhereTrace = 0; +/***/ int sqlite3WhereTrace; #endif #if defined(SQLITE_DEBUG) \ && (defined(SQLITE_TEST) || defined(SQLITE_ENABLE_WHERETRACE)) @@ -161,10 +161,6 @@ struct WhereOrSet { WhereOrCost a[N_OR_COST]; /* Set of best costs */ }; - -/* Forward declaration of methods */ -static int whereLoopResize(sqlite3*, WhereLoop*, int); - /* ** Each instance of this object holds a sequence of WhereLoop objects ** that implement some or all of a query plan. @@ -423,6 +419,52 @@ struct WhereInfo { WhereLevel a[1]; /* Information about each nest loop in WHERE */ }; +/* +** Private interfaces - callable only by other where.c routines. +*/ +Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); +WhereTerm *sqlite3WhereFindTerm( + WhereClause *pWC, /* The WHERE clause to be searched */ + int iCur, /* Cursor number of LHS */ + int iColumn, /* Column number of LHS */ + Bitmask notReady, /* RHS must not overlap with this mask */ + u32 op, /* Mask of WO_xx values describing operator */ + Index *pIdx /* Must be compatible with this index, if not NULL */ +); +#ifndef SQLITE_OMIT_EXPLAIN +int sqlite3WhereExplainOneScan( + Parse *pParse, /* Parse context */ + SrcList *pTabList, /* Table list this loop refers to */ + WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ + int iLevel, /* Value for "level" column of output */ + int iFrom, /* Value for "from" column of output */ + u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ +); +#else +# define sqlite3WhereExplainOneScan(u,v,w,x,y,z) 0 +#endif /* SQLITE_OMIT_EXPLAIN */ +#ifdef SQLITE_ENABLE_STMT_SCANSTATUS +void sqlite3WhereAddScanStatus( + 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) */ +); +#else +# define sqlite3WhereAddScanStatus(a, b, c, d) ((void)d) +#endif +Bitmask sqlite3WhereCodeOneLoopStart( + WhereInfo *pWInfo, /* Complete information about the WHERE clause */ + int iLevel, /* Which level of pWInfo->a[] should be coded */ + Bitmask notReady /* Which tables are currently available */ +); + + + + + + + /* ** Bitmasks for the operators on WhereTerm objects. These are all ** operators that are of interest to the query planner. An diff --git a/src/wherecode.c b/src/wherecode.c new file mode 100644 index 0000000000..e1f0f86615 --- /dev/null +++ b/src/wherecode.c @@ -0,0 +1,1501 @@ +/* +** 2015-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 module contains C code that generates VDBE code used to process +** the WHERE clause of SQL statements. +** +** This file was split off from where.c on 2015-06-06 in order to reduce the +** size of where.c and make it easier to edit. This file contains the routines +** that actually generate the bulk of the WHERE loop code. The original where.c +** file retains the code that does query planning and analysis. +*/ +#include "sqliteInt.h" +#include "whereInt.h" + +#ifndef SQLITE_OMIT_EXPLAIN +/* +** This routine is a helper for explainIndexRange() below +** +** pStr holds the text of an expression that we are building up one term +** at a time. This routine adds a new term to the end of the expression. +** Terms are separated by AND so add the "AND" text for second and subsequent +** terms only. +*/ +static void explainAppendTerm( + StrAccum *pStr, /* The text expression being built */ + int iTerm, /* Index of this term. First is zero */ + const char *zColumn, /* Name of the column */ + const char *zOp /* Name of the operator */ +){ + if( iTerm ) sqlite3StrAccumAppend(pStr, " AND ", 5); + sqlite3StrAccumAppendAll(pStr, zColumn); + sqlite3StrAccumAppend(pStr, zOp, 1); + sqlite3StrAccumAppend(pStr, "?", 1); +} + +/* +** Argument pLevel describes a strategy for scanning table pTab. This +** 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: +** +** SELECT * FROM t1 WHERE a=1 AND b>2; +** +** is run and there is an index on (a, b), then this function returns a +** string similar to: +** +** "a=? AND b>?" +*/ +static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop, Table *pTab){ + Index *pIndex = pLoop->u.btree.pIndex; + u16 nEq = pLoop->u.btree.nEq; + u16 nSkip = pLoop->nSkip; + int i, j; + Column *aCol = pTab->aCol; + i16 *aiColumn = pIndex->aiColumn; + + if( nEq==0 && (pLoop->wsFlags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))==0 ) return; + sqlite3StrAccumAppend(pStr, " (", 2); + for(i=0; i=nSkip ){ + explainAppendTerm(pStr, i, z, "="); + }else{ + 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(pStr, i++, z, ">"); + } + if( pLoop->wsFlags&WHERE_TOP_LIMIT ){ + char *z = aiColumn[j] < 0 ? "rowid" : aCol[aiColumn[j]].zName; + explainAppendTerm(pStr, i, z, "<"); + } + sqlite3StrAccumAppend(pStr, ")", 1); +} + +/* +** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN +** 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. +*/ +int sqlite3WhereExplainOneScan( + Parse *pParse, /* Parse context */ + SrcList *pTabList, /* Table list this loop refers to */ + WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ + int iLevel, /* Value for "level" column of output */ + int iFrom, /* Value for "from" column of output */ + u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ +){ + 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 */ + 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 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)); + + sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); + sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); + if( pItem->pSelect ){ + sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); + }else{ + sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); + } + + if( pItem->zAlias ){ + sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias); + } + 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) ){ + if( isSearch ){ + zFmt = "PRIMARY KEY"; + } + }else if( flags & WHERE_PARTIALIDX ){ + zFmt = "AUTOMATIC PARTIAL COVERING INDEX"; + }else if( flags & WHERE_AUTO_INDEX ){ + zFmt = "AUTOMATIC COVERING INDEX"; + }else if( flags & WHERE_IDX_ONLY ){ + zFmt = "COVERING INDEX %s"; + }else{ + zFmt = "INDEX %s"; + } + if( zFmt ){ + sqlite3StrAccumAppend(&str, " USING ", 7); + sqlite3XPrintf(&str, 0, zFmt, pIdx->zName); + explainIndexRange(&str, pLoop, pItem->pTab); + } + }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ + const char *zRange; + if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ + zRange = "(rowid=?)"; + }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ + zRange = "(rowid>? AND rowid?)"; + }else{ + assert( flags&WHERE_TOP_LIMIT); + zRange = "(rowidu.vtab.idxNum, pLoop->u.vtab.idxStr); + } +#endif +#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; +} +#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. +*/ +void sqlite3WhereAddScanStatus( + 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 + ); +} +#endif + + +/* +** Disable a term in the WHERE clause. Except, do not disable the term +** if it controls a LEFT OUTER JOIN and it did not originate in the ON +** or USING clause of that join. +** +** Consider the term t2.z='ok' in the following queries: +** +** (1) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x WHERE t2.z='ok' +** (2) SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.x AND t2.z='ok' +** (3) SELECT * FROM t1, t2 WHERE t1.a=t2.x AND t2.z='ok' +** +** The t2.z='ok' is disabled in the in (2) because it originates +** in the ON clause. The term is disabled in (3) because it is not part +** of a LEFT OUTER JOIN. In (1), the term is not disabled. +** +** Disabling a term causes that term to not be tested in the inner loop +** of the join. Disabling is an optimization. When terms are satisfied +** by indices, we disable them to prevent redundant tests in the inner +** loop. We would get the correct results if nothing were ever disabled, +** 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){ + int nLoop = 0; + while( pTerm + && (pTerm->wtFlags & TERM_CODED)==0 + && (pLevel->iLeftJoin==0 || ExprHasProperty(pTerm->pExpr, EP_FromJoin)) + && (pLevel->notReady & pTerm->prereqAll)==0 + ){ + 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++; + } +} + +/* +** Code an OP_Affinity opcode to apply the column affinity string zAff +** to the n registers starting at base. +** +** As an optimization, SQLITE_AFF_BLOB entries (which are no-ops) at the +** beginning and end of zAff are ignored. If all entries in zAff are +** SQLITE_AFF_BLOB, then no code gets generated. +** +** This routine makes its own copy of zAff so that the caller is free +** to modify zAff after this routine returns. +*/ +static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){ + Vdbe *v = pParse->pVdbe; + if( zAff==0 ){ + assert( pParse->db->mallocFailed ); + return; + } + assert( v!=0 ); + + /* Adjust base and n to skip over SQLITE_AFF_BLOB entries at the beginning + ** and end of the affinity string. + */ + while( n>0 && zAff[0]==SQLITE_AFF_BLOB ){ + n--; + base++; + zAff++; + } + while( n>1 && zAff[n-1]==SQLITE_AFF_BLOB ){ + n--; + } + + /* Code the OP_Affinity opcode if there is anything left to do. */ + if( n>0 ){ + sqlite3VdbeAddOp2(v, OP_Affinity, base, n); + sqlite3VdbeChangeP4(v, -1, zAff, n); + sqlite3ExprCacheAffinityChange(pParse, base, n); + } +} + + +/* +** Generate code for a single equality term of the WHERE clause. An equality +** term can be either X=expr or X IN (...). pTerm is the term to be +** coded. +** +** The current value for the constraint is left in register iReg. +** +** For a constraint of the form X=expr, the expression is evaluated and its +** result is left on the stack. For constraints of the form X IN (...) +** this routine sets up a loop that will iterate over all values of X. +*/ +static int codeEqualityTerm( + Parse *pParse, /* The parsing context */ + WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ + WhereLevel *pLevel, /* The level of the FROM clause we are working on */ + int iEq, /* Index of the equality term within this level */ + int bRev, /* True for reverse-order IN operations */ + int iTarget /* Attempt to leave results in this register */ +){ + Expr *pX = pTerm->pExpr; + Vdbe *v = pParse->pVdbe; + int iReg; /* Register holding results */ + + assert( iTarget>0 ); + if( pX->op==TK_EQ || pX->op==TK_IS ){ + iReg = sqlite3ExprCodeTarget(pParse, pX->pRight, iTarget); + }else if( pX->op==TK_ISNULL ){ + iReg = iTarget; + sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); +#ifndef SQLITE_OMIT_SUBQUERY + }else{ + int eType; + int iTab; + struct InLoop *pIn; + WhereLoop *pLoop = pLevel->pWLoop; + + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 + && pLoop->u.btree.pIndex!=0 + && pLoop->u.btree.pIndex->aSortOrder[iEq] + ){ + testcase( iEq==0 ); + testcase( bRev ); + bRev = !bRev; + } + assert( pX->op==TK_IN ); + iReg = iTarget; + eType = sqlite3FindInIndex(pParse, pX, IN_INDEX_LOOP, 0); + if( eType==IN_INDEX_INDEX_DESC ){ + testcase( bRev ); + bRev = !bRev; + } + iTab = pX->iTable; + sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0); + VdbeCoverageIf(v, bRev); + VdbeCoverageIf(v, !bRev); + assert( (pLoop->wsFlags & WHERE_MULTI_OR)==0 ); + pLoop->wsFlags |= WHERE_IN_ABLE; + if( pLevel->u.in.nIn==0 ){ + pLevel->addrNxt = sqlite3VdbeMakeLabel(v); + } + pLevel->u.in.nIn++; + pLevel->u.in.aInLoop = + sqlite3DbReallocOrFree(pParse->db, pLevel->u.in.aInLoop, + sizeof(pLevel->u.in.aInLoop[0])*pLevel->u.in.nIn); + pIn = pLevel->u.in.aInLoop; + if( pIn ){ + pIn += pLevel->u.in.nIn - 1; + pIn->iCur = iTab; + if( eType==IN_INDEX_ROWID ){ + pIn->addrInTop = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg); + }else{ + pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg); + } + pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen; + sqlite3VdbeAddOp1(v, OP_IsNull, iReg); VdbeCoverage(v); + }else{ + pLevel->u.in.nIn = 0; + } +#endif + } + disableTerm(pLevel, pTerm); + return iReg; +} + +/* +** Generate code that will evaluate all == and IN constraints for an +** index scan. +** +** For example, consider table t1(a,b,c,d,e,f) with index i1(a,b,c). +** Suppose the WHERE clause is this: a==5 AND b IN (1,2,3) AND c>5 AND c<10 +** The index has as many as three equality constraints, but in this +** example, the third "c" value is an inequality. So only two +** constraints are coded. This routine will generate code to evaluate +** a==5 and b IN (1,2,3). The current values for a and b will be stored +** in consecutive registers and the index of the first register is returned. +** +** In the example above nEq==2. But this subroutine works for any value +** of nEq including 0. If nEq==0, this routine is nearly a no-op. +** The only thing it does is allocate the pLevel->iMem memory cell and +** compute the affinity string. +** +** The nExtraReg parameter is 0 or 1. It is 0 if all WHERE clause constraints +** are == or IN and are covered by the nEq. nExtraReg is 1 if there is +** an inequality constraint (such as the "c>=5 AND c<10" in the example) that +** occurs after the nEq quality constraints. +** +** This routine allocates a range of nEq+nExtraReg memory cells and returns +** the index of the first memory cell in that range. The code that +** calls this routine will use that memory range to store keys for +** start and termination conditions of the loop. +** key value of the loop. If one or more IN operators appear, then +** this routine allocates an additional nEq memory cells for internal +** use. +** +** Before returning, *pzAff is set to point to a buffer containing a +** copy of the column affinity string of the index allocated using +** sqlite3DbMalloc(). Except, entries in the copy of the string associated +** with equality constraints that use BLOB or NONE affinity are set to +** SQLITE_AFF_BLOB. This is to deal with SQL such as the following: +** +** CREATE TABLE t1(a TEXT PRIMARY KEY, b); +** SELECT ... FROM t1 AS t2, t1 WHERE t1.a = t2.b; +** +** In the example above, the index on t1(a) has TEXT affinity. But since +** the right hand side of the equality constraint (t2.b) has BLOB/NONE affinity, +** no conversion should be attempted before using a t2.b value as part of +** a key to search the index. Hence the first byte in the returned affinity +** string in this example would be set to SQLITE_AFF_BLOB. +*/ +static int codeAllEqualityTerms( + Parse *pParse, /* Parsing context */ + WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ + int bRev, /* Reverse the order of IN operators */ + int nExtraReg, /* Number of extra registers to allocate */ + char **pzAff /* OUT: Set to point to affinity string */ +){ + u16 nEq; /* The number of == or IN constraints to code */ + u16 nSkip; /* Number of left-most columns to skip */ + Vdbe *v = pParse->pVdbe; /* The vm under construction */ + Index *pIdx; /* The index being used for this loop */ + WhereTerm *pTerm; /* A single constraint term */ + WhereLoop *pLoop; /* The WhereLoop object */ + int j; /* Loop counter */ + int regBase; /* Base register */ + int nReg; /* Number of registers to allocate */ + char *zAff; /* Affinity string to return */ + + /* This module is only called on query plans that use an index. */ + pLoop = pLevel->pWLoop; + assert( (pLoop->wsFlags & WHERE_VIRTUALTABLE)==0 ); + nEq = pLoop->u.btree.nEq; + nSkip = pLoop->nSkip; + pIdx = pLoop->u.btree.pIndex; + assert( pIdx!=0 ); + + /* Figure out how many memory cells we will need then allocate them. + */ + regBase = pParse->nMem + 1; + nReg = pLoop->u.btree.nEq + nExtraReg; + pParse->nMem += nReg; + + zAff = sqlite3DbStrDup(pParse->db, sqlite3IndexAffinityStr(v, pIdx)); + if( !zAff ){ + pParse->db->mallocFailed = 1; + } + + if( nSkip ){ + int iIdxCur = pLevel->iIdxCur; + sqlite3VdbeAddOp1(v, (bRev?OP_Last:OP_Rewind), iIdxCur); + VdbeCoverageIf(v, bRev==0); + VdbeCoverageIf(v, bRev!=0); + VdbeComment((v, "begin skip-scan on %s", pIdx->zName)); + j = sqlite3VdbeAddOp0(v, OP_Goto); + pLevel->addrSkip = sqlite3VdbeAddOp4Int(v, (bRev?OP_SeekLT:OP_SeekGT), + iIdxCur, 0, regBase, nSkip); + VdbeCoverageIf(v, bRev==0); + VdbeCoverageIf(v, bRev!=0); + sqlite3VdbeJumpHere(v, j); + for(j=0; jaiColumn[j]>=0 ); + VdbeComment((v, "%s", pIdx->pTable->aCol[pIdx->aiColumn[j]].zName)); + } + } + + /* Evaluate the equality constraints + */ + assert( zAff==0 || (int)strlen(zAff)>=nEq ); + for(j=nSkip; jaLTerm[j]; + assert( pTerm!=0 ); + /* The following testcase is true for indices with redundant columns. + ** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */ + testcase( (pTerm->wtFlags & TERM_CODED)!=0 ); + testcase( pTerm->wtFlags & TERM_VIRTUAL ); + r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, regBase+j); + if( r1!=regBase+j ){ + if( nReg==1 ){ + sqlite3ReleaseTempReg(pParse, regBase); + regBase = r1; + }else{ + sqlite3VdbeAddOp2(v, OP_SCopy, r1, regBase+j); + } + } + testcase( pTerm->eOperator & WO_ISNULL ); + testcase( pTerm->eOperator & WO_IN ); + if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ + Expr *pRight = pTerm->pExpr->pRight; + if( (pTerm->wtFlags & TERM_IS)==0 && sqlite3ExprCanBeNull(pRight) ){ + sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); + VdbeCoverage(v); + } + if( zAff ){ + if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){ + zAff[j] = SQLITE_AFF_BLOB; + } + if( sqlite3ExprNeedsNoAffinityChange(pRight, zAff[j]) ){ + zAff[j] = SQLITE_AFF_BLOB; + } + } + } + } + *pzAff = zAff; + return regBase; +} + +/* +** 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 +** implementation described by pWInfo. +*/ +Bitmask sqlite3WhereCodeOneLoopStart( + WhereInfo *pWInfo, /* Complete information about the WHERE clause */ + int iLevel, /* Which level of pWInfo->a[] should be coded */ + Bitmask notReady /* Which tables are currently available */ +){ + int j, k; /* Loop counters */ + int iCur; /* The VDBE cursor for the table */ + int addrNxt; /* Where to jump to continue with the next IN case */ + int omitTable; /* True if we use the index only */ + int bRev; /* True if we need to scan in reverse order */ + WhereLevel *pLevel; /* The where level to be coded */ + WhereLoop *pLoop; /* The WhereLoop object being coded */ + WhereClause *pWC; /* Decomposition of the entire WHERE clause */ + WhereTerm *pTerm; /* A WHERE clause term */ + Parse *pParse; /* Parsing context */ + sqlite3 *db; /* Database connection */ + Vdbe *v; /* The prepared stmt under constructions */ + struct SrcList_item *pTabItem; /* FROM clause term being coded */ + int addrBrk; /* Jump here to break out of the loop */ + int addrCont; /* Jump here to continue with next cycle */ + int iRowidReg = 0; /* Rowid is stored in this register, if not zero */ + int iReleaseReg = 0; /* Temp register to free before returning */ + + pParse = pWInfo->pParse; + v = pParse->pVdbe; + pWC = &pWInfo->sWC; + db = pParse->db; + pLevel = &pWInfo->a[iLevel]; + pLoop = pLevel->pWLoop; + pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; + iCur = pTabItem->iCursor; + pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); + bRev = (pWInfo->revMask>>iLevel)&1; + omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0 + && (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0; + VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); + + /* Create labels for the "break" and "continue" instructions + ** for the current loop. Jump to addrBrk to break out of a loop. + ** Jump to cont to go immediately to the next iteration of the + ** loop. + ** + ** When there is an IN operator, we also have a "addrNxt" label that + ** means to continue with the next IN value combination. When + ** there are no IN operators in the constraints, the "addrNxt" label + ** is the same as "addrBrk". + */ + addrBrk = pLevel->addrBrk = pLevel->addrNxt = sqlite3VdbeMakeLabel(v); + addrCont = pLevel->addrCont = sqlite3VdbeMakeLabel(v); + + /* If this is the right table of a LEFT OUTER JOIN, allocate and + ** initialize a memory cell that records if this table matches any + ** row of the left table of the join. + */ + if( pLevel->iFrom>0 && (pTabItem[0].jointype & JT_LEFT)!=0 ){ + pLevel->iLeftJoin = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Integer, 0, pLevel->iLeftJoin); + VdbeComment((v, "init LEFT JOIN no-match flag")); + } + + /* Special case of a FROM clause subquery implemented as a co-routine */ + if( pTabItem->viaCoroutine ){ + int regYield = pTabItem->regReturn; + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); + pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); + VdbeCoverage(v); + VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName)); + pLevel->op = OP_Goto; + }else + +#ifndef SQLITE_OMIT_VIRTUALTABLE + if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ + /* Case 1: The table is a virtual-table. Use the VFilter and VNext + ** to access the data. + */ + int iReg; /* P3 Value for OP_VFilter */ + int addrNotFound; + int nConstraint = pLoop->nLTerm; + + sqlite3ExprCachePush(pParse); + iReg = sqlite3GetTempRange(pParse, nConstraint+2); + addrNotFound = pLevel->addrBrk; + for(j=0; jaLTerm[j]; + if( pTerm==0 ) continue; + if( pTerm->eOperator & WO_IN ){ + codeEqualityTerm(pParse, pTerm, pLevel, j, bRev, iTarget); + addrNotFound = pLevel->addrNxt; + }else{ + sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget); + } + } + sqlite3VdbeAddOp2(v, OP_Integer, pLoop->u.vtab.idxNum, iReg); + sqlite3VdbeAddOp2(v, OP_Integer, nConstraint, iReg+1); + sqlite3VdbeAddOp4(v, OP_VFilter, iCur, addrNotFound, iReg, + pLoop->u.vtab.idxStr, + pLoop->u.vtab.needFree ? P4_MPRINTF : P4_STATIC); + VdbeCoverage(v); + pLoop->u.vtab.needFree = 0; + for(j=0; ju.vtab.omitMask>>j)&1 ){ + disableTerm(pLevel, pLoop->aLTerm[j]); + } + } + pLevel->op = OP_VNext; + pLevel->p1 = iCur; + pLevel->p2 = sqlite3VdbeCurrentAddr(v); + sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); + sqlite3ExprCachePop(pParse); + }else +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + + if( (pLoop->wsFlags & WHERE_IPK)!=0 + && (pLoop->wsFlags & (WHERE_COLUMN_IN|WHERE_COLUMN_EQ))!=0 + ){ + /* Case 2: We can directly reference a single row using an + ** equality comparison against the ROWID field. Or + ** we reference multiple rows using a "rowid IN (...)" + ** construct. + */ + assert( pLoop->u.btree.nEq==1 ); + pTerm = pLoop->aLTerm[0]; + assert( pTerm!=0 ); + assert( pTerm->pExpr!=0 ); + assert( omitTable==0 ); + testcase( pTerm->wtFlags & TERM_VIRTUAL ); + iReleaseReg = ++pParse->nMem; + iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, bRev, iReleaseReg); + if( iRowidReg!=iReleaseReg ) sqlite3ReleaseTempReg(pParse, iReleaseReg); + addrNxt = pLevel->addrNxt; + sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt); VdbeCoverage(v); + sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg); + VdbeCoverage(v); + sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1); + sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); + VdbeComment((v, "pk")); + pLevel->op = OP_Noop; + }else if( (pLoop->wsFlags & WHERE_IPK)!=0 + && (pLoop->wsFlags & WHERE_COLUMN_RANGE)!=0 + ){ + /* Case 3: We have an inequality comparison against the ROWID field. + */ + int testOp = OP_Noop; + int start; + int memEndValue = 0; + WhereTerm *pStart, *pEnd; + + assert( omitTable==0 ); + j = 0; + pStart = pEnd = 0; + if( pLoop->wsFlags & WHERE_BTM_LIMIT ) pStart = pLoop->aLTerm[j++]; + if( pLoop->wsFlags & WHERE_TOP_LIMIT ) pEnd = pLoop->aLTerm[j++]; + assert( pStart!=0 || pEnd!=0 ); + if( bRev ){ + pTerm = pStart; + pStart = pEnd; + pEnd = pTerm; + } + if( pStart ){ + Expr *pX; /* The expression that defines the start bound */ + int r1, rTemp; /* Registers for holding the start boundary */ + + /* The following constant maps TK_xx codes into corresponding + ** seek opcodes. It depends on a particular ordering of TK_xx + */ + const u8 aMoveOp[] = { + /* TK_GT */ OP_SeekGT, + /* TK_LE */ OP_SeekLE, + /* TK_LT */ OP_SeekLT, + /* TK_GE */ OP_SeekGE + }; + assert( TK_LE==TK_GT+1 ); /* Make sure the ordering.. */ + assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */ + assert( TK_GE==TK_GT+3 ); /* ... is correcct. */ + + assert( (pStart->wtFlags & TERM_VNULL)==0 ); + testcase( pStart->wtFlags & TERM_VIRTUAL ); + pX = pStart->pExpr; + assert( pX!=0 ); + testcase( pStart->leftCursor!=iCur ); /* transitive constraints */ + r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); + sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1); + VdbeComment((v, "pk")); + VdbeCoverageIf(v, pX->op==TK_GT); + VdbeCoverageIf(v, pX->op==TK_LE); + VdbeCoverageIf(v, pX->op==TK_LT); + VdbeCoverageIf(v, pX->op==TK_GE); + sqlite3ExprCacheAffinityChange(pParse, r1, 1); + sqlite3ReleaseTempReg(pParse, rTemp); + disableTerm(pLevel, pStart); + }else{ + sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, addrBrk); + VdbeCoverageIf(v, bRev==0); + VdbeCoverageIf(v, bRev!=0); + } + if( pEnd ){ + Expr *pX; + pX = pEnd->pExpr; + assert( pX!=0 ); + assert( (pEnd->wtFlags & TERM_VNULL)==0 ); + testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */ + testcase( pEnd->wtFlags & TERM_VIRTUAL ); + memEndValue = ++pParse->nMem; + sqlite3ExprCode(pParse, pX->pRight, memEndValue); + if( pX->op==TK_LT || pX->op==TK_GT ){ + testOp = bRev ? OP_Le : OP_Ge; + }else{ + testOp = bRev ? OP_Lt : OP_Gt; + } + disableTerm(pLevel, pEnd); + } + start = sqlite3VdbeCurrentAddr(v); + pLevel->op = bRev ? OP_Prev : OP_Next; + pLevel->p1 = iCur; + pLevel->p2 = start; + assert( pLevel->p5==0 ); + if( testOp!=OP_Noop ){ + iRowidReg = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_Rowid, iCur, iRowidReg); + sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); + sqlite3VdbeAddOp3(v, testOp, memEndValue, addrBrk, iRowidReg); + VdbeCoverageIf(v, testOp==OP_Le); + VdbeCoverageIf(v, testOp==OP_Lt); + VdbeCoverageIf(v, testOp==OP_Ge); + VdbeCoverageIf(v, testOp==OP_Gt); + sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); + } + }else if( pLoop->wsFlags & WHERE_INDEXED ){ + /* Case 4: A scan using an index. + ** + ** The WHERE clause may contain zero or more equality + ** terms ("==" or "IN" operators) that refer to the N + ** left-most columns of the index. It may also contain + ** inequality constraints (>, <, >= or <=) on the indexed + ** column that immediately follows the N equalities. Only + ** the right-most column can be an inequality - the rest must + ** use the "==" and "IN" operators. For example, if the + ** index is on (x,y,z), then the following clauses are all + ** optimized: + ** + ** x=5 + ** x=5 AND y=10 + ** x=5 AND y<10 + ** x=5 AND y>5 AND y<10 + ** x=5 AND y=5 AND z<=10 + ** + ** The z<10 term of the following cannot be used, only + ** the x=5 term: + ** + ** x=5 AND z<10 + ** + ** N may be zero if there are inequality constraints. + ** If there are no inequality constraints, then N is at + ** least one. + ** + ** This case is also used when there are no WHERE clause + ** constraints but an index is selected anyway, in order + ** to force the output order to conform to an ORDER BY. + */ + static const u8 aStartOp[] = { + 0, + 0, + OP_Rewind, /* 2: (!start_constraints && startEq && !bRev) */ + OP_Last, /* 3: (!start_constraints && startEq && bRev) */ + OP_SeekGT, /* 4: (start_constraints && !startEq && !bRev) */ + OP_SeekLT, /* 5: (start_constraints && !startEq && bRev) */ + OP_SeekGE, /* 6: (start_constraints && startEq && !bRev) */ + OP_SeekLE /* 7: (start_constraints && startEq && bRev) */ + }; + static const u8 aEndOp[] = { + OP_IdxGE, /* 0: (end_constraints && !bRev && !endEq) */ + OP_IdxGT, /* 1: (end_constraints && !bRev && endEq) */ + OP_IdxLE, /* 2: (end_constraints && bRev && !endEq) */ + OP_IdxLT, /* 3: (end_constraints && bRev && endEq) */ + }; + u16 nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */ + int regBase; /* Base register holding constraint values */ + WhereTerm *pRangeStart = 0; /* Inequality constraint at range start */ + WhereTerm *pRangeEnd = 0; /* Inequality constraint at range end */ + int startEq; /* True if range start uses ==, >= or <= */ + int endEq; /* True if range end uses ==, >= or <= */ + int start_constraints; /* Start of range is constrained */ + int nConstraint; /* Number of constraint terms */ + Index *pIdx; /* The index we will be using */ + int iIdxCur; /* The VDBE cursor for the index */ + int nExtraReg = 0; /* Number of extra registers needed */ + int op; /* Instruction opcode */ + char *zStartAff; /* Affinity for start of range constraint */ + char cEndAff = 0; /* Affinity for end of range constraint */ + u8 bSeekPastNull = 0; /* True to seek past initial nulls */ + u8 bStopAtNull = 0; /* Add condition to terminate at NULLs */ + + pIdx = pLoop->u.btree.pIndex; + iIdxCur = pLevel->iIdxCur; + 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) ..." + ** query, then the caller will only allow the loop to run for + ** a single iteration. This means that the first row returned + ** should not have a NULL value stored in 'x'. If column 'x' is + ** 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->nOBSat>0 + && (pIdx->nKeyCol>nEq) + ){ + assert( pLoop->nSkip==0 ); + bSeekPastNull = 1; + nExtraReg = 1; + } + + /* Find any inequality constraint terms for the start and end + ** of the range. + */ + j = nEq; + 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 + ){ + bSeekPastNull = 1; + } + } + assert( pRangeEnd==0 || (pRangeEnd->wtFlags & TERM_VNULL)==0 ); + + /* Generate code to evaluate all constraint terms using == or IN + ** and store the values of those terms in an array of registers + ** starting at regBase. + */ + regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff); + assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq ); + if( zStartAff ) cEndAff = zStartAff[nEq]; + addrNxt = pLevel->addrNxt; + + /* If we are doing a reverse order scan on an ascending index, or + ** a forward order scan on a descending index, interchange the + ** start and end terms (pRangeStart and pRangeEnd). + */ + if( (nEqnKeyCol && bRev==(pIdx->aSortOrder[nEq]==SQLITE_SO_ASC)) + || (bRev && pIdx->nKeyCol==nEq) + ){ + SWAP(WhereTerm *, pRangeEnd, pRangeStart); + SWAP(u8, bSeekPastNull, bStopAtNull); + } + + testcase( pRangeStart && (pRangeStart->eOperator & WO_LE)!=0 ); + testcase( pRangeStart && (pRangeStart->eOperator & WO_GE)!=0 ); + testcase( pRangeEnd && (pRangeEnd->eOperator & WO_LE)!=0 ); + testcase( pRangeEnd && (pRangeEnd->eOperator & WO_GE)!=0 ); + startEq = !pRangeStart || pRangeStart->eOperator & (WO_LE|WO_GE); + endEq = !pRangeEnd || pRangeEnd->eOperator & (WO_LE|WO_GE); + start_constraints = pRangeStart || nEq>0; + + /* Seek the index cursor to the start of the range. */ + nConstraint = nEq; + if( pRangeStart ){ + Expr *pRight = pRangeStart->pExpr->pRight; + sqlite3ExprCode(pParse, pRight, regBase+nEq); + whereLikeOptimizationStringFixup(v, pLevel, pRangeStart); + if( (pRangeStart->wtFlags & TERM_VNULL)==0 + && sqlite3ExprCanBeNull(pRight) + ){ + sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); + VdbeCoverage(v); + } + if( zStartAff ){ + if( sqlite3CompareAffinity(pRight, zStartAff[nEq])==SQLITE_AFF_BLOB){ + /* Since the comparison is to be performed with no conversions + ** applied to the operands, set the affinity to apply to pRight to + ** SQLITE_AFF_BLOB. */ + zStartAff[nEq] = SQLITE_AFF_BLOB; + } + if( sqlite3ExprNeedsNoAffinityChange(pRight, zStartAff[nEq]) ){ + zStartAff[nEq] = SQLITE_AFF_BLOB; + } + } + nConstraint++; + testcase( pRangeStart->wtFlags & TERM_VIRTUAL ); + }else if( bSeekPastNull ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); + nConstraint++; + startEq = 0; + start_constraints = 1; + } + codeApplyAffinity(pParse, regBase, nConstraint - bSeekPastNull, zStartAff); + op = aStartOp[(start_constraints<<2) + (startEq<<1) + bRev]; + assert( op!=0 ); + sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); + VdbeCoverage(v); + VdbeCoverageIf(v, op==OP_Rewind); testcase( op==OP_Rewind ); + VdbeCoverageIf(v, op==OP_Last); testcase( op==OP_Last ); + VdbeCoverageIf(v, op==OP_SeekGT); testcase( op==OP_SeekGT ); + VdbeCoverageIf(v, op==OP_SeekGE); testcase( op==OP_SeekGE ); + VdbeCoverageIf(v, op==OP_SeekLE); testcase( op==OP_SeekLE ); + VdbeCoverageIf(v, op==OP_SeekLT); testcase( op==OP_SeekLT ); + + /* Load the value for the inequality constraint at the end of the + ** range (if any). + */ + nConstraint = nEq; + if( pRangeEnd ){ + 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) + ){ + sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, addrNxt); + VdbeCoverage(v); + } + if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_BLOB + && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff) + ){ + codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff); + } + nConstraint++; + testcase( pRangeEnd->wtFlags & TERM_VIRTUAL ); + }else if( bStopAtNull ){ + sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); + endEq = 0; + nConstraint++; + } + sqlite3DbFree(db, zStartAff); + + /* Top of the loop body */ + pLevel->p2 = sqlite3VdbeCurrentAddr(v); + + /* Check if the index cursor is past the end of the range. */ + if( nConstraint ){ + op = aEndOp[bRev*2 + endEq]; + sqlite3VdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase, nConstraint); + testcase( op==OP_IdxGT ); VdbeCoverageIf(v, op==OP_IdxGT ); + testcase( op==OP_IdxGE ); VdbeCoverageIf(v, op==OP_IdxGE ); + testcase( op==OP_IdxLT ); VdbeCoverageIf(v, op==OP_IdxLT ); + testcase( op==OP_IdxLE ); VdbeCoverageIf(v, op==OP_IdxLE ); + } + + /* Seek the table cursor, if required */ + disableTerm(pLevel, pRangeStart); + disableTerm(pLevel, pRangeEnd); + if( omitTable ){ + /* pIdx is a covering index. No need to access the main table. */ + }else if( HasRowid(pIdx->pTable) ){ + iRowidReg = ++pParse->nMem; + sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, iRowidReg); + sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg); + sqlite3VdbeAddOp2(v, OP_Seek, iCur, iRowidReg); /* Deferred seek */ + }else if( iCur!=iIdxCur ){ + Index *pPk = sqlite3PrimaryKeyIndex(pIdx->pTable); + iRowidReg = sqlite3GetTempRange(pParse, pPk->nKeyCol); + for(j=0; jnKeyCol; j++){ + k = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[j]); + sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, k, iRowidReg+j); + } + sqlite3VdbeAddOp4Int(v, OP_NotFound, iCur, addrCont, + iRowidReg, pPk->nKeyCol); VdbeCoverage(v); + } + + /* Record the instruction used to terminate the loop. Disable + ** WHERE clause terms made redundant by the index range scan. + */ + if( pLoop->wsFlags & WHERE_ONEROW ){ + pLevel->op = OP_Noop; + }else if( bRev ){ + pLevel->op = OP_Prev; + }else{ + pLevel->op = OP_Next; + } + pLevel->p1 = iIdxCur; + pLevel->p3 = (pLoop->wsFlags&WHERE_UNQ_WANTED)!=0 ? 1:0; + if( (pLoop->wsFlags & WHERE_CONSTRAINT)==0 ){ + pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; + }else{ + assert( pLevel->p5==0 ); + } + }else + +#ifndef SQLITE_OMIT_OR_OPTIMIZATION + if( pLoop->wsFlags & WHERE_MULTI_OR ){ + /* Case 5: Two or more separately indexed terms connected by OR + ** + ** Example: + ** + ** CREATE TABLE t1(a,b,c,d); + ** CREATE INDEX i1 ON t1(a); + ** CREATE INDEX i2 ON t1(b); + ** CREATE INDEX i3 ON t1(c); + ** + ** SELECT * FROM t1 WHERE a=5 OR b=7 OR (c=11 AND d=13) + ** + ** In the example, there are three indexed terms connected by OR. + ** The top of the loop looks like this: + ** + ** Null 1 # Zero the rowset in reg 1 + ** + ** Then, for each indexed term, the following. The arguments to + ** RowSetTest are such that the rowid of the current row is inserted + ** into the RowSet. If it is already present, control skips the + ** Gosub opcode and jumps straight to the code generated by WhereEnd(). + ** + ** sqlite3WhereBegin() + ** RowSetTest # Insert rowid into rowset + ** Gosub 2 A + ** sqlite3WhereEnd() + ** + ** Following the above, code to terminate the loop. Label A, the target + ** of the Gosub above, jumps to the instruction right after the Goto. + ** + ** Null 1 # Zero the rowset in reg 1 + ** Goto B # The loop is finished. + ** + ** A: # Return data, whatever. + ** + ** Return 2 # Jump back to the Gosub + ** + ** B: + ** + ** Added 2014-05-26: If the table is a WITHOUT ROWID table, then + ** use an ephemeral 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 */ + Index *pCov = 0; /* Potential covering index (or NULL) */ + int iCovCur = pParse->nTab++; /* Cursor used for index scans (if any) */ + + int regReturn = ++pParse->nMem; /* Register used with OP_Gosub */ + int regRowset = 0; /* Register for RowSet object */ + int regRowid = 0; /* Register holding rowid */ + int iLoopBody = sqlite3VdbeMakeLabel(v); /* Start of loop body */ + 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 ); + assert( pTerm->eOperator & WO_OR ); + assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); + pOrWc = &pTerm->u.pOrInfo->wc; + pLevel->op = OP_Return; + pLevel->p1 = regReturn; + + /* Set up a new SrcList in pOrTab containing the table being scanned + ** by this loop in the a[0] slot and all notReady tables in a[1..] slots. + ** This becomes the SrcList in the recursive call to sqlite3WhereBegin(). + */ + if( pWInfo->nLevel>1 ){ + int nNotReady; /* The number of notReady tables */ + struct SrcList_item *origSrc; /* Original list of tables */ + nNotReady = pWInfo->nLevel - iLevel - 1; + pOrTab = sqlite3StackAllocRaw(db, + sizeof(*pOrTab)+ nNotReady*sizeof(pOrTab->a[0])); + if( pOrTab==0 ) return notReady; + pOrTab->nAlloc = (u8)(nNotReady + 1); + pOrTab->nSrc = pOrTab->nAlloc; + memcpy(pOrTab->a, pTabItem, sizeof(*pTabItem)); + origSrc = pWInfo->pTabList->a; + for(k=1; k<=nNotReady; k++){ + memcpy(&pOrTab->a[k], &origSrc[pLevel[k].iFrom], sizeof(pOrTab->a[k])); + } + }else{ + pOrTab = pWInfo->pTabList; + } + + /* Initialize the rowset register to contain NULL. An SQL NULL is + ** 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 + ** immediately following the OP_Return at the bottom of the loop. This + ** is required in a few obscure LEFT JOIN cases where control jumps + ** over the top of the loop into the body of it. In this case the + ** correct response for the end-of-loop code (the OP_Return) is to + ** fall through to the next instruction, just as an OP_Next does if + ** called on an uninitialized cursor. + */ + if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ + 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; + } + iRetInit = sqlite3VdbeAddOp2(v, OP_Integer, 0, regReturn); + + /* If the original WHERE clause is z of the form: (x1 OR x2 OR ...) AND y + ** Then for every term xN, evaluate as the subexpression: xN AND z + ** That way, terms in y that are factored into the disjunction will + ** be picked up by the recursive calls to sqlite3WhereBegin() below. + ** + ** Actually, each subexpression is converted to "xN AND w" where w is + ** the "interesting" terms of z - terms that did not originate in the + ** ON or USING clause of a LEFT JOIN, and terms that are usable as + ** indices. + ** + ** This optimization also only applies if the (x1 OR x2 OR ...) term + ** is not contained in the ON clause of a LEFT JOIN. + ** See ticket http://www.sqlite.org/src/info/f2369304e4 + */ + if( pWC->nTerm>1 ){ + int iTerm; + for(iTerm=0; iTermnTerm; iTerm++){ + Expr *pExpr = pWC->a[iTerm].pExpr; + if( &pWC->a[iTerm] == pTerm ) continue; + if( ExprHasProperty(pExpr, EP_FromJoin) ) 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); + } + if( pAndExpr ){ + pAndExpr = sqlite3PExpr(pParse, TK_AND, 0, pAndExpr, 0); + } + } + + /* 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_FORCE_TABLE + | 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 ){ + 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. */ + 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; + int addrExplain = sqlite3WhereExplainOneScan( + pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 + ); + sqlite3WhereAddScanStatus(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 + ** row will be skipped in subsequent sub-WHERE clauses. + */ + if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ + int r; + 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 + ** need to be tested later. + */ + if( pSubWInfo->untestedTerms ) untestedTerms = 1; + + /* If all of the OR-connected terms are optimized using the same + ** index, and the index is opened using the same cursor number + ** by each call to sqlite3WhereBegin() made by this loop, it may + ** be possible to use that index as a covering index. + ** + ** If the call to sqlite3WhereBegin() above resulted in a scan that + ** uses an index, and this is either the first OR-connected term + ** processed or the index is the same as that used by all previous + ** terms, set pCov to the candidate covering index. Otherwise, set + ** pCov to NULL to indicate that no candidate covering index will + ** be available. + */ + pSubLoop = pSubWInfo->a[0].pWLoop; + 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; + } + + /* Finish the loop through table entries that match term pOrTerm. */ + sqlite3WhereEnd(pSubWInfo); + } + } + } + pLevel->u.pCovidx = pCov; + if( pCov ) pLevel->iIdxCur = iCovCur; + if( pAndExpr ){ + pAndExpr->pLeft = 0; + sqlite3ExprDelete(db, pAndExpr); + } + sqlite3VdbeChangeP1(v, iRetInit, sqlite3VdbeCurrentAddr(v)); + sqlite3VdbeAddOp2(v, OP_Goto, 0, pLevel->addrBrk); + sqlite3VdbeResolveLabel(v, iLoopBody); + + if( pWInfo->nLevel>1 ) sqlite3StackFree(db, pOrTab); + if( !untestedTerms ) disableTerm(pLevel, pTerm); + }else +#endif /* SQLITE_OMIT_OR_OPTIMIZATION */ + + { + /* Case 6: There is no usable index. We must do a complete + ** scan of the entire table. + */ + static const u8 aStep[] = { OP_Next, OP_Prev }; + static const u8 aStart[] = { OP_Rewind, OP_Last }; + assert( bRev==0 || bRev==1 ); + if( pTabItem->isRecursive ){ + /* Tables marked isRecursive have only a single row that is stored in + ** a pseudo-cursor. No need to Rewind or Next such cursors. */ + pLevel->op = OP_Noop; + }else{ + pLevel->op = aStep[bRev]; + pLevel->p1 = iCur; + pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); + VdbeCoverageIf(v, bRev==0); + VdbeCoverageIf(v, bRev!=0); + pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; + } + } + +#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. + */ + 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; + if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ + testcase( pWInfo->untestedTerms==0 + && (pWInfo->wctrlFlags & WHERE_ONETABLE_ONLY)!=0 ); + pWInfo->untestedTerms = 1; + continue; + } + pE = pTerm->pExpr; + assert( pE!=0 ); + 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; + } + + /* Insert code to test for implied constraints based on transitivity + ** of the "==" operator. + ** + ** Example: If the WHERE clause contains "t1.a=t2.b" and "t2.b=123" + ** and we are coding the t1 loop and the t2 loop has not yet coded, + ** then we cannot use the "t1.a=t2.b" constraint, but we can code + ** the implied "t1.a=123" constraint. + */ + for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ + Expr *pE, *pEAlt; + WhereTerm *pAlt; + if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; + if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) continue; + if( (pTerm->eOperator & WO_EQUIV)==0 ) continue; + if( pTerm->leftCursor!=iCur ) continue; + if( pLevel->iLeftJoin ) continue; + pE = pTerm->pExpr; + assert( !ExprHasProperty(pE, EP_FromJoin) ); + assert( (pTerm->prereqRight & pLevel->notReady)!=0 ); + pAlt = sqlite3WhereFindTerm(pWC, iCur, pTerm->u.leftColumn, notReady, + WO_EQ|WO_IN|WO_IS, 0); + if( pAlt==0 ) continue; + if( pAlt->wtFlags & (TERM_CODED) ) continue; + testcase( pAlt->eOperator & WO_EQ ); + testcase( pAlt->eOperator & WO_IS ); + testcase( pAlt->eOperator & WO_IN ); + VdbeModuleComment((v, "begin transitive constraint")); + pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt)); + if( pEAlt ){ + *pEAlt = *pAlt->pExpr; + pEAlt->pLeft = pE->pLeft; + sqlite3ExprIfFalse(pParse, pEAlt, addrCont, SQLITE_JUMPIFNULL); + sqlite3StackFree(db, pEAlt); + } + } + + /* For a LEFT OUTER JOIN, generate code that will record the fact that + ** at least one row of the right table has matched the left table. + */ + if( pLevel->iLeftJoin ){ + pLevel->addrFirst = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp2(v, OP_Integer, 1, pLevel->iLeftJoin); + VdbeComment((v, "record LEFT JOIN hit")); + sqlite3ExprCacheClear(pParse); + for(pTerm=pWC->a, j=0; jnTerm; j++, pTerm++){ + testcase( pTerm->wtFlags & TERM_VIRTUAL ); + testcase( pTerm->wtFlags & TERM_CODED ); + if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; + if( (pTerm->prereqAll & pLevel->notReady)!=0 ){ + assert( pWInfo->untestedTerms ); + continue; + } + assert( pTerm->pExpr ); + sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL); + pTerm->wtFlags |= TERM_CODED; + } + } + + return pLevel->notReady; +} diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index 0f1f8a4fce..8e7858896a 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -343,6 +343,7 @@ foreach file { update.c vacuum.c vtab.c + wherecode.c where.c parse.c From 6c1f4ef217deae6f288f86cb9b572256024fa97d Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 8 Jun 2015 14:23:15 +0000 Subject: [PATCH 16/28] Split more subfunctions of where.c out into a new whereexpr.c source file, for improved maintainability. FossilOrigin-Name: 46ef95c108ad8961f2bf3d2dc839d4fb1fddd770 --- Makefile.in | 8 +- Makefile.msc | 8 +- main.mk | 5 +- manifest | 23 +- manifest.uuid | 2 +- src/where.c | 1240 +----------------------------------------- src/whereInt.h | 17 +- src/whereexpr.c | 1249 +++++++++++++++++++++++++++++++++++++++++++ tool/mksqlite3c.tcl | 1 + 9 files changed, 1306 insertions(+), 1247 deletions(-) create mode 100644 src/whereexpr.c diff --git a/Makefile.in b/Makefile.in index 48dba42e63..ea1715557e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -184,7 +184,8 @@ LIBOBJS0 = alter.lo analyze.lo attach.lo auth.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 wherecode.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. # @@ -294,6 +295,7 @@ SRC = \ $(TOP)/src/walker.c \ $(TOP)/src/where.c \ $(TOP)/src/wherecode.c \ + $(TOP)/src/whereexpr.c \ $(TOP)/src/whereInt.h # Source code for extensions @@ -456,6 +458,7 @@ TESTSRC2 = \ $(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 \ @@ -854,6 +857,9 @@ where.lo: $(TOP)/src/where.c $(HDR) 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 diff --git a/Makefile.msc b/Makefile.msc index 6cd1f37b81..11b2097465 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -838,7 +838,8 @@ LIBOBJS0 = vdbe.lo parse.lo alter.lo analyze.lo attach.lo auth.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 wherecode.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. # @@ -960,6 +961,7 @@ SRC2 = \ $(TOP)\src\walker.c \ $(TOP)\src\where.c \ $(TOP)\src\wherecode.c \ + $(TOP)\src\whereexpr.c \ $(TOP)\src\whereInt.h # Source code for extensions @@ -1123,6 +1125,7 @@ TESTSRC2 = \ $(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 \ @@ -1535,6 +1538,9 @@ where.lo: $(TOP)\src\where.c $(HDR) 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 diff --git a/main.mk b/main.mk index 71ce38ad32..27d56fb80f 100644 --- a/main.mk +++ b/main.mk @@ -69,7 +69,8 @@ LIBOBJ+= vdbe.o parse.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 wherecode.o utf.o vtab.o + vdbetrace.o wal.o walker.o where.o wherecode.o whereexpr.o \ + utf.o vtab.o @@ -172,6 +173,7 @@ SRC = \ $(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 +341,7 @@ TESTSRC2 = \ $(TOP)/src/vdbemem.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 \ diff --git a/manifest b/manifest index e7b9ade388..0307e1a087 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Split\sout\sthe\sbulk\sof\sthe\sactual\sVDBE\scode\sgeneration\slogic\sfrom\swhere.c\ninto\sa\snew\sfile,\sleaving\sbehind\sthe\sanalysis\slogic.\s\sThis\smakes\sthe\soriginal\nwhere.c\ssmaller\sand\shopefully\seasier\sto\sedit. -D 2015-06-06T20:12:09.183 +C Split\smore\ssubfunctions\sof\swhere.c\sout\sinto\sa\snew\swhereexpr.c\ssource\sfile,\nfor\simproved\smaintainability. +D 2015-06-08T14:23:15.485 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in 64136f59edd49b389b5c5d24388e204929b807e5 +F Makefile.in d7bde8e39e88f23c99219e822aaab80a9ce48a53 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc e2f1f95dc4a0af0b9ac3c2ee66878700b71ad93f +F Makefile.msc e4e8cbbe98d77d62b1fed34d95d966d5db2a1b01 F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858 F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7 F VERSION ce0ae95abd7121c534f6917c1c8f2b70d9acd4db @@ -171,7 +171,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk b9e0c806c04739b20f281680f8771bc2e20acd54 +F main.mk 4aed2f4087f3880a92c505fba772f2368d699da5 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk d5e22023b5238985bb54a72d33e0ac71fe4f8a32 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -326,9 +326,10 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c c9d804dcf02388207096e4da19487d9a2a7a9a67 -F src/whereInt.h 40e1d060b6aa02edbb7b8a1f3dfc0cc4ff140881 +F src/where.c a328fcc3342044992644b6a11bf301593b8dafb4 +F src/whereInt.h 5f87e3c4b0551747d119730dfebddd3c54f04047 F src/wherecode.c 0669481cabaf5caf934b6bb825df15bc57f60d40 +F src/whereexpr.c 9ce1c9cfedbf80c93c7d899497025ec8256ce652 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 @@ -1248,7 +1249,7 @@ F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e F tool/mkpragmatab.tcl 40c287d3f929ece67da6e9e7c49885789960accf F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl 69bae8ce4aa52d2ff82d4a8a856bf283ec035b2e -F tool/mksqlite3c.tcl 9f60238b2273048a4089077a43716d3b33a67c51 +F tool/mksqlite3c.tcl 9a4b87e86c6036b285b5f0fe1e4db0c79c4092ab F tool/mksqlite3h.tcl 44730d586c9031638cdd2eb443b801c0d2dbd9f8 F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b F tool/mkvsix.tcl 3b58b9398f91c7dbf18d49eb87cefeee9efdbce1 @@ -1283,7 +1284,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 4f20ac90bce8bd7ba43ef59af5cc4ef7aa282fe8 -R f7b66d3e1070ad2d563a494aba699c70 +P faa0e420e93a2bc1c84df9eb9fef4748d29ce339 +R d7cd77de896255756abb541430f78771 U drh -Z 85351aea272e066665037522f98406f9 +Z 58efdf4d20fca9a444e5c6368ea56c89 diff --git a/manifest.uuid b/manifest.uuid index a3541920e7..1199d6a972 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -faa0e420e93a2bc1c84df9eb9fef4748d29ce339 \ No newline at end of file +46ef95c108ad8961f2bf3d2dc839d4fb1fddd770 \ No newline at end of file diff --git a/src/where.c b/src/where.c index e446f6db8c..5c5022c9f6 100644 --- a/src/where.c +++ b/src/where.c @@ -136,150 +136,6 @@ whereOrInsert_done: return 1; } -/* -** Initialize a preallocated WhereClause structure. -*/ -static void whereClauseInit( - WhereClause *pWC, /* The WhereClause to be initialized */ - WhereInfo *pWInfo /* The WHERE processing context */ -){ - pWC->pWInfo = pWInfo; - pWC->pOuter = 0; - pWC->nTerm = 0; - pWC->nSlot = ArraySize(pWC->aStatic); - pWC->a = pWC->aStatic; -} - -/* Forward reference */ -static void whereClauseClear(WhereClause*); - -/* -** Deallocate all memory associated with a WhereOrInfo object. -*/ -static void whereOrInfoDelete(sqlite3 *db, WhereOrInfo *p){ - whereClauseClear(&p->wc); - sqlite3DbFree(db, p); -} - -/* -** Deallocate all memory associated with a WhereAndInfo object. -*/ -static void whereAndInfoDelete(sqlite3 *db, WhereAndInfo *p){ - whereClauseClear(&p->wc); - sqlite3DbFree(db, p); -} - -/* -** Deallocate a WhereClause structure. The WhereClause structure -** itself is not freed. This routine is the inverse of whereClauseInit(). -*/ -static void whereClauseClear(WhereClause *pWC){ - int i; - WhereTerm *a; - sqlite3 *db = pWC->pWInfo->pParse->db; - for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){ - if( a->wtFlags & TERM_DYNAMIC ){ - sqlite3ExprDelete(db, a->pExpr); - } - if( a->wtFlags & TERM_ORINFO ){ - whereOrInfoDelete(db, a->u.pOrInfo); - }else if( a->wtFlags & TERM_ANDINFO ){ - whereAndInfoDelete(db, a->u.pAndInfo); - } - } - if( pWC->a!=pWC->aStatic ){ - sqlite3DbFree(db, pWC->a); - } -} - -/* -** Add a single new WhereTerm entry to the WhereClause object pWC. -** The new WhereTerm object is constructed from Expr p and with wtFlags. -** The index in pWC->a[] of the new WhereTerm is returned on success. -** 0 is returned if the new WhereTerm could not be added due to a memory -** allocation error. The memory allocation failure will be recorded in -** the db->mallocFailed flag so that higher-level functions can detect it. -** -** This routine will increase the size of the pWC->a[] array as necessary. -** -** If the wtFlags argument includes TERM_DYNAMIC, then responsibility -** for freeing the expression p is assumed by the WhereClause object pWC. -** This is true even if this routine fails to allocate a new WhereTerm. -** -** WARNING: This routine might reallocate the space used to store -** WhereTerms. All pointers to WhereTerms should be invalidated after -** calling this routine. Such pointers may be reinitialized by referencing -** the pWC->a[] array. -*/ -static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ - WhereTerm *pTerm; - int idx; - testcase( wtFlags & TERM_VIRTUAL ); - if( pWC->nTerm>=pWC->nSlot ){ - WhereTerm *pOld = pWC->a; - sqlite3 *db = pWC->pWInfo->pParse->db; - pWC->a = sqlite3DbMallocRaw(db, sizeof(pWC->a[0])*pWC->nSlot*2 ); - if( pWC->a==0 ){ - if( wtFlags & TERM_DYNAMIC ){ - sqlite3ExprDelete(db, p); - } - pWC->a = pOld; - return 0; - } - memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm); - if( pOld!=pWC->aStatic ){ - 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) - 270; - }else{ - pTerm->truthProb = 1; - } - pTerm->pExpr = sqlite3ExprSkipCollate(p); - pTerm->wtFlags = wtFlags; - pTerm->pWC = pWC; - pTerm->iParent = -1; - return idx; -} - -/* -** This routine identifies subexpressions in the WHERE clause where -** each subexpression is separated by the AND operator or some other -** operator specified in the op parameter. The WhereClause structure -** is filled with pointers to subexpressions. For example: -** -** WHERE a=='hello' AND coalesce(b,11)<10 AND (c+12!=d OR c==22) -** \________/ \_______________/ \________________/ -** slot[0] slot[1] slot[2] -** -** The original WHERE clause in pExpr is unaltered. All this routine -** does is make slot[] entries point to substructure within pExpr. -** -** In the previous sentence and in the diagram, "slot[]" refers to -** the WhereClause.a[] array. The slot[] array grows as needed to contain -** all terms of the WHERE clause. -*/ -static void whereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ - Expr *pE2 = sqlite3ExprSkipCollate(pExpr); - pWC->op = op; - if( pE2==0 ) return; - if( pE2->op!=op ){ - whereClauseInsert(pWC, pExpr, 0); - }else{ - whereSplit(pWC, pE2->pLeft, op); - whereSplit(pWC, pE2->pRight, op); - } -} - -/* -** Initialize a WhereMaskSet object -*/ -#define initMaskSet(P) (P)->n=0 - /* ** Return the bitmask for the given cursor number. Return 0 if ** iCursor is not in the set. @@ -308,140 +164,6 @@ static void createMask(WhereMaskSet *pMaskSet, int iCursor){ pMaskSet->ix[pMaskSet->n++] = iCursor; } -/* -** These routines walk (recursively) an expression tree and generate -** a bitmask indicating which tables are used in that expression -** tree. -*/ -static Bitmask exprListTableUsage(WhereMaskSet*, ExprList*); -static Bitmask exprSelectTableUsage(WhereMaskSet*, Select*); -static Bitmask exprTableUsage(WhereMaskSet *pMaskSet, Expr *p){ - Bitmask mask = 0; - if( p==0 ) return 0; - if( p->op==TK_COLUMN ){ - mask = sqlite3WhereGetMask(pMaskSet, p->iTable); - return mask; - } - mask = exprTableUsage(pMaskSet, p->pRight); - mask |= exprTableUsage(pMaskSet, p->pLeft); - if( ExprHasProperty(p, EP_xIsSelect) ){ - mask |= exprSelectTableUsage(pMaskSet, p->x.pSelect); - }else{ - mask |= exprListTableUsage(pMaskSet, p->x.pList); - } - return mask; -} -static Bitmask exprListTableUsage(WhereMaskSet *pMaskSet, ExprList *pList){ - int i; - Bitmask mask = 0; - if( pList ){ - for(i=0; inExpr; i++){ - mask |= exprTableUsage(pMaskSet, pList->a[i].pExpr); - } - } - return mask; -} -static Bitmask exprSelectTableUsage(WhereMaskSet *pMaskSet, Select *pS){ - Bitmask mask = 0; - while( pS ){ - SrcList *pSrc = pS->pSrc; - mask |= exprListTableUsage(pMaskSet, pS->pEList); - mask |= exprListTableUsage(pMaskSet, pS->pGroupBy); - mask |= exprListTableUsage(pMaskSet, pS->pOrderBy); - mask |= exprTableUsage(pMaskSet, pS->pWhere); - mask |= exprTableUsage(pMaskSet, pS->pHaving); - if( ALWAYS(pSrc!=0) ){ - int i; - for(i=0; inSrc; i++){ - mask |= exprSelectTableUsage(pMaskSet, pSrc->a[i].pSelect); - mask |= exprTableUsage(pMaskSet, pSrc->a[i].pOn); - } - } - pS = pS->pPrior; - } - return mask; -} - -/* -** Return TRUE if the given operator is one of the operators that is -** allowed for an indexable WHERE clause term. The allowed operators are -** "=", "<", ">", "<=", ">=", "IN", and "IS NULL" -*/ -static int allowedOp(int op){ - assert( TK_GT>TK_EQ && TK_GTTK_EQ && TK_LTTK_EQ && TK_LE=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS; -} - -/* -** Commute a comparison operator. Expressions of the form "X op Y" -** are converted into "Y op X". -** -** If left/right precedence rules come into play when determining the -** collating sequence, then COLLATE operators are adjusted to ensure -** that the collating sequence does not change. For example: -** "Y collate NOCASE op X" becomes "X op Y" because any collation sequence on -** the left hand side of a comparison overrides any collation sequence -** attached to the right. For the same reason the EP_Collate flag -** is not commuted. -*/ -static void exprCommute(Parse *pParse, Expr *pExpr){ - u16 expRight = (pExpr->pRight->flags & EP_Collate); - u16 expLeft = (pExpr->pLeft->flags & EP_Collate); - assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN ); - if( expRight==expLeft ){ - /* Either X and Y both have COLLATE operator or neither do */ - if( expRight ){ - /* Both X and Y have COLLATE operators. Make sure X is always - ** used by clearing the EP_Collate flag from Y. */ - pExpr->pRight->flags &= ~EP_Collate; - }else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){ - /* Neither X nor Y have COLLATE operators, but X has a non-default - ** collating sequence. So add the EP_Collate marker on X to cause - ** it to be searched first. */ - pExpr->pLeft->flags |= EP_Collate; - } - } - SWAP(Expr*,pExpr->pRight,pExpr->pLeft); - if( pExpr->op>=TK_GT ){ - assert( TK_LT==TK_GT+2 ); - assert( TK_GE==TK_LE+2 ); - assert( TK_GT>TK_EQ ); - assert( TK_GTop>=TK_GT && pExpr->op<=TK_GE ); - pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT; - } -} - -/* -** Translate from TK_xx operator to WO_xx bitmask. -*/ -static u16 operatorMask(int op){ - u16 c; - assert( allowedOp(op) ); - if( op==TK_IN ){ - c = WO_IN; - }else if( op==TK_ISNULL ){ - c = WO_ISNULL; - }else if( op==TK_IS ){ - c = WO_IS; - }else{ - assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff ); - c = (u16)(WO_EQ<<(op-TK_EQ)); - } - assert( op!=TK_ISNULL || c==WO_ISNULL ); - assert( op!=TK_IN || c==WO_IN ); - assert( op!=TK_EQ || c==WO_EQ ); - assert( op!=TK_LT || c==WO_LT ); - assert( op!=TK_LE || c==WO_LE ); - assert( op!=TK_GT || c==WO_GT ); - assert( op!=TK_GE || c==WO_GE ); - assert( op!=TK_IS || c==WO_IS ); - return c; -} - /* ** Advance to the next WhereTerm that matches according to the criteria ** established when the pScan object was initialized by whereScanInit(). @@ -620,952 +342,6 @@ WhereTerm *sqlite3WhereFindTerm( return pResult; } -/* Forward reference */ -static void exprAnalyze(SrcList*, WhereClause*, int); - -/* -** Call exprAnalyze on all terms in a WHERE clause. -** -** Note that exprAnalyze() might add new virtual terms onto the -** end of the WHERE clause. We do not want to analyze these new -** virtual terms, so start analyzing at the end and work forward -** so that the added virtual terms are never processed. -*/ -static void exprAnalyzeAll( - SrcList *pTabList, /* the FROM clause */ - WhereClause *pWC /* the WHERE clause to be analyzed */ -){ - int i; - for(i=pWC->nTerm-1; i>=0; i--){ - exprAnalyze(pTabList, pWC, i); - } -} - -#ifndef SQLITE_OMIT_LIKE_OPTIMIZATION -/* -** Check to see if the given expression is a LIKE or GLOB operator that -** can be optimized using inequality constraints. Return TRUE if it is -** 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. 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.) 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 */ - Expr *pExpr, /* Test this expression */ - Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */ - int *pisComplete, /* True if the only wildcard is % in the last character */ - int *pnoCase /* True if uppercase is equivalent to lowercase */ -){ - const char *z = 0; /* String on RHS of LIKE operator */ - Expr *pRight, *pLeft; /* Right and left size of LIKE operator */ - ExprList *pList; /* List of operands to the LIKE operator */ - int c; /* One character in z[] */ - int cnt; /* Number of non-wildcard prefix characters */ - char wc[3]; /* Wildcard characters */ - sqlite3 *db = pParse->db; /* Database connection */ - sqlite3_value *pVal = 0; - int op; /* Opcode of pRight */ - - if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){ - return 0; - } -#ifdef SQLITE_EBCDIC - if( *pnoCase ) return 0; -#endif - pList = pExpr->x.pList; - pLeft = pList->a[1].pExpr; - if( pLeft->op!=TK_COLUMN - || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT - || 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. */ - return 0; - } - assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */ - - pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr); - op = pRight->op; - if( op==TK_VARIABLE ){ - Vdbe *pReprepare = pParse->pReprepare; - int iCol = pRight->iColumn; - pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB); - if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ - z = (char *)sqlite3_value_text(pVal); - } - sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); - assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); - }else if( op==TK_STRING ){ - z = pRight->u.zToken; - } - if( z ){ - cnt = 0; - while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ - cnt++; - } - if( cnt!=0 && 255!=(u8)z[cnt-1] ){ - Expr *pPrefix; - *pisComplete = c==wc[0] && z[cnt+1]==0; - pPrefix = sqlite3Expr(db, TK_STRING, z); - if( pPrefix ) pPrefix->u.zToken[cnt] = 0; - *ppPrefix = pPrefix; - if( op==TK_VARIABLE ){ - Vdbe *v = pParse->pVdbe; - sqlite3VdbeSetVarmask(v, pRight->iColumn); - if( *pisComplete && pRight->u.zToken[1] ){ - /* If the rhs of the LIKE expression is a variable, and the current - ** 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 work around them, add a dummy OP_Variable here. - */ - int r1 = sqlite3GetTempReg(pParse); - sqlite3ExprCodeTarget(pParse, pRight, r1); - sqlite3VdbeChangeP3(v, sqlite3VdbeCurrentAddr(v)-1, 0); - sqlite3ReleaseTempReg(pParse, r1); - } - } - }else{ - z = 0; - } - } - - sqlite3ValueFree(pVal); - return (z!=0); -} -#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ - - -#ifndef SQLITE_OMIT_VIRTUALTABLE -/* -** Check to see if the given expression is of the form -** -** column MATCH expr -** -** If it is then return TRUE. If not, return FALSE. -*/ -static int isMatchOfColumn( - Expr *pExpr /* Test this expression */ -){ - ExprList *pList; - - if( pExpr->op!=TK_FUNCTION ){ - return 0; - } - if( sqlite3StrICmp(pExpr->u.zToken,"match")!=0 ){ - return 0; - } - pList = pExpr->x.pList; - if( pList->nExpr!=2 ){ - return 0; - } - if( pList->a[1].pExpr->op != TK_COLUMN ){ - return 0; - } - return 1; -} -#endif /* SQLITE_OMIT_VIRTUALTABLE */ - -/* -** If the pBase expression originated in the ON or USING clause of -** a join, then transfer the appropriate markings over to derived. -*/ -static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ - if( pDerived ){ - pDerived->flags |= pBase->flags & EP_FromJoin; - pDerived->iRightJoinTable = pBase->iRightJoinTable; - } -} - -/* -** 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++; -} - -/* -** 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 -** subterms. So in: -** -** ... WHERE (a=5) AND (b=7 OR c=9 OR d=13) AND (d=13) -** ^^^^^^^^^^^^^^^^^^^^ -** -** This routine analyzes terms such as the middle term in the above example. -** A WhereOrTerm object is computed and attached to the term under -** analysis, regardless of the outcome of the analysis. Hence: -** -** WhereTerm.wtFlags |= TERM_ORINFO -** WhereTerm.u.pOrInfo = a dynamically allocated WhereOrTerm object -** -** The term being analyzed must have two or more of OR-connected subterms. -** A single subterm might be a set of AND-connected sub-subterms. -** Examples of terms under analysis: -** -** (A) t1.x=t2.y OR t1.x=t2.z OR t1.y=15 OR t1.z=t3.a+5 -** (B) x=expr1 OR expr2=x OR x=expr3 -** (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: -** -** If all subterms are of the form T.C=expr for some single column of C and -** a single table T (as shown in example B above) then create a new virtual -** term that is an equivalent IN expression. In other words, if the term -** being analyzed is: -** -** x = expr1 OR expr2 = x OR x = expr3 -** -** then create a new virtual term like this: -** -** x IN (expr1,expr2,expr3) -** -** CASE 2: -** -** If there are exactly two disjuncts and 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 -** WhereTerm.u.pOrInfo->indexable |= the cursor number for table T -** -** A subterm is "indexable" if it is of the form -** "T.C " where C is any column of table T and -** is one of "=", "<", "<=", ">", ">=", "IS NULL", or "IN". -** A subterm is also indexable if it is an AND of two or more -** subsubterms at least one of which is indexable. Indexable AND -** subterms have their eOperator set to WO_AND and they have -** u.pAndInfo set to a dynamically allocated WhereAndTerm object. -** -** From another point of view, "indexable" means that the subterm could -** potentially be used with an index if an appropriate index exists. -** This analysis does not consider whether or not the index exists; that -** is decided elsewhere. This analysis only looks at whether subterms -** appropriate for indexing exist. -** -** All examples A through E above satisfy case 3. But if a term -** 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 3 is not -** satisfied. -** -** It might be the case that multiple tables are indexable. For example, -** (E) above is indexable on tables P, Q, and R. -** -** Terms that satisfy case 3 are candidates for lookup by using -** separate indices to find rowids for each subterm and composing -** the union of all rowids using a RowSet object. This is similar -** to "bitmap indices" in other database engines. -** -** OTHERWISE: -** -** If none of cases 1, 2, or 3 apply, then leave the eOperator set to -** zero. This term is not useful for search. -*/ -static void exprAnalyzeOrTerm( - SrcList *pSrc, /* the FROM clause */ - WhereClause *pWC, /* the complete WHERE clause */ - int idxTerm /* Index of the OR-term to be analyzed */ -){ - WhereInfo *pWInfo = pWC->pWInfo; /* WHERE clause processing context */ - Parse *pParse = pWInfo->pParse; /* Parser context */ - sqlite3 *db = pParse->db; /* Database connection */ - WhereTerm *pTerm = &pWC->a[idxTerm]; /* The term to be analyzed */ - Expr *pExpr = pTerm->pExpr; /* The expression of the term */ - int i; /* Loop counters */ - WhereClause *pOrWc; /* Breakup of pTerm into subterms */ - WhereTerm *pOrTerm; /* A Sub-term within the pOrWc */ - WhereOrInfo *pOrInfo; /* Additional information associated with pTerm */ - Bitmask chngToIN; /* Tables that might satisfy case 1 */ - Bitmask indexable; /* Tables that are indexable, satisfying case 2 */ - - /* - ** Break the OR clause into its separate subterms. The subterms are - ** stored in a WhereClause structure containing within the WhereOrInfo - ** object that is attached to the original OR clause term. - */ - assert( (pTerm->wtFlags & (TERM_DYNAMIC|TERM_ORINFO|TERM_ANDINFO))==0 ); - assert( pExpr->op==TK_OR ); - pTerm->u.pOrInfo = pOrInfo = sqlite3DbMallocZero(db, sizeof(*pOrInfo)); - if( pOrInfo==0 ) return; - pTerm->wtFlags |= TERM_ORINFO; - pOrWc = &pOrInfo->wc; - whereClauseInit(pOrWc, pWInfo); - whereSplit(pOrWc, pExpr, TK_OR); - exprAnalyzeAll(pSrc, pOrWc); - if( db->mallocFailed ) return; - assert( pOrWc->nTerm>=2 ); - - /* - ** Compute the set of tables that might satisfy cases 1 or 3. - */ - indexable = ~(Bitmask)0; - chngToIN = ~(Bitmask)0; - for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){ - if( (pOrTerm->eOperator & WO_SINGLE)==0 ){ - WhereAndInfo *pAndInfo; - assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 ); - chngToIN = 0; - pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo)); - if( pAndInfo ){ - WhereClause *pAndWC; - WhereTerm *pAndTerm; - int j; - Bitmask b = 0; - pOrTerm->u.pAndInfo = pAndInfo; - pOrTerm->wtFlags |= TERM_ANDINFO; - pOrTerm->eOperator = WO_AND; - pAndWC = &pAndInfo->wc; - whereClauseInit(pAndWC, pWC->pWInfo); - whereSplit(pAndWC, pOrTerm->pExpr, TK_AND); - exprAnalyzeAll(pSrc, pAndWC); - pAndWC->pOuter = pWC; - testcase( db->mallocFailed ); - if( !db->mallocFailed ){ - for(j=0, pAndTerm=pAndWC->a; jnTerm; j++, pAndTerm++){ - assert( pAndTerm->pExpr ); - if( allowedOp(pAndTerm->pExpr->op) ){ - b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); - } - } - } - indexable &= b; - } - }else if( pOrTerm->wtFlags & TERM_COPIED ){ - /* Skip this term for now. We revisit it when we process the - ** corresponding TERM_VIRTUAL term */ - }else{ - Bitmask b; - b = sqlite3WhereGetMask(&pWInfo->sMaskSet, pOrTerm->leftCursor); - if( pOrTerm->wtFlags & TERM_VIRTUAL ){ - WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent]; - b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pOther->leftCursor); - } - indexable &= b; - if( (pOrTerm->eOperator & WO_EQ)==0 ){ - chngToIN = 0; - }else{ - chngToIN &= b; - } - } - } - - /* - ** 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 - ** is satisfied. - ** - ** chngToIN will hold either 0, 1, or 2 bits. The 0-bit case means - ** that there is no possibility of transforming the OR clause into an - ** IN operator because one or more terms in the OR clause contain - ** something other than == on a column in the single table. The 1-bit - ** case means that every term of the OR clause is of the form - ** "table.column=expr" for some single table. The one bit that is set - ** will correspond to the common table. We still need to check to make - ** sure the same column is used on all terms. The 2-bit case is when - ** the all terms are of the form "table1.column=table2.column". It - ** might be possible to form an IN operator with either table1.column - ** or table2.column as the LHS if either is common to every term of - ** the OR clause. - ** - ** Note that terms of the form "table.column1=table.column2" (the - ** same table on both sizes of the ==) cannot be optimized. - */ - if( chngToIN ){ - int okToChngToIN = 0; /* True if the conversion to IN is valid */ - int iColumn = -1; /* Column index on lhs of IN operator */ - int iCursor = -1; /* Table cursor common to all terms */ - int j = 0; /* Loop counter */ - - /* Search for a table and column that appears on one side or the - ** other of the == operator in every subterm. That table and column - ** will be recorded in iCursor and iColumn. There might not be any - ** such table and column. Set okToChngToIN if an appropriate table - ** and column is found but leave okToChngToIN false if not found. - */ - for(j=0; j<2 && !okToChngToIN; j++){ - pOrTerm = pOrWc->a; - for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ - assert( pOrTerm->eOperator & WO_EQ ); - pOrTerm->wtFlags &= ~TERM_OR_OK; - if( pOrTerm->leftCursor==iCursor ){ - /* This is the 2-bit case and we are on the second iteration and - ** current term is from the first iteration. So skip this term. */ - assert( j==1 ); - continue; - } - if( (chngToIN & sqlite3WhereGetMask(&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 preceded - ** or follwed by an inverted copy (t2.b==t1.a). Skip this term - ** and use its inversion. */ - testcase( pOrTerm->wtFlags & TERM_COPIED ); - testcase( pOrTerm->wtFlags & TERM_VIRTUAL ); - assert( pOrTerm->wtFlags & (TERM_COPIED|TERM_VIRTUAL) ); - continue; - } - iColumn = pOrTerm->u.leftColumn; - iCursor = pOrTerm->leftCursor; - break; - } - if( i<0 ){ - /* No candidate table+column was found. This can only occur - ** on the second iteration */ - assert( j==1 ); - assert( IsPowerOfTwo(chngToIN) ); - assert( chngToIN==sqlite3WhereGetMask(&pWInfo->sMaskSet, iCursor) ); - break; - } - testcase( j==1 ); - - /* We have found a candidate table and column. Check to see if that - ** table and column is common to every term in the OR clause */ - okToChngToIN = 1; - for(; i>=0 && okToChngToIN; i--, pOrTerm++){ - assert( pOrTerm->eOperator & WO_EQ ); - if( pOrTerm->leftCursor!=iCursor ){ - pOrTerm->wtFlags &= ~TERM_OR_OK; - }else if( pOrTerm->u.leftColumn!=iColumn ){ - okToChngToIN = 0; - }else{ - int affLeft, affRight; - /* If the right-hand side is also a column, then the affinities - ** of both right and left sides must be such that no type - ** conversions are required on the right. (Ticket #2249) - */ - affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight); - affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft); - if( affRight!=0 && affRight!=affLeft ){ - okToChngToIN = 0; - }else{ - pOrTerm->wtFlags |= TERM_OR_OK; - } - } - } - } - - /* At this point, okToChngToIN is true if original pTerm satisfies - ** case 1. In that case, construct a new virtual term that is - ** pTerm converted into an IN operator. - */ - if( okToChngToIN ){ - Expr *pDup; /* A transient duplicate expression */ - ExprList *pList = 0; /* The RHS of the IN operator */ - Expr *pLeft = 0; /* The LHS of the IN operator */ - Expr *pNew; /* The complete IN operator */ - - for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ - if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; - assert( pOrTerm->eOperator & WO_EQ ); - assert( pOrTerm->leftCursor==iCursor ); - assert( pOrTerm->u.leftColumn==iColumn ); - pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); - pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup); - pLeft = pOrTerm->pExpr->pLeft; - } - assert( pLeft!=0 ); - pDup = sqlite3ExprDup(db, pLeft, 0); - pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0, 0); - if( pNew ){ - int idxNew; - transferJoinMarkings(pNew, pExpr); - assert( !ExprHasProperty(pNew, EP_xIsSelect) ); - pNew->x.pList = pList; - idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); - testcase( idxNew==0 ); - exprAnalyze(pSrc, pWC, idxNew); - pTerm = &pWC->a[idxTerm]; - markTermAsChild(pWC, idxNew, idxTerm); - }else{ - sqlite3ExprListDelete(db, pList); - } - pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */ - } - } -} -#endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */ - -/* -** We already know that pExpr is a binary operator where both operands are -** column references. This routine checks to see if pExpr is an equivalence -** relation: -** 1. The SQLITE_Transitive optimization must be enabled -** 2. Must be either an == or an IS operator -** 3. Not originating in the ON clause of an OUTER JOIN -** 4. The affinities of A and B must be compatible -** 5a. Both operands use the same collating sequence OR -** 5b. The overall collating sequence is BINARY -** If this routine returns TRUE, that means that the RHS can be substituted -** for the LHS anyplace else in the WHERE clause where the LHS column occurs. -** This is an optimization. No harm comes from returning 0. But if 1 is -** returned when it should not be, then incorrect answers might result. -*/ -static int termIsEquivalence(Parse *pParse, Expr *pExpr){ - char aff1, aff2; - CollSeq *pColl; - const char *zColl1, *zColl2; - if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; - if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; - if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; - aff1 = sqlite3ExprAffinity(pExpr->pLeft); - aff2 = sqlite3ExprAffinity(pExpr->pRight); - if( aff1!=aff2 - && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) - ){ - return 0; - } - pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); - if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1; - pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); - /* Since pLeft and pRight are both a column references, their collating - ** sequence should always be defined. */ - zColl1 = ALWAYS(pColl) ? pColl->zName : 0; - pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight); - zColl2 = ALWAYS(pColl) ? pColl->zName : 0; - return sqlite3StrICmp(zColl1, zColl2)==0; -} - -/* -** The input to this routine is an WhereTerm structure with only the -** "pExpr" field filled in. The job of this routine is to analyze the -** subexpression and populate all the other fields of the WhereTerm -** structure. -** -** If the expression is of the form " X" it gets commuted -** to the standard form of "X ". -** -** If the expression is of the form "X Y" where both X and Y are -** columns, then the original expression is unchanged and a new virtual -** term of the form "Y X" is added to the WHERE clause and -** analyzed separately. The original term is marked with TERM_COPIED -** and the new term is marked with TERM_DYNAMIC (because it's pExpr -** needs to be freed with the WhereClause) and TERM_VIRTUAL (because it -** is a commuted copy of a prior term.) The original term has nChild=1 -** and the copy has idxParent set to the index of the original term. -*/ -static void exprAnalyze( - SrcList *pSrc, /* the FROM clause */ - WhereClause *pWC, /* the WHERE clause */ - int idxTerm /* Index of the term to be analyzed */ -){ - WhereInfo *pWInfo = pWC->pWInfo; /* WHERE clause processing context */ - WhereTerm *pTerm; /* The term to be analyzed */ - WhereMaskSet *pMaskSet; /* Set of table index masks */ - Expr *pExpr; /* The expression to be analyzed */ - Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */ - Bitmask prereqAll; /* Prerequesites of pExpr */ - 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; /* uppercase equivalent to lowercase */ - int op; /* Top-level operator. pExpr->op */ - Parse *pParse = pWInfo->pParse; /* Parsing context */ - sqlite3 *db = pParse->db; /* Database connection */ - - if( db->mallocFailed ){ - return; - } - pTerm = &pWC->a[idxTerm]; - pMaskSet = &pWInfo->sMaskSet; - pExpr = pTerm->pExpr; - assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE ); - prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft); - op = pExpr->op; - if( op==TK_IN ){ - assert( pExpr->pRight==0 ); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - pTerm->prereqRight = exprSelectTableUsage(pMaskSet, pExpr->x.pSelect); - }else{ - pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->x.pList); - } - }else if( op==TK_ISNULL ){ - pTerm->prereqRight = 0; - }else{ - pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight); - } - prereqAll = exprTableUsage(pMaskSet, pExpr); - if( ExprHasProperty(pExpr, EP_FromJoin) ){ - Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable); - prereqAll |= x; - extraRight = x-1; /* ON clause terms may not be used with an index - ** on left table of a LEFT JOIN. Ticket #3015 */ - } - pTerm->prereqAll = prereqAll; - pTerm->leftCursor = -1; - pTerm->iParent = -1; - pTerm->eOperator = 0; - if( allowedOp(op) ){ - Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); - Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); - u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; - if( pLeft->op==TK_COLUMN ){ - pTerm->leftCursor = pLeft->iTable; - pTerm->u.leftColumn = pLeft->iColumn; - pTerm->eOperator = operatorMask(op) & opMask; - } - if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; - if( pRight && pRight->op==TK_COLUMN ){ - WhereTerm *pNew; - Expr *pDup; - u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ - if( pTerm->leftCursor>=0 ){ - int idxNew; - pDup = sqlite3ExprDup(db, pExpr, 0); - if( db->mallocFailed ){ - sqlite3ExprDelete(db, pDup); - return; - } - idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC); - if( idxNew==0 ) return; - pNew = &pWC->a[idxNew]; - markTermAsChild(pWC, idxNew, idxTerm); - if( op==TK_IS ) pNew->wtFlags |= TERM_IS; - pTerm = &pWC->a[idxTerm]; - pTerm->wtFlags |= TERM_COPIED; - - if( termIsEquivalence(pParse, pDup) ){ - pTerm->eOperator |= WO_EQUIV; - eExtraOp = WO_EQUIV; - } - }else{ - pDup = pExpr; - pNew = pTerm; - } - exprCommute(pParse, pDup); - pLeft = sqlite3ExprSkipCollate(pDup->pLeft); - pNew->leftCursor = pLeft->iTable; - pNew->u.leftColumn = pLeft->iColumn; - testcase( (prereqLeft | extraRight) != prereqLeft ); - pNew->prereqRight = prereqLeft | extraRight; - pNew->prereqAll = prereqAll; - pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; - } - } - -#ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION - /* If a term is the BETWEEN operator, create two new virtual terms - ** that define the range that the BETWEEN implements. For example: - ** - ** a BETWEEN b AND c - ** - ** is converted into: - ** - ** (a BETWEEN b AND c) AND (a>=b) AND (a<=c) - ** - ** The two new terms are added onto the end of the WhereClause object. - ** The new terms are "dynamic" and are children of the original BETWEEN - ** term. That means that if the BETWEEN term is coded, the children are - ** skipped. Or, if the children are satisfied by an index, the original - ** BETWEEN term is skipped. - */ - else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){ - ExprList *pList = pExpr->x.pList; - int i; - static const u8 ops[] = {TK_GE, TK_LE}; - assert( pList!=0 ); - assert( pList->nExpr==2 ); - for(i=0; i<2; i++){ - Expr *pNewExpr; - int idxNew; - pNewExpr = sqlite3PExpr(pParse, ops[i], - sqlite3ExprDup(db, pExpr->pLeft, 0), - sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0); - transferJoinMarkings(pNewExpr, pExpr); - idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); - testcase( idxNew==0 ); - exprAnalyze(pSrc, pWC, idxNew); - pTerm = &pWC->a[idxTerm]; - markTermAsChild(pWC, idxNew, idxTerm); - } - } -#endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */ - -#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) - /* Analyze a term that is composed of two or more subterms connected by - ** an OR operator. - */ - else if( pExpr->op==TK_OR ){ - assert( pWC->op==TK_AND ); - exprAnalyzeOrTerm(pSrc, pWC, idxTerm); - pTerm = &pWC->a[idxTerm]; - } -#endif /* SQLITE_OMIT_OR_OPTIMIZATION */ - -#ifndef SQLITE_OMIT_LIKE_OPTIMIZATION - /* 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 - ** - ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%' - ** - ** The last character of the prefix "abc" is incremented to form the - ** 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) - ){ - Expr *pLeft; /* LHS of LIKE/GLOB operator */ - Expr *pStr2; /* Copy of pStr1 - RHS of LIKE/GLOB operator */ - Expr *pNewExpr1; - Expr *pNewExpr2; - int idxNew1; - int idxNew2; - 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]; - c = *pC; - if( noCase ){ - /* The point is to increment the last character before the first - ** wildcard. But if we increment '@', that will push it into the - ** alphabetic range where case conversions will mess up the - ** inequality. To avoid this, make sure to also run the full - ** LIKE on all candidate expressions by clearing the isComplete flag - */ - if( c=='A'-1 ) isComplete = 0; - c = sqlite3UpperToLower[c]; - } - *pC = c + 1; - } - zCollSeqName = noCase ? "NOCASE" : "BINARY"; - pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); - pNewExpr1 = sqlite3PExpr(pParse, TK_GE, - sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), - pStr1, 0); - transferJoinMarkings(pNewExpr1, pExpr); - idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); - testcase( idxNew1==0 ); - exprAnalyze(pSrc, pWC, idxNew1); - pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); - pNewExpr2 = sqlite3PExpr(pParse, TK_LT, - sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName), - pStr2, 0); - transferJoinMarkings(pNewExpr2, pExpr); - idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); - testcase( idxNew2==0 ); - exprAnalyze(pSrc, pWC, idxNew2); - pTerm = &pWC->a[idxTerm]; - if( isComplete ){ - markTermAsChild(pWC, idxNew1, idxTerm); - markTermAsChild(pWC, idxNew2, idxTerm); - } - } -#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ - -#ifndef SQLITE_OMIT_VIRTUALTABLE - /* Add a WO_MATCH auxiliary term to the constraint set if the - ** current expression is of the form: column MATCH expr. - ** This information is used by the xBestIndex methods of - ** virtual tables. The native query optimizer does not attempt - ** to do anything with MATCH functions. - */ - if( isMatchOfColumn(pExpr) ){ - int idxNew; - Expr *pRight, *pLeft; - WhereTerm *pNewTerm; - Bitmask prereqColumn, prereqExpr; - - pRight = pExpr->x.pList->a[0].pExpr; - pLeft = pExpr->x.pList->a[1].pExpr; - prereqExpr = exprTableUsage(pMaskSet, pRight); - prereqColumn = exprTableUsage(pMaskSet, pLeft); - if( (prereqExpr & prereqColumn)==0 ){ - Expr *pNewExpr; - pNewExpr = sqlite3PExpr(pParse, TK_MATCH, - 0, sqlite3ExprDup(db, pRight, 0), 0); - idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); - testcase( idxNew==0 ); - pNewTerm = &pWC->a[idxNew]; - pNewTerm->prereqRight = prereqExpr; - pNewTerm->leftCursor = pLeft->iTable; - pNewTerm->u.leftColumn = pLeft->iColumn; - pNewTerm->eOperator = WO_MATCH; - markTermAsChild(pWC, idxNew, idxTerm); - pTerm = &pWC->a[idxTerm]; - pTerm->wtFlags |= TERM_COPIED; - pNewTerm->prereqAll = pTerm->prereqAll; - } - } -#endif /* SQLITE_OMIT_VIRTUALTABLE */ - -#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 - /* When sqlite_stat3 histogram data is available an operator of the - ** form "x IS NOT NULL" can sometimes be evaluated more efficiently - ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a - ** virtual term of that form. - ** - ** Note that the virtual term must be tagged with TERM_VNULL. - */ - if( pExpr->op==TK_NOTNULL - && pExpr->pLeft->op==TK_COLUMN - && pExpr->pLeft->iColumn>=0 - && OptimizationEnabled(db, SQLITE_Stat34) - ){ - Expr *pNewExpr; - Expr *pLeft = pExpr->pLeft; - int idxNew; - WhereTerm *pNewTerm; - - pNewExpr = sqlite3PExpr(pParse, TK_GT, - sqlite3ExprDup(db, pLeft, 0), - sqlite3PExpr(pParse, TK_NULL, 0, 0, 0), 0); - - idxNew = whereClauseInsert(pWC, pNewExpr, - TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL); - if( idxNew ){ - pNewTerm = &pWC->a[idxNew]; - pNewTerm->prereqRight = 0; - pNewTerm->leftCursor = pLeft->iTable; - pNewTerm->u.leftColumn = pLeft->iColumn; - pNewTerm->eOperator = WO_GT; - markTermAsChild(pWC, idxNew, idxTerm); - pTerm = &pWC->a[idxTerm]; - pTerm->wtFlags |= TERM_COPIED; - pNewTerm->prereqAll = pTerm->prereqAll; - } - } -#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ - - /* Prevent ON clause terms of a LEFT JOIN from being used to drive - ** an index for tables to the left of the join. - */ - pTerm->prereqRight |= extraRight; -} - /* ** This function searches pList for an entry that matches the iCol-th column ** of index pIdx. @@ -2938,7 +1714,7 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){ sqlite3DbFree(db, pLevel->u.in.aInLoop); } } - whereClauseClear(&pWInfo->sWC); + sqlite3WhereClauseClear(&pWInfo->sWC); while( pWInfo->pLoops ){ WhereLoop *p = pWInfo->pLoops; pWInfo->pLoops = p->pNextLoop; @@ -4456,7 +3232,7 @@ static i8 wherePathSatisfiesOrderBy( Bitmask mTerm; if( MASKBIT(i) & obSat ) continue; p = pOrderBy->a[i].pExpr; - mTerm = exprTableUsage(&pWInfo->sMaskSet,p); + mTerm = sqlite3WhereExprUsage(&pWInfo->sMaskSet,p); if( mTerm==0 && !sqlite3ExprIsConstant(p) ) continue; if( (mTerm&~orderDistinctMask)==0 ){ obSat |= MASKBIT(i); @@ -5169,8 +3945,8 @@ WhereInfo *sqlite3WhereBegin( ** subexpression is separated by an AND operator. */ initMaskSet(pMaskSet); - whereClauseInit(&pWInfo->sWC, pWInfo); - whereSplit(&pWInfo->sWC, pWhere, TK_AND); + sqlite3WhereClauseInit(&pWInfo->sWC, pWInfo); + sqlite3WhereSplit(&pWInfo->sWC, pWhere, TK_AND); /* Special case: a WHERE clause that is constant. Evaluate the ** expression and either jump over all of the code or fall thru. @@ -5223,7 +3999,7 @@ WhereInfo *sqlite3WhereBegin( #endif /* Analyze all of the subexpressions. */ - exprAnalyzeAll(pTabList, &pWInfo->sWC); + sqlite3WhereExprAnalyze(pTabList, &pWInfo->sWC); if( db->mallocFailed ) goto whereBeginError; if( wctrlFlags & WHERE_WANT_DISTINCT ){ @@ -5309,8 +4085,10 @@ WhereInfo *sqlite3WhereBegin( && pResultSet!=0 && OptimizationEnabled(db, SQLITE_OmitNoopJoin) ){ - Bitmask tabUsed = exprListTableUsage(pMaskSet, pResultSet); - if( sWLB.pOrderBy ) tabUsed |= exprListTableUsage(pMaskSet, sWLB.pOrderBy); + Bitmask tabUsed = sqlite3WhereExprListUsage(pMaskSet, pResultSet); + if( sWLB.pOrderBy ){ + tabUsed |= sqlite3WhereExprListUsage(pMaskSet, sWLB.pOrderBy); + } while( pWInfo->nLevel>=2 ){ WhereTerm *pTerm, *pEnd; pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop; diff --git a/src/whereInt.h b/src/whereInt.h index 075deed4a2..8929d8c4be 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -368,6 +368,11 @@ struct WhereMaskSet { int ix[BMS]; /* Cursor assigned to each bit */ }; +/* +** Initialize a WhereMaskSet object +*/ +#define initMaskSet(P) (P)->n=0 + /* ** This object is a convenience wrapper holding all information needed ** to construct WhereLoop objects for a particular query. @@ -421,6 +426,8 @@ struct WhereInfo { /* ** Private interfaces - callable only by other where.c routines. +** +** where.c: */ Bitmask sqlite3WhereGetMask(WhereMaskSet*,int); WhereTerm *sqlite3WhereFindTerm( @@ -431,6 +438,8 @@ WhereTerm *sqlite3WhereFindTerm( u32 op, /* Mask of WO_xx values describing operator */ Index *pIdx /* Must be compatible with this index, if not NULL */ ); + +/* wherecode.c: */ #ifndef SQLITE_OMIT_EXPLAIN int sqlite3WhereExplainOneScan( Parse *pParse, /* Parse context */ @@ -459,7 +468,13 @@ Bitmask sqlite3WhereCodeOneLoopStart( Bitmask notReady /* Which tables are currently available */ ); - +/* whereexpr.c: */ +void sqlite3WhereClauseInit(WhereClause*,WhereInfo*); +void sqlite3WhereClauseClear(WhereClause*); +void sqlite3WhereSplit(WhereClause*,Expr*,u8); +Bitmask sqlite3WhereExprUsage(WhereMaskSet*, Expr*); +Bitmask sqlite3WhereExprListUsage(WhereMaskSet*, ExprList*); +void sqlite3WhereExprAnalyze(SrcList*, WhereClause*); diff --git a/src/whereexpr.c b/src/whereexpr.c new file mode 100644 index 0000000000..3607ef5352 --- /dev/null +++ b/src/whereexpr.c @@ -0,0 +1,1249 @@ +/* +** 2015-06-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 module contains C code that generates VDBE code used to process +** the WHERE clause of SQL statements. +** +** This file was originally part of where.c but was split out to improve +** readability and editabiliity. This file contains utility routines for +** analyzing Expr objects in the WHERE clause. +*/ +#include "sqliteInt.h" +#include "whereInt.h" + +/* Forward declarations */ +static void exprAnalyze(SrcList*, WhereClause*, int); + +/* +** Deallocate all memory associated with a WhereOrInfo object. +*/ +static void whereOrInfoDelete(sqlite3 *db, WhereOrInfo *p){ + sqlite3WhereClauseClear(&p->wc); + sqlite3DbFree(db, p); +} + +/* +** Deallocate all memory associated with a WhereAndInfo object. +*/ +static void whereAndInfoDelete(sqlite3 *db, WhereAndInfo *p){ + sqlite3WhereClauseClear(&p->wc); + sqlite3DbFree(db, p); +} + +/* +** Add a single new WhereTerm entry to the WhereClause object pWC. +** The new WhereTerm object is constructed from Expr p and with wtFlags. +** The index in pWC->a[] of the new WhereTerm is returned on success. +** 0 is returned if the new WhereTerm could not be added due to a memory +** allocation error. The memory allocation failure will be recorded in +** the db->mallocFailed flag so that higher-level functions can detect it. +** +** This routine will increase the size of the pWC->a[] array as necessary. +** +** If the wtFlags argument includes TERM_DYNAMIC, then responsibility +** for freeing the expression p is assumed by the WhereClause object pWC. +** This is true even if this routine fails to allocate a new WhereTerm. +** +** WARNING: This routine might reallocate the space used to store +** WhereTerms. All pointers to WhereTerms should be invalidated after +** calling this routine. Such pointers may be reinitialized by referencing +** the pWC->a[] array. +*/ +static int whereClauseInsert(WhereClause *pWC, Expr *p, u16 wtFlags){ + WhereTerm *pTerm; + int idx; + testcase( wtFlags & TERM_VIRTUAL ); + if( pWC->nTerm>=pWC->nSlot ){ + WhereTerm *pOld = pWC->a; + sqlite3 *db = pWC->pWInfo->pParse->db; + pWC->a = sqlite3DbMallocRaw(db, sizeof(pWC->a[0])*pWC->nSlot*2 ); + if( pWC->a==0 ){ + if( wtFlags & TERM_DYNAMIC ){ + sqlite3ExprDelete(db, p); + } + pWC->a = pOld; + return 0; + } + memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm); + if( pOld!=pWC->aStatic ){ + 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) - 270; + }else{ + pTerm->truthProb = 1; + } + pTerm->pExpr = sqlite3ExprSkipCollate(p); + pTerm->wtFlags = wtFlags; + pTerm->pWC = pWC; + pTerm->iParent = -1; + return idx; +} + +/* +** Return TRUE if the given operator is one of the operators that is +** allowed for an indexable WHERE clause term. The allowed operators are +** "=", "<", ">", "<=", ">=", "IN", and "IS NULL" +*/ +static int allowedOp(int op){ + assert( TK_GT>TK_EQ && TK_GTTK_EQ && TK_LTTK_EQ && TK_LE=TK_EQ && op<=TK_GE) || op==TK_ISNULL || op==TK_IS; +} + +/* +** Commute a comparison operator. Expressions of the form "X op Y" +** are converted into "Y op X". +** +** If left/right precedence rules come into play when determining the +** collating sequence, then COLLATE operators are adjusted to ensure +** that the collating sequence does not change. For example: +** "Y collate NOCASE op X" becomes "X op Y" because any collation sequence on +** the left hand side of a comparison overrides any collation sequence +** attached to the right. For the same reason the EP_Collate flag +** is not commuted. +*/ +static void exprCommute(Parse *pParse, Expr *pExpr){ + u16 expRight = (pExpr->pRight->flags & EP_Collate); + u16 expLeft = (pExpr->pLeft->flags & EP_Collate); + assert( allowedOp(pExpr->op) && pExpr->op!=TK_IN ); + if( expRight==expLeft ){ + /* Either X and Y both have COLLATE operator or neither do */ + if( expRight ){ + /* Both X and Y have COLLATE operators. Make sure X is always + ** used by clearing the EP_Collate flag from Y. */ + pExpr->pRight->flags &= ~EP_Collate; + }else if( sqlite3ExprCollSeq(pParse, pExpr->pLeft)!=0 ){ + /* Neither X nor Y have COLLATE operators, but X has a non-default + ** collating sequence. So add the EP_Collate marker on X to cause + ** it to be searched first. */ + pExpr->pLeft->flags |= EP_Collate; + } + } + SWAP(Expr*,pExpr->pRight,pExpr->pLeft); + if( pExpr->op>=TK_GT ){ + assert( TK_LT==TK_GT+2 ); + assert( TK_GE==TK_LE+2 ); + assert( TK_GT>TK_EQ ); + assert( TK_GTop>=TK_GT && pExpr->op<=TK_GE ); + pExpr->op = ((pExpr->op-TK_GT)^2)+TK_GT; + } +} + +/* +** Translate from TK_xx operator to WO_xx bitmask. +*/ +static u16 operatorMask(int op){ + u16 c; + assert( allowedOp(op) ); + if( op==TK_IN ){ + c = WO_IN; + }else if( op==TK_ISNULL ){ + c = WO_ISNULL; + }else if( op==TK_IS ){ + c = WO_IS; + }else{ + assert( (WO_EQ<<(op-TK_EQ)) < 0x7fff ); + c = (u16)(WO_EQ<<(op-TK_EQ)); + } + assert( op!=TK_ISNULL || c==WO_ISNULL ); + assert( op!=TK_IN || c==WO_IN ); + assert( op!=TK_EQ || c==WO_EQ ); + assert( op!=TK_LT || c==WO_LT ); + assert( op!=TK_LE || c==WO_LE ); + assert( op!=TK_GT || c==WO_GT ); + assert( op!=TK_GE || c==WO_GE ); + assert( op!=TK_IS || c==WO_IS ); + return c; +} + + +#ifndef SQLITE_OMIT_LIKE_OPTIMIZATION +/* +** Check to see if the given expression is a LIKE or GLOB operator that +** can be optimized using inequality constraints. Return TRUE if it is +** 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. 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.) 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 */ + Expr *pExpr, /* Test this expression */ + Expr **ppPrefix, /* Pointer to TK_STRING expression with pattern prefix */ + int *pisComplete, /* True if the only wildcard is % in the last character */ + int *pnoCase /* True if uppercase is equivalent to lowercase */ +){ + const char *z = 0; /* String on RHS of LIKE operator */ + Expr *pRight, *pLeft; /* Right and left size of LIKE operator */ + ExprList *pList; /* List of operands to the LIKE operator */ + int c; /* One character in z[] */ + int cnt; /* Number of non-wildcard prefix characters */ + char wc[3]; /* Wildcard characters */ + sqlite3 *db = pParse->db; /* Database connection */ + sqlite3_value *pVal = 0; + int op; /* Opcode of pRight */ + + if( !sqlite3IsLikeFunction(db, pExpr, pnoCase, wc) ){ + return 0; + } +#ifdef SQLITE_EBCDIC + if( *pnoCase ) return 0; +#endif + pList = pExpr->x.pList; + pLeft = pList->a[1].pExpr; + if( pLeft->op!=TK_COLUMN + || sqlite3ExprAffinity(pLeft)!=SQLITE_AFF_TEXT + || 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. */ + return 0; + } + assert( pLeft->iColumn!=(-1) ); /* Because IPK never has AFF_TEXT */ + + pRight = sqlite3ExprSkipCollate(pList->a[0].pExpr); + op = pRight->op; + if( op==TK_VARIABLE ){ + Vdbe *pReprepare = pParse->pReprepare; + int iCol = pRight->iColumn; + pVal = sqlite3VdbeGetBoundValue(pReprepare, iCol, SQLITE_AFF_BLOB); + if( pVal && sqlite3_value_type(pVal)==SQLITE_TEXT ){ + z = (char *)sqlite3_value_text(pVal); + } + sqlite3VdbeSetVarmask(pParse->pVdbe, iCol); + assert( pRight->op==TK_VARIABLE || pRight->op==TK_REGISTER ); + }else if( op==TK_STRING ){ + z = pRight->u.zToken; + } + if( z ){ + cnt = 0; + while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ + cnt++; + } + if( cnt!=0 && 255!=(u8)z[cnt-1] ){ + Expr *pPrefix; + *pisComplete = c==wc[0] && z[cnt+1]==0; + pPrefix = sqlite3Expr(db, TK_STRING, z); + if( pPrefix ) pPrefix->u.zToken[cnt] = 0; + *ppPrefix = pPrefix; + if( op==TK_VARIABLE ){ + Vdbe *v = pParse->pVdbe; + sqlite3VdbeSetVarmask(v, pRight->iColumn); + if( *pisComplete && pRight->u.zToken[1] ){ + /* If the rhs of the LIKE expression is a variable, and the current + ** 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 work around them, add a dummy OP_Variable here. + */ + int r1 = sqlite3GetTempReg(pParse); + sqlite3ExprCodeTarget(pParse, pRight, r1); + sqlite3VdbeChangeP3(v, sqlite3VdbeCurrentAddr(v)-1, 0); + sqlite3ReleaseTempReg(pParse, r1); + } + } + }else{ + z = 0; + } + } + + sqlite3ValueFree(pVal); + return (z!=0); +} +#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ + + +#ifndef SQLITE_OMIT_VIRTUALTABLE +/* +** Check to see if the given expression is of the form +** +** column MATCH expr +** +** If it is then return TRUE. If not, return FALSE. +*/ +static int isMatchOfColumn( + Expr *pExpr /* Test this expression */ +){ + ExprList *pList; + + if( pExpr->op!=TK_FUNCTION ){ + return 0; + } + if( sqlite3StrICmp(pExpr->u.zToken,"match")!=0 ){ + return 0; + } + pList = pExpr->x.pList; + if( pList->nExpr!=2 ){ + return 0; + } + if( pList->a[1].pExpr->op != TK_COLUMN ){ + return 0; + } + return 1; +} +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +/* +** If the pBase expression originated in the ON or USING clause of +** a join, then transfer the appropriate markings over to derived. +*/ +static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ + if( pDerived ){ + pDerived->flags |= pBase->flags & EP_FromJoin; + pDerived->iRightJoinTable = pBase->iRightJoinTable; + } +} + +/* +** 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++; +} + +/* +** 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 +** subterms. So in: +** +** ... WHERE (a=5) AND (b=7 OR c=9 OR d=13) AND (d=13) +** ^^^^^^^^^^^^^^^^^^^^ +** +** This routine analyzes terms such as the middle term in the above example. +** A WhereOrTerm object is computed and attached to the term under +** analysis, regardless of the outcome of the analysis. Hence: +** +** WhereTerm.wtFlags |= TERM_ORINFO +** WhereTerm.u.pOrInfo = a dynamically allocated WhereOrTerm object +** +** The term being analyzed must have two or more of OR-connected subterms. +** A single subterm might be a set of AND-connected sub-subterms. +** Examples of terms under analysis: +** +** (A) t1.x=t2.y OR t1.x=t2.z OR t1.y=15 OR t1.z=t3.a+5 +** (B) x=expr1 OR expr2=x OR x=expr3 +** (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: +** +** If all subterms are of the form T.C=expr for some single column of C and +** a single table T (as shown in example B above) then create a new virtual +** term that is an equivalent IN expression. In other words, if the term +** being analyzed is: +** +** x = expr1 OR expr2 = x OR x = expr3 +** +** then create a new virtual term like this: +** +** x IN (expr1,expr2,expr3) +** +** CASE 2: +** +** If there are exactly two disjuncts and 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 +** WhereTerm.u.pOrInfo->indexable |= the cursor number for table T +** +** A subterm is "indexable" if it is of the form +** "T.C " where C is any column of table T and +** is one of "=", "<", "<=", ">", ">=", "IS NULL", or "IN". +** A subterm is also indexable if it is an AND of two or more +** subsubterms at least one of which is indexable. Indexable AND +** subterms have their eOperator set to WO_AND and they have +** u.pAndInfo set to a dynamically allocated WhereAndTerm object. +** +** From another point of view, "indexable" means that the subterm could +** potentially be used with an index if an appropriate index exists. +** This analysis does not consider whether or not the index exists; that +** is decided elsewhere. This analysis only looks at whether subterms +** appropriate for indexing exist. +** +** All examples A through E above satisfy case 3. But if a term +** 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 3 is not +** satisfied. +** +** It might be the case that multiple tables are indexable. For example, +** (E) above is indexable on tables P, Q, and R. +** +** Terms that satisfy case 3 are candidates for lookup by using +** separate indices to find rowids for each subterm and composing +** the union of all rowids using a RowSet object. This is similar +** to "bitmap indices" in other database engines. +** +** OTHERWISE: +** +** If none of cases 1, 2, or 3 apply, then leave the eOperator set to +** zero. This term is not useful for search. +*/ +static void exprAnalyzeOrTerm( + SrcList *pSrc, /* the FROM clause */ + WhereClause *pWC, /* the complete WHERE clause */ + int idxTerm /* Index of the OR-term to be analyzed */ +){ + WhereInfo *pWInfo = pWC->pWInfo; /* WHERE clause processing context */ + Parse *pParse = pWInfo->pParse; /* Parser context */ + sqlite3 *db = pParse->db; /* Database connection */ + WhereTerm *pTerm = &pWC->a[idxTerm]; /* The term to be analyzed */ + Expr *pExpr = pTerm->pExpr; /* The expression of the term */ + int i; /* Loop counters */ + WhereClause *pOrWc; /* Breakup of pTerm into subterms */ + WhereTerm *pOrTerm; /* A Sub-term within the pOrWc */ + WhereOrInfo *pOrInfo; /* Additional information associated with pTerm */ + Bitmask chngToIN; /* Tables that might satisfy case 1 */ + Bitmask indexable; /* Tables that are indexable, satisfying case 2 */ + + /* + ** Break the OR clause into its separate subterms. The subterms are + ** stored in a WhereClause structure containing within the WhereOrInfo + ** object that is attached to the original OR clause term. + */ + assert( (pTerm->wtFlags & (TERM_DYNAMIC|TERM_ORINFO|TERM_ANDINFO))==0 ); + assert( pExpr->op==TK_OR ); + pTerm->u.pOrInfo = pOrInfo = sqlite3DbMallocZero(db, sizeof(*pOrInfo)); + if( pOrInfo==0 ) return; + pTerm->wtFlags |= TERM_ORINFO; + pOrWc = &pOrInfo->wc; + sqlite3WhereClauseInit(pOrWc, pWInfo); + sqlite3WhereSplit(pOrWc, pExpr, TK_OR); + sqlite3WhereExprAnalyze(pSrc, pOrWc); + if( db->mallocFailed ) return; + assert( pOrWc->nTerm>=2 ); + + /* + ** Compute the set of tables that might satisfy cases 1 or 3. + */ + indexable = ~(Bitmask)0; + chngToIN = ~(Bitmask)0; + for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0 && indexable; i--, pOrTerm++){ + if( (pOrTerm->eOperator & WO_SINGLE)==0 ){ + WhereAndInfo *pAndInfo; + assert( (pOrTerm->wtFlags & (TERM_ANDINFO|TERM_ORINFO))==0 ); + chngToIN = 0; + pAndInfo = sqlite3DbMallocRaw(db, sizeof(*pAndInfo)); + if( pAndInfo ){ + WhereClause *pAndWC; + WhereTerm *pAndTerm; + int j; + Bitmask b = 0; + pOrTerm->u.pAndInfo = pAndInfo; + pOrTerm->wtFlags |= TERM_ANDINFO; + pOrTerm->eOperator = WO_AND; + pAndWC = &pAndInfo->wc; + sqlite3WhereClauseInit(pAndWC, pWC->pWInfo); + sqlite3WhereSplit(pAndWC, pOrTerm->pExpr, TK_AND); + sqlite3WhereExprAnalyze(pSrc, pAndWC); + pAndWC->pOuter = pWC; + testcase( db->mallocFailed ); + if( !db->mallocFailed ){ + for(j=0, pAndTerm=pAndWC->a; jnTerm; j++, pAndTerm++){ + assert( pAndTerm->pExpr ); + if( allowedOp(pAndTerm->pExpr->op) ){ + b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pAndTerm->leftCursor); + } + } + } + indexable &= b; + } + }else if( pOrTerm->wtFlags & TERM_COPIED ){ + /* Skip this term for now. We revisit it when we process the + ** corresponding TERM_VIRTUAL term */ + }else{ + Bitmask b; + b = sqlite3WhereGetMask(&pWInfo->sMaskSet, pOrTerm->leftCursor); + if( pOrTerm->wtFlags & TERM_VIRTUAL ){ + WhereTerm *pOther = &pOrWc->a[pOrTerm->iParent]; + b |= sqlite3WhereGetMask(&pWInfo->sMaskSet, pOther->leftCursor); + } + indexable &= b; + if( (pOrTerm->eOperator & WO_EQ)==0 ){ + chngToIN = 0; + }else{ + chngToIN &= b; + } + } + } + + /* + ** 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 + ** is satisfied. + ** + ** chngToIN will hold either 0, 1, or 2 bits. The 0-bit case means + ** that there is no possibility of transforming the OR clause into an + ** IN operator because one or more terms in the OR clause contain + ** something other than == on a column in the single table. The 1-bit + ** case means that every term of the OR clause is of the form + ** "table.column=expr" for some single table. The one bit that is set + ** will correspond to the common table. We still need to check to make + ** sure the same column is used on all terms. The 2-bit case is when + ** the all terms are of the form "table1.column=table2.column". It + ** might be possible to form an IN operator with either table1.column + ** or table2.column as the LHS if either is common to every term of + ** the OR clause. + ** + ** Note that terms of the form "table.column1=table.column2" (the + ** same table on both sizes of the ==) cannot be optimized. + */ + if( chngToIN ){ + int okToChngToIN = 0; /* True if the conversion to IN is valid */ + int iColumn = -1; /* Column index on lhs of IN operator */ + int iCursor = -1; /* Table cursor common to all terms */ + int j = 0; /* Loop counter */ + + /* Search for a table and column that appears on one side or the + ** other of the == operator in every subterm. That table and column + ** will be recorded in iCursor and iColumn. There might not be any + ** such table and column. Set okToChngToIN if an appropriate table + ** and column is found but leave okToChngToIN false if not found. + */ + for(j=0; j<2 && !okToChngToIN; j++){ + pOrTerm = pOrWc->a; + for(i=pOrWc->nTerm-1; i>=0; i--, pOrTerm++){ + assert( pOrTerm->eOperator & WO_EQ ); + pOrTerm->wtFlags &= ~TERM_OR_OK; + if( pOrTerm->leftCursor==iCursor ){ + /* This is the 2-bit case and we are on the second iteration and + ** current term is from the first iteration. So skip this term. */ + assert( j==1 ); + continue; + } + if( (chngToIN & sqlite3WhereGetMask(&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 preceded + ** or follwed by an inverted copy (t2.b==t1.a). Skip this term + ** and use its inversion. */ + testcase( pOrTerm->wtFlags & TERM_COPIED ); + testcase( pOrTerm->wtFlags & TERM_VIRTUAL ); + assert( pOrTerm->wtFlags & (TERM_COPIED|TERM_VIRTUAL) ); + continue; + } + iColumn = pOrTerm->u.leftColumn; + iCursor = pOrTerm->leftCursor; + break; + } + if( i<0 ){ + /* No candidate table+column was found. This can only occur + ** on the second iteration */ + assert( j==1 ); + assert( IsPowerOfTwo(chngToIN) ); + assert( chngToIN==sqlite3WhereGetMask(&pWInfo->sMaskSet, iCursor) ); + break; + } + testcase( j==1 ); + + /* We have found a candidate table and column. Check to see if that + ** table and column is common to every term in the OR clause */ + okToChngToIN = 1; + for(; i>=0 && okToChngToIN; i--, pOrTerm++){ + assert( pOrTerm->eOperator & WO_EQ ); + if( pOrTerm->leftCursor!=iCursor ){ + pOrTerm->wtFlags &= ~TERM_OR_OK; + }else if( pOrTerm->u.leftColumn!=iColumn ){ + okToChngToIN = 0; + }else{ + int affLeft, affRight; + /* If the right-hand side is also a column, then the affinities + ** of both right and left sides must be such that no type + ** conversions are required on the right. (Ticket #2249) + */ + affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight); + affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft); + if( affRight!=0 && affRight!=affLeft ){ + okToChngToIN = 0; + }else{ + pOrTerm->wtFlags |= TERM_OR_OK; + } + } + } + } + + /* At this point, okToChngToIN is true if original pTerm satisfies + ** case 1. In that case, construct a new virtual term that is + ** pTerm converted into an IN operator. + */ + if( okToChngToIN ){ + Expr *pDup; /* A transient duplicate expression */ + ExprList *pList = 0; /* The RHS of the IN operator */ + Expr *pLeft = 0; /* The LHS of the IN operator */ + Expr *pNew; /* The complete IN operator */ + + for(i=pOrWc->nTerm-1, pOrTerm=pOrWc->a; i>=0; i--, pOrTerm++){ + if( (pOrTerm->wtFlags & TERM_OR_OK)==0 ) continue; + assert( pOrTerm->eOperator & WO_EQ ); + assert( pOrTerm->leftCursor==iCursor ); + assert( pOrTerm->u.leftColumn==iColumn ); + pDup = sqlite3ExprDup(db, pOrTerm->pExpr->pRight, 0); + pList = sqlite3ExprListAppend(pWInfo->pParse, pList, pDup); + pLeft = pOrTerm->pExpr->pLeft; + } + assert( pLeft!=0 ); + pDup = sqlite3ExprDup(db, pLeft, 0); + pNew = sqlite3PExpr(pParse, TK_IN, pDup, 0, 0); + if( pNew ){ + int idxNew; + transferJoinMarkings(pNew, pExpr); + assert( !ExprHasProperty(pNew, EP_xIsSelect) ); + pNew->x.pList = pList; + idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); + testcase( idxNew==0 ); + exprAnalyze(pSrc, pWC, idxNew); + pTerm = &pWC->a[idxTerm]; + markTermAsChild(pWC, idxNew, idxTerm); + }else{ + sqlite3ExprListDelete(db, pList); + } + pTerm->eOperator = WO_NOOP; /* case 1 trumps case 3 */ + } + } +} +#endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */ + +/* +** We already know that pExpr is a binary operator where both operands are +** column references. This routine checks to see if pExpr is an equivalence +** relation: +** 1. The SQLITE_Transitive optimization must be enabled +** 2. Must be either an == or an IS operator +** 3. Not originating in the ON clause of an OUTER JOIN +** 4. The affinities of A and B must be compatible +** 5a. Both operands use the same collating sequence OR +** 5b. The overall collating sequence is BINARY +** If this routine returns TRUE, that means that the RHS can be substituted +** for the LHS anyplace else in the WHERE clause where the LHS column occurs. +** This is an optimization. No harm comes from returning 0. But if 1 is +** returned when it should not be, then incorrect answers might result. +*/ +static int termIsEquivalence(Parse *pParse, Expr *pExpr){ + char aff1, aff2; + CollSeq *pColl; + const char *zColl1, *zColl2; + if( !OptimizationEnabled(pParse->db, SQLITE_Transitive) ) return 0; + if( pExpr->op!=TK_EQ && pExpr->op!=TK_IS ) return 0; + if( ExprHasProperty(pExpr, EP_FromJoin) ) return 0; + aff1 = sqlite3ExprAffinity(pExpr->pLeft); + aff2 = sqlite3ExprAffinity(pExpr->pRight); + if( aff1!=aff2 + && (!sqlite3IsNumericAffinity(aff1) || !sqlite3IsNumericAffinity(aff2)) + ){ + return 0; + } + pColl = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft, pExpr->pRight); + if( pColl==0 || sqlite3StrICmp(pColl->zName, "BINARY")==0 ) return 1; + pColl = sqlite3ExprCollSeq(pParse, pExpr->pLeft); + /* Since pLeft and pRight are both a column references, their collating + ** sequence should always be defined. */ + zColl1 = ALWAYS(pColl) ? pColl->zName : 0; + pColl = sqlite3ExprCollSeq(pParse, pExpr->pRight); + zColl2 = ALWAYS(pColl) ? pColl->zName : 0; + return sqlite3StrICmp(zColl1, zColl2)==0; +} + +/* +** Recursively walk the expressions of a SELECT statement and generate +** a bitmask indicating which tables are used in that expression +** tree. +*/ +static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){ + Bitmask mask = 0; + while( pS ){ + SrcList *pSrc = pS->pSrc; + mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pEList); + mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pGroupBy); + mask |= sqlite3WhereExprListUsage(pMaskSet, pS->pOrderBy); + mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere); + mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving); + if( ALWAYS(pSrc!=0) ){ + int i; + for(i=0; inSrc; i++){ + mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); + mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].pOn); + } + } + pS = pS->pPrior; + } + return mask; +} + +/* +** The input to this routine is an WhereTerm structure with only the +** "pExpr" field filled in. The job of this routine is to analyze the +** subexpression and populate all the other fields of the WhereTerm +** structure. +** +** If the expression is of the form " X" it gets commuted +** to the standard form of "X ". +** +** If the expression is of the form "X Y" where both X and Y are +** columns, then the original expression is unchanged and a new virtual +** term of the form "Y X" is added to the WHERE clause and +** analyzed separately. The original term is marked with TERM_COPIED +** and the new term is marked with TERM_DYNAMIC (because it's pExpr +** needs to be freed with the WhereClause) and TERM_VIRTUAL (because it +** is a commuted copy of a prior term.) The original term has nChild=1 +** and the copy has idxParent set to the index of the original term. +*/ +static void exprAnalyze( + SrcList *pSrc, /* the FROM clause */ + WhereClause *pWC, /* the WHERE clause */ + int idxTerm /* Index of the term to be analyzed */ +){ + WhereInfo *pWInfo = pWC->pWInfo; /* WHERE clause processing context */ + WhereTerm *pTerm; /* The term to be analyzed */ + WhereMaskSet *pMaskSet; /* Set of table index masks */ + Expr *pExpr; /* The expression to be analyzed */ + Bitmask prereqLeft; /* Prerequesites of the pExpr->pLeft */ + Bitmask prereqAll; /* Prerequesites of pExpr */ + 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; /* uppercase equivalent to lowercase */ + int op; /* Top-level operator. pExpr->op */ + Parse *pParse = pWInfo->pParse; /* Parsing context */ + sqlite3 *db = pParse->db; /* Database connection */ + + if( db->mallocFailed ){ + return; + } + pTerm = &pWC->a[idxTerm]; + pMaskSet = &pWInfo->sMaskSet; + pExpr = pTerm->pExpr; + assert( pExpr->op!=TK_AS && pExpr->op!=TK_COLLATE ); + prereqLeft = sqlite3WhereExprUsage(pMaskSet, pExpr->pLeft); + op = pExpr->op; + if( op==TK_IN ){ + assert( pExpr->pRight==0 ); + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + pTerm->prereqRight = exprSelectUsage(pMaskSet, pExpr->x.pSelect); + }else{ + pTerm->prereqRight = sqlite3WhereExprListUsage(pMaskSet, pExpr->x.pList); + } + }else if( op==TK_ISNULL ){ + pTerm->prereqRight = 0; + }else{ + pTerm->prereqRight = sqlite3WhereExprUsage(pMaskSet, pExpr->pRight); + } + prereqAll = sqlite3WhereExprUsage(pMaskSet, pExpr); + if( ExprHasProperty(pExpr, EP_FromJoin) ){ + Bitmask x = sqlite3WhereGetMask(pMaskSet, pExpr->iRightJoinTable); + prereqAll |= x; + extraRight = x-1; /* ON clause terms may not be used with an index + ** on left table of a LEFT JOIN. Ticket #3015 */ + } + pTerm->prereqAll = prereqAll; + pTerm->leftCursor = -1; + pTerm->iParent = -1; + pTerm->eOperator = 0; + if( allowedOp(op) ){ + Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft); + Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight); + u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV; + if( pLeft->op==TK_COLUMN ){ + pTerm->leftCursor = pLeft->iTable; + pTerm->u.leftColumn = pLeft->iColumn; + pTerm->eOperator = operatorMask(op) & opMask; + } + if( op==TK_IS ) pTerm->wtFlags |= TERM_IS; + if( pRight && pRight->op==TK_COLUMN ){ + WhereTerm *pNew; + Expr *pDup; + u16 eExtraOp = 0; /* Extra bits for pNew->eOperator */ + if( pTerm->leftCursor>=0 ){ + int idxNew; + pDup = sqlite3ExprDup(db, pExpr, 0); + if( db->mallocFailed ){ + sqlite3ExprDelete(db, pDup); + return; + } + idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC); + if( idxNew==0 ) return; + pNew = &pWC->a[idxNew]; + markTermAsChild(pWC, idxNew, idxTerm); + if( op==TK_IS ) pNew->wtFlags |= TERM_IS; + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags |= TERM_COPIED; + + if( termIsEquivalence(pParse, pDup) ){ + pTerm->eOperator |= WO_EQUIV; + eExtraOp = WO_EQUIV; + } + }else{ + pDup = pExpr; + pNew = pTerm; + } + exprCommute(pParse, pDup); + pLeft = sqlite3ExprSkipCollate(pDup->pLeft); + pNew->leftCursor = pLeft->iTable; + pNew->u.leftColumn = pLeft->iColumn; + testcase( (prereqLeft | extraRight) != prereqLeft ); + pNew->prereqRight = prereqLeft | extraRight; + pNew->prereqAll = prereqAll; + pNew->eOperator = (operatorMask(pDup->op) + eExtraOp) & opMask; + } + } + +#ifndef SQLITE_OMIT_BETWEEN_OPTIMIZATION + /* If a term is the BETWEEN operator, create two new virtual terms + ** that define the range that the BETWEEN implements. For example: + ** + ** a BETWEEN b AND c + ** + ** is converted into: + ** + ** (a BETWEEN b AND c) AND (a>=b) AND (a<=c) + ** + ** The two new terms are added onto the end of the WhereClause object. + ** The new terms are "dynamic" and are children of the original BETWEEN + ** term. That means that if the BETWEEN term is coded, the children are + ** skipped. Or, if the children are satisfied by an index, the original + ** BETWEEN term is skipped. + */ + else if( pExpr->op==TK_BETWEEN && pWC->op==TK_AND ){ + ExprList *pList = pExpr->x.pList; + int i; + static const u8 ops[] = {TK_GE, TK_LE}; + assert( pList!=0 ); + assert( pList->nExpr==2 ); + for(i=0; i<2; i++){ + Expr *pNewExpr; + int idxNew; + pNewExpr = sqlite3PExpr(pParse, ops[i], + sqlite3ExprDup(db, pExpr->pLeft, 0), + sqlite3ExprDup(db, pList->a[i].pExpr, 0), 0); + transferJoinMarkings(pNewExpr, pExpr); + idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); + testcase( idxNew==0 ); + exprAnalyze(pSrc, pWC, idxNew); + pTerm = &pWC->a[idxTerm]; + markTermAsChild(pWC, idxNew, idxTerm); + } + } +#endif /* SQLITE_OMIT_BETWEEN_OPTIMIZATION */ + +#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY) + /* Analyze a term that is composed of two or more subterms connected by + ** an OR operator. + */ + else if( pExpr->op==TK_OR ){ + assert( pWC->op==TK_AND ); + exprAnalyzeOrTerm(pSrc, pWC, idxTerm); + pTerm = &pWC->a[idxTerm]; + } +#endif /* SQLITE_OMIT_OR_OPTIMIZATION */ + +#ifndef SQLITE_OMIT_LIKE_OPTIMIZATION + /* 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 + ** + ** x>='ABC' AND x<'abd' AND x LIKE 'aBc%' + ** + ** The last character of the prefix "abc" is incremented to form the + ** 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) + ){ + Expr *pLeft; /* LHS of LIKE/GLOB operator */ + Expr *pStr2; /* Copy of pStr1 - RHS of LIKE/GLOB operator */ + Expr *pNewExpr1; + Expr *pNewExpr2; + int idxNew1; + int idxNew2; + 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]; + c = *pC; + if( noCase ){ + /* The point is to increment the last character before the first + ** wildcard. But if we increment '@', that will push it into the + ** alphabetic range where case conversions will mess up the + ** inequality. To avoid this, make sure to also run the full + ** LIKE on all candidate expressions by clearing the isComplete flag + */ + if( c=='A'-1 ) isComplete = 0; + c = sqlite3UpperToLower[c]; + } + *pC = c + 1; + } + zCollSeqName = noCase ? "NOCASE" : "BINARY"; + pNewExpr1 = sqlite3ExprDup(db, pLeft, 0); + pNewExpr1 = sqlite3PExpr(pParse, TK_GE, + sqlite3ExprAddCollateString(pParse,pNewExpr1,zCollSeqName), + pStr1, 0); + transferJoinMarkings(pNewExpr1, pExpr); + idxNew1 = whereClauseInsert(pWC, pNewExpr1, wtFlags); + testcase( idxNew1==0 ); + exprAnalyze(pSrc, pWC, idxNew1); + pNewExpr2 = sqlite3ExprDup(db, pLeft, 0); + pNewExpr2 = sqlite3PExpr(pParse, TK_LT, + sqlite3ExprAddCollateString(pParse,pNewExpr2,zCollSeqName), + pStr2, 0); + transferJoinMarkings(pNewExpr2, pExpr); + idxNew2 = whereClauseInsert(pWC, pNewExpr2, wtFlags); + testcase( idxNew2==0 ); + exprAnalyze(pSrc, pWC, idxNew2); + pTerm = &pWC->a[idxTerm]; + if( isComplete ){ + markTermAsChild(pWC, idxNew1, idxTerm); + markTermAsChild(pWC, idxNew2, idxTerm); + } + } +#endif /* SQLITE_OMIT_LIKE_OPTIMIZATION */ + +#ifndef SQLITE_OMIT_VIRTUALTABLE + /* Add a WO_MATCH auxiliary term to the constraint set if the + ** current expression is of the form: column MATCH expr. + ** This information is used by the xBestIndex methods of + ** virtual tables. The native query optimizer does not attempt + ** to do anything with MATCH functions. + */ + if( isMatchOfColumn(pExpr) ){ + int idxNew; + Expr *pRight, *pLeft; + WhereTerm *pNewTerm; + Bitmask prereqColumn, prereqExpr; + + pRight = pExpr->x.pList->a[0].pExpr; + pLeft = pExpr->x.pList->a[1].pExpr; + prereqExpr = sqlite3WhereExprUsage(pMaskSet, pRight); + prereqColumn = sqlite3WhereExprUsage(pMaskSet, pLeft); + if( (prereqExpr & prereqColumn)==0 ){ + Expr *pNewExpr; + pNewExpr = sqlite3PExpr(pParse, TK_MATCH, + 0, sqlite3ExprDup(db, pRight, 0), 0); + idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC); + testcase( idxNew==0 ); + pNewTerm = &pWC->a[idxNew]; + pNewTerm->prereqRight = prereqExpr; + pNewTerm->leftCursor = pLeft->iTable; + pNewTerm->u.leftColumn = pLeft->iColumn; + pNewTerm->eOperator = WO_MATCH; + markTermAsChild(pWC, idxNew, idxTerm); + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags |= TERM_COPIED; + pNewTerm->prereqAll = pTerm->prereqAll; + } + } +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifdef SQLITE_ENABLE_STAT3_OR_STAT4 + /* When sqlite_stat3 histogram data is available an operator of the + ** form "x IS NOT NULL" can sometimes be evaluated more efficiently + ** as "x>NULL" if x is not an INTEGER PRIMARY KEY. So construct a + ** virtual term of that form. + ** + ** Note that the virtual term must be tagged with TERM_VNULL. + */ + if( pExpr->op==TK_NOTNULL + && pExpr->pLeft->op==TK_COLUMN + && pExpr->pLeft->iColumn>=0 + && OptimizationEnabled(db, SQLITE_Stat34) + ){ + Expr *pNewExpr; + Expr *pLeft = pExpr->pLeft; + int idxNew; + WhereTerm *pNewTerm; + + pNewExpr = sqlite3PExpr(pParse, TK_GT, + sqlite3ExprDup(db, pLeft, 0), + sqlite3PExpr(pParse, TK_NULL, 0, 0, 0), 0); + + idxNew = whereClauseInsert(pWC, pNewExpr, + TERM_VIRTUAL|TERM_DYNAMIC|TERM_VNULL); + if( idxNew ){ + pNewTerm = &pWC->a[idxNew]; + pNewTerm->prereqRight = 0; + pNewTerm->leftCursor = pLeft->iTable; + pNewTerm->u.leftColumn = pLeft->iColumn; + pNewTerm->eOperator = WO_GT; + markTermAsChild(pWC, idxNew, idxTerm); + pTerm = &pWC->a[idxTerm]; + pTerm->wtFlags |= TERM_COPIED; + pNewTerm->prereqAll = pTerm->prereqAll; + } + } +#endif /* SQLITE_ENABLE_STAT3_OR_STAT4 */ + + /* Prevent ON clause terms of a LEFT JOIN from being used to drive + ** an index for tables to the left of the join. + */ + pTerm->prereqRight |= extraRight; +} + +/*************************************************************************** +** Routines with file scope above. Interface to the rest of the where.c +** subsystem follows. +***************************************************************************/ + +/* +** This routine identifies subexpressions in the WHERE clause where +** each subexpression is separated by the AND operator or some other +** operator specified in the op parameter. The WhereClause structure +** is filled with pointers to subexpressions. For example: +** +** WHERE a=='hello' AND coalesce(b,11)<10 AND (c+12!=d OR c==22) +** \________/ \_______________/ \________________/ +** slot[0] slot[1] slot[2] +** +** The original WHERE clause in pExpr is unaltered. All this routine +** does is make slot[] entries point to substructure within pExpr. +** +** In the previous sentence and in the diagram, "slot[]" refers to +** the WhereClause.a[] array. The slot[] array grows as needed to contain +** all terms of the WHERE clause. +*/ +void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ + Expr *pE2 = sqlite3ExprSkipCollate(pExpr); + pWC->op = op; + if( pE2==0 ) return; + if( pE2->op!=op ){ + whereClauseInsert(pWC, pExpr, 0); + }else{ + sqlite3WhereSplit(pWC, pE2->pLeft, op); + sqlite3WhereSplit(pWC, pE2->pRight, op); + } +} + +/* +** Initialize a preallocated WhereClause structure. +*/ +void sqlite3WhereClauseInit( + WhereClause *pWC, /* The WhereClause to be initialized */ + WhereInfo *pWInfo /* The WHERE processing context */ +){ + pWC->pWInfo = pWInfo; + pWC->pOuter = 0; + pWC->nTerm = 0; + pWC->nSlot = ArraySize(pWC->aStatic); + pWC->a = pWC->aStatic; +} + +/* +** Deallocate a WhereClause structure. The WhereClause structure +** itself is not freed. This routine is the inverse of sqlite3WhereClauseInit(). +*/ +void sqlite3WhereClauseClear(WhereClause *pWC){ + int i; + WhereTerm *a; + sqlite3 *db = pWC->pWInfo->pParse->db; + for(i=pWC->nTerm-1, a=pWC->a; i>=0; i--, a++){ + if( a->wtFlags & TERM_DYNAMIC ){ + sqlite3ExprDelete(db, a->pExpr); + } + if( a->wtFlags & TERM_ORINFO ){ + whereOrInfoDelete(db, a->u.pOrInfo); + }else if( a->wtFlags & TERM_ANDINFO ){ + whereAndInfoDelete(db, a->u.pAndInfo); + } + } + if( pWC->a!=pWC->aStatic ){ + sqlite3DbFree(db, pWC->a); + } +} + + +/* +** These routines walk (recursively) an expression tree and generate +** a bitmask indicating which tables are used in that expression +** tree. +*/ +Bitmask sqlite3WhereExprUsage(WhereMaskSet *pMaskSet, Expr *p){ + Bitmask mask = 0; + if( p==0 ) return 0; + if( p->op==TK_COLUMN ){ + mask = sqlite3WhereGetMask(pMaskSet, p->iTable); + return mask; + } + mask = sqlite3WhereExprUsage(pMaskSet, p->pRight); + mask |= sqlite3WhereExprUsage(pMaskSet, p->pLeft); + if( ExprHasProperty(p, EP_xIsSelect) ){ + mask |= exprSelectUsage(pMaskSet, p->x.pSelect); + }else{ + mask |= sqlite3WhereExprListUsage(pMaskSet, p->x.pList); + } + return mask; +} +Bitmask sqlite3WhereExprListUsage(WhereMaskSet *pMaskSet, ExprList *pList){ + int i; + Bitmask mask = 0; + if( pList ){ + for(i=0; inExpr; i++){ + mask |= sqlite3WhereExprUsage(pMaskSet, pList->a[i].pExpr); + } + } + return mask; +} + + +/* +** Call exprAnalyze on all terms in a WHERE clause. +** +** Note that exprAnalyze() might add new virtual terms onto the +** end of the WHERE clause. We do not want to analyze these new +** virtual terms, so start analyzing at the end and work forward +** so that the added virtual terms are never processed. +*/ +void sqlite3WhereExprAnalyze( + SrcList *pTabList, /* the FROM clause */ + WhereClause *pWC /* the WHERE clause to be analyzed */ +){ + int i; + for(i=pWC->nTerm-1; i>=0; i--){ + exprAnalyze(pTabList, pWC, i); + } +} diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index 8e7858896a..320a12eef1 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -344,6 +344,7 @@ foreach file { vacuum.c vtab.c wherecode.c + whereexpr.c where.c parse.c From 38b4149ca1308db644dbf55426cc366c45ad7579 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 8 Jun 2015 15:08:15 +0000 Subject: [PATCH 17/28] Factor out the TreeView parse tree printing module into a separate file. FossilOrigin-Name: c32ce54ca46a4be4373983be6fd44b1f3a0250d1 --- Makefile.in | 6 +- Makefile.msc | 6 +- main.mk | 3 +- manifest | 27 +-- manifest.uuid | 2 +- src/expr.c | 254 -------------------------- src/printf.c | 66 +------ src/select.c | 128 +++---------- src/sqliteInt.h | 4 - src/treeview.c | 425 ++++++++++++++++++++++++++++++++++++++++++++ tool/mksqlite3c.tcl | 1 + 11 files changed, 475 insertions(+), 447 deletions(-) create mode 100644 src/treeview.c diff --git a/Makefile.in b/Makefile.in index ea1715557e..1b7c7f9dc5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -181,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 threads.lo tokenize.lo trigger.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 wherecode.lo whereexpr.lo \ @@ -274,6 +274,7 @@ SRC = \ $(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 \ @@ -806,6 +807,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 diff --git a/Makefile.msc b/Makefile.msc index 11b2097465..c3272de0de 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -835,7 +835,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 threads.lo tokenize.lo trigger.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 wherecode.lo whereexpr.lo \ @@ -940,6 +940,7 @@ SRC2 = \ $(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 \ @@ -1487,6 +1488,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 diff --git a/main.mk b/main.mk index 27d56fb80f..22fc700a75 100644 --- a/main.mk +++ b/main.mk @@ -66,7 +66,7 @@ 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 sqlite3ota.o status.o \ - table.o threads.o tokenize.o trigger.o \ + table.o threads.o tokenize.o treeview.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 wherecode.o whereexpr.o \ @@ -152,6 +152,7 @@ SRC = \ $(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 \ diff --git a/manifest b/manifest index 0307e1a087..2ac088fd87 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Split\smore\ssubfunctions\sof\swhere.c\sout\sinto\sa\snew\swhereexpr.c\ssource\sfile,\nfor\simproved\smaintainability. -D 2015-06-08T14:23:15.485 +C Factor\sout\sthe\sTreeView\sparse\stree\sprinting\smodule\sinto\sa\sseparate\sfile. +D 2015-06-08T15:08:15.270 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in d7bde8e39e88f23c99219e822aaab80a9ce48a53 +F Makefile.in a7b384855b72378fd860425b128ea5f75296e9d6 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc e4e8cbbe98d77d62b1fed34d95d966d5db2a1b01 +F Makefile.msc 5438dc167466f51349ab0c4497aef547d0c9352c F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858 F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7 F VERSION ce0ae95abd7121c534f6917c1c8f2b70d9acd4db @@ -171,7 +171,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 4aed2f4087f3880a92c505fba772f2368d699da5 +F main.mk dc931768b88e4417bc2f8b2d45dba385ad29f727 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk d5e22023b5238985bb54a72d33e0ac71fe4f8a32 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -202,7 +202,7 @@ F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e -F src/expr.c 12e04f322956076b1f8748ca572568968f8155d9 +F src/expr.c 0550baeca8dd7472e298d9e881e5e3484f7666f8 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 F src/func.c 5b8b8e77a0fb644eaf8947d413804622e32692b6 @@ -246,16 +246,16 @@ F src/pcache1.c 69d137620a305f814398bd29a0c998038c0695e9 F src/pragma.c c1f4d012ea9f6b1ce52d341b2cd0ad72d560afd7 F src/pragma.h b8632d7cdda7b25323fa580e3e558a4f0d4502cc F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 -F src/printf.c 13ce37e5574f9b0682fa86dbcf9faf76b9d82a15 +F src/printf.c 9889e8826f8e2bd8c2718d7d3faa761bef8eac79 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e -F src/select.c d507fe715b12e6aba157fa34b0a5680809e59bac +F src/select.c 45a814a755f90c1a6345164d2da4a8ef293da53d F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 2ebeb634e751a61a6f0eebfa0f4669f46a42f6cd -F src/sqliteInt.h 851cc2ee6ec9a853f3fbcf1ce582590531fd7528 +F src/sqliteInt.h 4c6731ce49b90582ea7d77c67b8792a4df8da237 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -307,6 +307,7 @@ F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 6bbcc9fe50c917864d48287b4792d46d6e873481 F src/tokenize.c baa0e550dfa76a8d781732a7bfb1f0aa094942f2 +F src/treeview.c 84aa2d2ed26627ccc8dd3a2becfa18dc86ee4607 F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f F src/update.c 487747b328b7216bb7f6af0695d6937d5c9e605f F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c @@ -1249,7 +1250,7 @@ F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e F tool/mkpragmatab.tcl 40c287d3f929ece67da6e9e7c49885789960accf F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 F tool/mksqlite3c-noext.tcl 69bae8ce4aa52d2ff82d4a8a856bf283ec035b2e -F tool/mksqlite3c.tcl 9a4b87e86c6036b285b5f0fe1e4db0c79c4092ab +F tool/mksqlite3c.tcl d79e450048b0bbf04d53677e01c249a012981182 F tool/mksqlite3h.tcl 44730d586c9031638cdd2eb443b801c0d2dbd9f8 F tool/mksqlite3internalh.tcl eb994013e833359137eb53a55acdad0b5ae1049b F tool/mkvsix.tcl 3b58b9398f91c7dbf18d49eb87cefeee9efdbce1 @@ -1284,7 +1285,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P faa0e420e93a2bc1c84df9eb9fef4748d29ce339 -R d7cd77de896255756abb541430f78771 +P 46ef95c108ad8961f2bf3d2dc839d4fb1fddd770 +R b8b4fb0f1a8beaad9f2b2c3f4237ea7b U drh -Z 58efdf4d20fca9a444e5c6368ea56c89 +Z 10e8e7d0fa9ce8baee6c4a1498d642ba diff --git a/manifest.uuid b/manifest.uuid index 1199d6a972..28f125a126 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -46ef95c108ad8961f2bf3d2dc839d4fb1fddd770 \ No newline at end of file +c32ce54ca46a4be4373983be6fd44b1f3a0250d1 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index d62346e39d..89eee29ecd 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3311,260 +3311,6 @@ void sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){ exprToRegister(pExpr, iMem); } -#ifdef SQLITE_DEBUG -/* -** Generate a human-readable explanation of an expression tree. -*/ -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 ){ - sqlite3TreeViewLine(pView, "nil"); - sqlite3TreeViewPop(pView); - return; - } - switch( pExpr->op ){ - case TK_AGG_COLUMN: { - sqlite3TreeViewLine(pView, "AGG{%d:%d}", - pExpr->iTable, pExpr->iColumn); - break; - } - case TK_COLUMN: { - if( pExpr->iTable<0 ){ - /* This only happens when coding check constraints */ - sqlite3TreeViewLine(pView, "COLUMN(%d)", pExpr->iColumn); - }else{ - sqlite3TreeViewLine(pView, "{%d:%d}", - pExpr->iTable, pExpr->iColumn); - } - break; - } - case TK_INTEGER: { - if( pExpr->flags & EP_IntValue ){ - sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); - }else{ - sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); - } - break; - } -#ifndef SQLITE_OMIT_FLOATING_POINT - case TK_FLOAT: { - sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); - break; - } -#endif - case TK_STRING: { - sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); - break; - } - case TK_NULL: { - sqlite3TreeViewLine(pView,"NULL"); - break; - } -#ifndef SQLITE_OMIT_BLOB_LITERAL - case TK_BLOB: { - sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); - break; - } -#endif - case TK_VARIABLE: { - sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", - pExpr->u.zToken, pExpr->iColumn); - break; - } - case TK_REGISTER: { - sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); - break; - } - case TK_AS: { - sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken); - sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); - break; - } - case TK_ID: { - sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); - break; - } -#ifndef SQLITE_OMIT_CAST - case TK_CAST: { - /* Expressions of the form: CAST(pLeft AS token) */ - sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); - sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); - break; - } -#endif /* SQLITE_OMIT_CAST */ - case TK_LT: zBinOp = "LT"; break; - case TK_LE: zBinOp = "LE"; break; - case TK_GT: zBinOp = "GT"; break; - case TK_GE: zBinOp = "GE"; break; - case TK_NE: zBinOp = "NE"; break; - case TK_EQ: zBinOp = "EQ"; break; - case TK_IS: zBinOp = "IS"; break; - case TK_ISNOT: zBinOp = "ISNOT"; break; - case TK_AND: zBinOp = "AND"; break; - case TK_OR: zBinOp = "OR"; break; - case TK_PLUS: zBinOp = "ADD"; break; - case TK_STAR: zBinOp = "MUL"; break; - case TK_MINUS: zBinOp = "SUB"; break; - case TK_REM: zBinOp = "REM"; break; - case TK_BITAND: zBinOp = "BITAND"; break; - case TK_BITOR: zBinOp = "BITOR"; break; - case TK_SLASH: zBinOp = "DIV"; break; - 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; - case TK_BITNOT: zUniOp = "BITNOT"; break; - case TK_NOT: zUniOp = "NOT"; break; - case TK_ISNULL: zUniOp = "ISNULL"; break; - case TK_NOTNULL: zUniOp = "NOTNULL"; break; - - case TK_COLLATE: { - sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken); - sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); - break; - } - - case TK_AGG_FUNCTION: - case TK_FUNCTION: { - ExprList *pFarg; /* List of function arguments */ - if( ExprHasProperty(pExpr, EP_TokenOnly) ){ - pFarg = 0; - }else{ - pFarg = pExpr->x.pList; - } - if( pExpr->op==TK_AGG_FUNCTION ){ - sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q", - pExpr->op2, pExpr->u.zToken); - }else{ - sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken); - } - if( pFarg ){ - sqlite3TreeViewExprList(pView, pFarg, 0, 0); - } - break; - } -#ifndef SQLITE_OMIT_SUBQUERY - case TK_EXISTS: { - sqlite3TreeViewLine(pView, "EXISTS-expr"); - sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); - break; - } - case TK_SELECT: { - sqlite3TreeViewLine(pView, "SELECT-expr"); - sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); - break; - } - case TK_IN: { - sqlite3TreeViewLine(pView, "IN"); - sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); - if( ExprHasProperty(pExpr, EP_xIsSelect) ){ - sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); - }else{ - sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); - } - break; - } -#endif /* SQLITE_OMIT_SUBQUERY */ - - /* - ** x BETWEEN y AND z - ** - ** This is equivalent to - ** - ** x>=y AND x<=z - ** - ** X is stored in pExpr->pLeft. - ** Y is stored in pExpr->pList->a[0].pExpr. - ** Z is stored in pExpr->pList->a[1].pExpr. - */ - case TK_BETWEEN: { - Expr *pX = pExpr->pLeft; - Expr *pY = pExpr->x.pList->a[0].pExpr; - Expr *pZ = pExpr->x.pList->a[1].pExpr; - sqlite3TreeViewLine(pView, "BETWEEN"); - sqlite3TreeViewExpr(pView, pX, 1); - sqlite3TreeViewExpr(pView, pY, 1); - sqlite3TreeViewExpr(pView, pZ, 0); - break; - } - case TK_TRIGGER: { - /* If the opcode is TK_TRIGGER, then the expression is a reference - ** to a column in the new.* or old.* pseudo-tables available to - ** trigger programs. In this case Expr.iTable is set to 1 for the - ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn - ** is set to the column of the pseudo-table to read, or to -1 to - ** read the rowid field. - */ - sqlite3TreeViewLine(pView, "%s(%d)", - pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); - break; - } - case TK_CASE: { - sqlite3TreeViewLine(pView, "CASE"); - sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); - sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); - break; - } -#ifndef SQLITE_OMIT_TRIGGER - case TK_RAISE: { - const char *zType = "unk"; - switch( pExpr->affinity ){ - case OE_Rollback: zType = "rollback"; break; - case OE_Abort: zType = "abort"; break; - case OE_Fail: zType = "fail"; break; - case OE_Ignore: zType = "ignore"; break; - } - sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); - break; - } -#endif - default: { - sqlite3TreeViewLine(pView, "op=%d", pExpr->op); - break; - } - } - if( zBinOp ){ - sqlite3TreeViewLine(pView, "%s", zBinOp); - sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); - sqlite3TreeViewExpr(pView, pExpr->pRight, 0); - }else if( zUniOp ){ - sqlite3TreeViewLine(pView, "%s", zUniOp); - sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); - } - sqlite3TreeViewPop(pView); -} -#endif /* SQLITE_DEBUG */ - -#ifdef SQLITE_DEBUG -/* -** Generate a human-readable explanation of an expression list. -*/ -void sqlite3TreeViewExprList( - TreeView *pView, - const ExprList *pList, - u8 moreToFollow, - const char *zLabel -){ - int i; - pView = sqlite3TreeViewPush(pView, moreToFollow); - if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; - if( pList==0 ){ - sqlite3TreeViewLine(pView, "%s (empty)", zLabel); - }else{ - sqlite3TreeViewLine(pView, "%s", zLabel); - for(i=0; inExpr; i++){ - sqlite3TreeViewExpr(pView, pList->a[i].pExpr, inExpr-1); - } - } - sqlite3TreeViewPop(pView); -} -#endif /* SQLITE_DEBUG */ - /* ** Generate code that pushes the value of every element of the given ** expression list into a sequence of registers beginning at target. diff --git a/src/printf.c b/src/printf.c index edf2210e0a..ebdf44518f 100644 --- a/src/printf.c +++ b/src/printf.c @@ -1,9 +1,6 @@ /* ** The "printf" code that follows dates from the 1980's. It is in -** the public domain. The original comments are included here for -** completeness. They are very out-of-date but might be useful as -** an historical reference. Most of the "enhancements" have been backed -** out so that the functionality is now the same as standard printf(). +** the public domain. ** ************************************************************************** ** @@ -1058,67 +1055,6 @@ 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_malloc64( 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, 0, zBuf, sizeof(zBuf), 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/select.c b/src/select.c index f801d1033a..f030d2f4a4 100644 --- a/src/select.c +++ b/src/select.c @@ -21,7 +21,8 @@ /***/ int sqlite3SelectTrace = 0; # define SELECTTRACE(K,P,S,X) \ if(sqlite3SelectTrace&(K)) \ - sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",(S)->zSelName,(S)),\ + sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",\ + (S)->zSelName,(S)),\ sqlite3DebugPrintf X #else # define SELECTTRACE(K,P,S,X) @@ -774,7 +775,8 @@ static void selectInnerLoop( default: { assert( pDistinct->eTnctType==WHERE_DISTINCT_UNORDERED ); - codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, regResult); + codeDistinct(pParse, pDistinct->tabTnct, iContinue, nResultCol, + regResult); break; } } @@ -827,7 +829,8 @@ static void selectInnerLoop( ** current row to the index and proceed with writing it to the ** output table as well. */ int addr = sqlite3VdbeCurrentAddr(v) + 4; - sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); VdbeCoverage(v); + sqlite3VdbeAddOp4Int(v, OP_Found, iParm+1, addr, r1, 0); + VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm+1, r1); assert( pSort==0 ); } @@ -1704,7 +1707,8 @@ static void selectAddColumnTypeAndCollation( for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ p = a[i].pExpr; if( pCol->zType==0 ){ - pCol->zType = sqlite3DbStrDup(db, columnType(&sNC, p,0,0,0, &pCol->szEst)); + pCol->zType = sqlite3DbStrDup(db, + columnType(&sNC, p,0,0,0, &pCol->szEst)); } szAll += pCol->szEst; pCol->affinity = sqlite3ExprAffinity(p); @@ -3214,8 +3218,8 @@ static void substSelect( ** ** (**) 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." +** 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. ** @@ -4985,7 +4989,8 @@ int sqlite3Select( } #endif - /* Various elements of the SELECT copied into local variables for convenience */ + /* Various elements of the SELECT copied into local variables for + ** convenience */ pEList = p->pEList; pWhere = p->pWhere; pGroupBy = p->pGroupBy; @@ -5067,9 +5072,9 @@ int sqlite3Select( if( p->selFlags & SF_Distinct ){ sDistinct.tabTnct = pParse->nTab++; sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, - sDistinct.tabTnct, 0, 0, - (char*)keyInfoFromExprList(pParse, p->pEList,0,0), - P4_KEYINFO); + sDistinct.tabTnct, 0, 0, + (char*)keyInfoFromExprList(pParse, p->pEList,0,0), + P4_KEYINFO); sqlite3VdbeChangeP5(v, BTREE_UNORDERED); sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED; }else{ @@ -5328,7 +5333,8 @@ int sqlite3Select( addrTopOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3ExprCacheClear(pParse); if( groupBySort ){ - sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, sortOut,sortPTab); + sqlite3VdbeAddOp3(v, OP_SorterData, sAggInfo.sortingIdx, + sortOut, sortPTab); } for(j=0; jnExpr; j++){ if( groupBySort ){ @@ -5400,7 +5406,8 @@ int sqlite3Select( sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); sqlite3VdbeResolveLabel(v, addrOutputRow); addrOutputRow = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); VdbeCoverage(v); + sqlite3VdbeAddOp2(v, OP_IfPos, iUseFlag, addrOutputRow+2); + VdbeCoverage(v); VdbeComment((v, "Groupby result generator entry point")); sqlite3VdbeAddOp1(v, OP_Return, regOutputRow); finalizeAggFunctions(pParse, &sAggInfo); @@ -5564,7 +5571,8 @@ int sqlite3Select( ** and send them to the callback one by one. */ if( sSort.pOrderBy ){ - explainTempTable(pParse, sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY"); + explainTempTable(pParse, + sSort.nOBSat>0 ? "RIGHT PART OF ORDER BY":"ORDER BY"); generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest); } @@ -5596,97 +5604,3 @@ select_end: #endif return rc; } - -#ifdef SQLITE_DEBUG -/* -** Generate a human-readable description of a the Select object. -*/ -void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ - int n = 0; - pView = sqlite3TreeViewPush(pView, moreToFollow); - sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x", - ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), - ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags - ); - 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; - pView = sqlite3TreeViewPush(pView, (n--)>0); - sqlite3TreeViewLine(pView, "FROM"); - for(i=0; ipSrc->nSrc; i++){ - struct SrcList_item *pItem = &p->pSrc->a[i]; - StrAccum x; - char zLine[100]; - 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); - }else if( pItem->zName ){ - sqlite3XPrintf(&x, 0, " %s", pItem->zName); - } - if( pItem->pTab ){ - sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName); - } - if( pItem->zAlias ){ - sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias); - } - if( pItem->jointype & JT_LEFT ){ - sqlite3XPrintf(&x, 0, " LEFT-JOIN"); - } - sqlite3StrAccumFinish(&x); - sqlite3TreeViewItem(pView, zLine, ipSrc->nSrc-1); - if( pItem->pSelect ){ - sqlite3TreeViewSelect(pView, pItem->pSelect, 0); - } - sqlite3TreeViewPop(pView); - } - sqlite3TreeViewPop(pView); - } - if( p->pWhere ){ - sqlite3TreeViewItem(pView, "WHERE", (n--)>0); - sqlite3TreeViewExpr(pView, p->pWhere, 0); - sqlite3TreeViewPop(pView); - } - if( p->pGroupBy ){ - sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY"); - } - if( p->pHaving ){ - sqlite3TreeViewItem(pView, "HAVING", (n--)>0); - sqlite3TreeViewExpr(pView, p->pHaving, 0); - sqlite3TreeViewPop(pView); - } - if( p->pOrderBy ){ - sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); - } - if( p->pLimit ){ - sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); - sqlite3TreeViewExpr(pView, p->pLimit, 0); - sqlite3TreeViewPop(pView); - } - if( p->pOffset ){ - 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); -} -#endif /* SQLITE_DEBUG */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 5b7fbbc835..43e4b0be9b 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3170,10 +3170,6 @@ char *sqlite3VMPrintf(sqlite3*,const char*, va_list); #endif #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); diff --git a/src/treeview.c b/src/treeview.c new file mode 100644 index 0000000000..7b63c884e7 --- /dev/null +++ b/src/treeview.c @@ -0,0 +1,425 @@ +/* +** 2015-06-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 C code to implement the TreeView debugging routines. +** These routines print a parse tree to standard output for debugging and +** analysis. +** +** The interfaces in this file is only available when compiling +** with SQLITE_DEBUG. +*/ +#include "sqliteInt.h" +#ifdef SQLITE_DEBUG + +/* +** Add a new subitem to the tree. The moreToFollow flag indicates that this +** is not the last item in the tree. +*/ +static TreeView *sqlite3TreeViewPush(TreeView *p, u8 moreToFollow){ + if( p==0 ){ + p = sqlite3_malloc64( 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 +*/ +static 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 +*/ +static void sqlite3TreeViewLine(TreeView *p, const char *zFormat, ...){ + va_list ap; + int i; + StrAccum acc; + char zBuf[500]; + sqlite3StrAccumInit(&acc, 0, zBuf, sizeof(zBuf), 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 +*/ +static void sqlite3TreeViewItem(TreeView *p, const char *zLabel,u8 moreFollows){ + p = sqlite3TreeViewPush(p, moreFollows); + sqlite3TreeViewLine(p, "%s", zLabel); +} + + +/* +** Generate a human-readable description of a the Select object. +*/ +void sqlite3TreeViewSelect(TreeView *pView, const Select *p, u8 moreToFollow){ + int n = 0; + pView = sqlite3TreeViewPush(pView, moreToFollow); + sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x", + ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), + ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags + ); + 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; + pView = sqlite3TreeViewPush(pView, (n--)>0); + sqlite3TreeViewLine(pView, "FROM"); + for(i=0; ipSrc->nSrc; i++){ + struct SrcList_item *pItem = &p->pSrc->a[i]; + StrAccum x; + char zLine[100]; + 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); + }else if( pItem->zName ){ + sqlite3XPrintf(&x, 0, " %s", pItem->zName); + } + if( pItem->pTab ){ + sqlite3XPrintf(&x, 0, " tabname=%Q", pItem->pTab->zName); + } + if( pItem->zAlias ){ + sqlite3XPrintf(&x, 0, " (AS %s)", pItem->zAlias); + } + if( pItem->jointype & JT_LEFT ){ + sqlite3XPrintf(&x, 0, " LEFT-JOIN"); + } + sqlite3StrAccumFinish(&x); + sqlite3TreeViewItem(pView, zLine, ipSrc->nSrc-1); + if( pItem->pSelect ){ + sqlite3TreeViewSelect(pView, pItem->pSelect, 0); + } + sqlite3TreeViewPop(pView); + } + sqlite3TreeViewPop(pView); + } + if( p->pWhere ){ + sqlite3TreeViewItem(pView, "WHERE", (n--)>0); + sqlite3TreeViewExpr(pView, p->pWhere, 0); + sqlite3TreeViewPop(pView); + } + if( p->pGroupBy ){ + sqlite3TreeViewExprList(pView, p->pGroupBy, (n--)>0, "GROUPBY"); + } + if( p->pHaving ){ + sqlite3TreeViewItem(pView, "HAVING", (n--)>0); + sqlite3TreeViewExpr(pView, p->pHaving, 0); + sqlite3TreeViewPop(pView); + } + if( p->pOrderBy ){ + sqlite3TreeViewExprList(pView, p->pOrderBy, (n--)>0, "ORDERBY"); + } + if( p->pLimit ){ + sqlite3TreeViewItem(pView, "LIMIT", (n--)>0); + sqlite3TreeViewExpr(pView, p->pLimit, 0); + sqlite3TreeViewPop(pView); + } + if( p->pOffset ){ + 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); +} + +/* +** Generate a human-readable explanation of an expression tree. +*/ +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 ){ + sqlite3TreeViewLine(pView, "nil"); + sqlite3TreeViewPop(pView); + return; + } + switch( pExpr->op ){ + case TK_AGG_COLUMN: { + sqlite3TreeViewLine(pView, "AGG{%d:%d}", + pExpr->iTable, pExpr->iColumn); + break; + } + case TK_COLUMN: { + if( pExpr->iTable<0 ){ + /* This only happens when coding check constraints */ + sqlite3TreeViewLine(pView, "COLUMN(%d)", pExpr->iColumn); + }else{ + sqlite3TreeViewLine(pView, "{%d:%d}", + pExpr->iTable, pExpr->iColumn); + } + break; + } + case TK_INTEGER: { + if( pExpr->flags & EP_IntValue ){ + sqlite3TreeViewLine(pView, "%d", pExpr->u.iValue); + }else{ + sqlite3TreeViewLine(pView, "%s", pExpr->u.zToken); + } + break; + } +#ifndef SQLITE_OMIT_FLOATING_POINT + case TK_FLOAT: { + sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); + break; + } +#endif + case TK_STRING: { + sqlite3TreeViewLine(pView,"%Q", pExpr->u.zToken); + break; + } + case TK_NULL: { + sqlite3TreeViewLine(pView,"NULL"); + break; + } +#ifndef SQLITE_OMIT_BLOB_LITERAL + case TK_BLOB: { + sqlite3TreeViewLine(pView,"%s", pExpr->u.zToken); + break; + } +#endif + case TK_VARIABLE: { + sqlite3TreeViewLine(pView,"VARIABLE(%s,%d)", + pExpr->u.zToken, pExpr->iColumn); + break; + } + case TK_REGISTER: { + sqlite3TreeViewLine(pView,"REGISTER(%d)", pExpr->iTable); + break; + } + case TK_AS: { + sqlite3TreeViewLine(pView,"AS %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } + case TK_ID: { + sqlite3TreeViewLine(pView,"ID \"%w\"", pExpr->u.zToken); + break; + } +#ifndef SQLITE_OMIT_CAST + case TK_CAST: { + /* Expressions of the form: CAST(pLeft AS token) */ + sqlite3TreeViewLine(pView,"CAST %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } +#endif /* SQLITE_OMIT_CAST */ + case TK_LT: zBinOp = "LT"; break; + case TK_LE: zBinOp = "LE"; break; + case TK_GT: zBinOp = "GT"; break; + case TK_GE: zBinOp = "GE"; break; + case TK_NE: zBinOp = "NE"; break; + case TK_EQ: zBinOp = "EQ"; break; + case TK_IS: zBinOp = "IS"; break; + case TK_ISNOT: zBinOp = "ISNOT"; break; + case TK_AND: zBinOp = "AND"; break; + case TK_OR: zBinOp = "OR"; break; + case TK_PLUS: zBinOp = "ADD"; break; + case TK_STAR: zBinOp = "MUL"; break; + case TK_MINUS: zBinOp = "SUB"; break; + case TK_REM: zBinOp = "REM"; break; + case TK_BITAND: zBinOp = "BITAND"; break; + case TK_BITOR: zBinOp = "BITOR"; break; + case TK_SLASH: zBinOp = "DIV"; break; + 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; + case TK_BITNOT: zUniOp = "BITNOT"; break; + case TK_NOT: zUniOp = "NOT"; break; + case TK_ISNULL: zUniOp = "ISNULL"; break; + case TK_NOTNULL: zUniOp = "NOTNULL"; break; + + case TK_COLLATE: { + sqlite3TreeViewLine(pView, "COLLATE %Q", pExpr->u.zToken); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + break; + } + + case TK_AGG_FUNCTION: + case TK_FUNCTION: { + ExprList *pFarg; /* List of function arguments */ + if( ExprHasProperty(pExpr, EP_TokenOnly) ){ + pFarg = 0; + }else{ + pFarg = pExpr->x.pList; + } + if( pExpr->op==TK_AGG_FUNCTION ){ + sqlite3TreeViewLine(pView, "AGG_FUNCTION%d %Q", + pExpr->op2, pExpr->u.zToken); + }else{ + sqlite3TreeViewLine(pView, "FUNCTION %Q", pExpr->u.zToken); + } + if( pFarg ){ + sqlite3TreeViewExprList(pView, pFarg, 0, 0); + } + break; + } +#ifndef SQLITE_OMIT_SUBQUERY + case TK_EXISTS: { + sqlite3TreeViewLine(pView, "EXISTS-expr"); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); + break; + } + case TK_SELECT: { + sqlite3TreeViewLine(pView, "SELECT-expr"); + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); + break; + } + case TK_IN: { + sqlite3TreeViewLine(pView, "IN"); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + if( ExprHasProperty(pExpr, EP_xIsSelect) ){ + sqlite3TreeViewSelect(pView, pExpr->x.pSelect, 0); + }else{ + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); + } + break; + } +#endif /* SQLITE_OMIT_SUBQUERY */ + + /* + ** x BETWEEN y AND z + ** + ** This is equivalent to + ** + ** x>=y AND x<=z + ** + ** X is stored in pExpr->pLeft. + ** Y is stored in pExpr->pList->a[0].pExpr. + ** Z is stored in pExpr->pList->a[1].pExpr. + */ + case TK_BETWEEN: { + Expr *pX = pExpr->pLeft; + Expr *pY = pExpr->x.pList->a[0].pExpr; + Expr *pZ = pExpr->x.pList->a[1].pExpr; + sqlite3TreeViewLine(pView, "BETWEEN"); + sqlite3TreeViewExpr(pView, pX, 1); + sqlite3TreeViewExpr(pView, pY, 1); + sqlite3TreeViewExpr(pView, pZ, 0); + break; + } + case TK_TRIGGER: { + /* If the opcode is TK_TRIGGER, then the expression is a reference + ** to a column in the new.* or old.* pseudo-tables available to + ** trigger programs. In this case Expr.iTable is set to 1 for the + ** new.* pseudo-table, or 0 for the old.* pseudo-table. Expr.iColumn + ** is set to the column of the pseudo-table to read, or to -1 to + ** read the rowid field. + */ + sqlite3TreeViewLine(pView, "%s(%d)", + pExpr->iTable ? "NEW" : "OLD", pExpr->iColumn); + break; + } + case TK_CASE: { + sqlite3TreeViewLine(pView, "CASE"); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0); + break; + } +#ifndef SQLITE_OMIT_TRIGGER + case TK_RAISE: { + const char *zType = "unk"; + switch( pExpr->affinity ){ + case OE_Rollback: zType = "rollback"; break; + case OE_Abort: zType = "abort"; break; + case OE_Fail: zType = "fail"; break; + case OE_Ignore: zType = "ignore"; break; + } + sqlite3TreeViewLine(pView, "RAISE %s(%Q)", zType, pExpr->u.zToken); + break; + } +#endif + default: { + sqlite3TreeViewLine(pView, "op=%d", pExpr->op); + break; + } + } + if( zBinOp ){ + sqlite3TreeViewLine(pView, "%s", zBinOp); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 1); + sqlite3TreeViewExpr(pView, pExpr->pRight, 0); + }else if( zUniOp ){ + sqlite3TreeViewLine(pView, "%s", zUniOp); + sqlite3TreeViewExpr(pView, pExpr->pLeft, 0); + } + sqlite3TreeViewPop(pView); +} + +/* +** Generate a human-readable explanation of an expression list. +*/ +void sqlite3TreeViewExprList( + TreeView *pView, + const ExprList *pList, + u8 moreToFollow, + const char *zLabel +){ + int i; + pView = sqlite3TreeViewPush(pView, moreToFollow); + if( zLabel==0 || zLabel[0]==0 ) zLabel = "LIST"; + if( pList==0 ){ + sqlite3TreeViewLine(pView, "%s (empty)", zLabel); + }else{ + sqlite3TreeViewLine(pView, "%s", zLabel); + for(i=0; inExpr; i++){ + sqlite3TreeViewExpr(pView, pList->a[i].pExpr, inExpr-1); + } + } + sqlite3TreeViewPop(pView); +} + +#endif /* SQLITE_DEBUG */ diff --git a/tool/mksqlite3c.tcl b/tool/mksqlite3c.tcl index 320a12eef1..5b00368427 100644 --- a/tool/mksqlite3c.tcl +++ b/tool/mksqlite3c.tcl @@ -289,6 +289,7 @@ foreach file { mutex_w32.c malloc.c printf.c + treeview.c random.c threads.c utf.c From f5b5f9b97211e772b49d37dbde0bec9a2bd2eef9 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Mon, 8 Jun 2015 17:42:57 +0000 Subject: [PATCH 18/28] Fix typo in comment. No changes to code. FossilOrigin-Name: e49c291735e613e384f6da044ef865dd274cabc8 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/printf.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 107500a732..899c066981 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Split\sout\ssome\ssource\scode\sinto\snew\sfiles:\swherecode.c,\swhereexpr.c,\sand\ntreeview.c.\s\sOther\sminor\srefactoring\schanges. -D 2015-06-08T17:40:30.804 +C Fix\stypo\sin\scomment.\s\sNo\schanges\sto\scode. +D 2015-06-08T17:42:57.317 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a7b384855b72378fd860425b128ea5f75296e9d6 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -246,7 +246,7 @@ F src/pcache1.c 69d137620a305f814398bd29a0c998038c0695e9 F src/pragma.c c1f4d012ea9f6b1ce52d341b2cd0ad72d560afd7 F src/pragma.h b8632d7cdda7b25323fa580e3e558a4f0d4502cc F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 -F src/printf.c 9889e8826f8e2bd8c2718d7d3faa761bef8eac79 +F src/printf.c db11b5960105ee661dcac690f2ae6276e49bf251 F src/random.c ba2679f80ec82c4190062d756f22d0c358180696 F src/resolve.c 84c571794e3ee5806274d95158a4c0177c6c4708 F src/rowset.c eccf6af6d620aaa4579bd3b72c1b6395d9e9fa1e @@ -1285,7 +1285,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 283bf0b64da7acc5aa5812fc659954965002d409 c32ce54ca46a4be4373983be6fd44b1f3a0250d1 -R b8b4fb0f1a8beaad9f2b2c3f4237ea7b -U drh -Z 5b9788fbc214053ba5053f4dafcfebef +P 50f336818c8509d8b8bde282e9399d2b2b5ea70a +R 960d1cfe6672a4659b85889f9d77d89d +U mistachkin +Z 915f959f38ed01d6c5f7a7f0fd181c25 diff --git a/manifest.uuid b/manifest.uuid index 6f08cec969..3649605487 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -50f336818c8509d8b8bde282e9399d2b2b5ea70a \ No newline at end of file +e49c291735e613e384f6da044ef865dd274cabc8 \ No newline at end of file diff --git a/src/printf.c b/src/printf.c index ebdf44518f..72b9497d7b 100644 --- a/src/printf.c +++ b/src/printf.c @@ -7,7 +7,7 @@ ** This file contains code for a set of "printf"-like routines. These ** routines format strings much like the printf() from the standard C ** library, though the implementation here has enhancements to support -** SQLlite. +** SQLite. */ #include "sqliteInt.h" From 4f20cd402b5ba0aa7cccd76fda51ad71d1f8367b Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 8 Jun 2015 18:05:54 +0000 Subject: [PATCH 19/28] Avoid passing constraints that are unusable due to LEFT or CROSS joins to virtual table xBestIndex() methods. FossilOrigin-Name: 80ee56dda7db3860f8be5f6968c8745138f8453f --- ext/rtree/rtreeC.test | 83 +++++++++++++++++++++++++++++++++++++++++++ manifest | 19 +++++----- manifest.uuid | 2 +- src/where.c | 69 +++++++++++++++++++++++++++-------- 4 files changed, 150 insertions(+), 23 deletions(-) diff --git a/ext/rtree/rtreeC.test b/ext/rtree/rtreeC.test index 94db05a4d1..9a64df51d5 100644 --- a/ext/rtree/rtreeC.test +++ b/ext/rtree/rtreeC.test @@ -269,5 +269,88 @@ ifcapable rtree { db close } +#-------------------------------------------------------------------- +# Test that queries featuring LEFT or CROSS JOINS are handled correctly. +# Handled correctly in this case means: +# +# * Terms with prereqs that appear to the left of a LEFT JOIN against +# the virtual table are always available to xBestIndex. +# +# * Terms with prereqs that appear to the right of a LEFT JOIN against +# the virtual table are never available to xBestIndex. +# +# And the same behaviour for CROSS joins. +# +reset_db +do_execsql_test 7.0 { + CREATE TABLE xdir(x1); + CREATE TABLE ydir(y1); + CREATE VIRTUAL TABLE rt USING rtree_i32(id, xmin, xmax, ymin, ymax); + + INSERT INTO xdir VALUES(5); + INSERT INTO ydir VALUES(10); + + INSERT INTO rt VALUES(1, 2, 7, 12, 14); -- Not a hit + INSERT INTO rt VALUES(2, 2, 7, 8, 12); -- A hit! + INSERT INTO rt VALUES(3, 7, 11, 8, 12); -- Not a hit! + INSERT INTO rt VALUES(4, 5, 5, 10, 10); -- A hit! + +} + +proc do_eqp_execsql_test {tn sql res} { + set query "EXPLAIN QUERY PLAN $sql ; $sql " + uplevel [list do_execsql_test $tn $query $res] +} + +do_eqp_execsql_test 7.1 { + SELECT id FROM xdir, rt, ydir + ON (y1 BETWEEN ymin AND ymax) + WHERE (x1 BETWEEN xmin AND xmax); +} { + 0 0 0 {SCAN TABLE xdir} + 0 1 2 {SCAN TABLE ydir} + 0 2 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B2D3B0D1} + 2 4 +} + +do_eqp_execsql_test 7.2 { + SELECT * FROM xdir, rt LEFT JOIN ydir + ON (y1 BETWEEN ymin AND ymax) + WHERE (x1 BETWEEN xmin AND xmax); +} { + 0 0 0 {SCAN TABLE xdir} + 0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1} + 0 2 2 {SCAN TABLE ydir} + + 5 1 2 7 12 14 {} + 5 2 2 7 8 12 10 + 5 4 5 5 10 10 10 +} + +do_eqp_execsql_test 7.3 { + SELECT id FROM xdir, rt CROSS JOIN ydir + ON (y1 BETWEEN ymin AND ymax) + WHERE (x1 BETWEEN xmin AND xmax); +} { + 0 0 0 {SCAN TABLE xdir} + 0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1} + 0 2 2 {SCAN TABLE ydir} + 2 4 +} + +do_eqp_execsql_test 7.4 { + SELECT id FROM rt, xdir CROSS JOIN ydir + ON (y1 BETWEEN ymin AND ymax) + WHERE (x1 BETWEEN xmin AND xmax); +} { + 0 0 1 {SCAN TABLE xdir} + 0 1 0 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1} + 0 2 2 {SCAN TABLE ydir} + 2 4 +} + +finish_test + + finish_test diff --git a/manifest b/manifest index 899c066981..fb3c09a77c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stypo\sin\scomment.\s\sNo\schanges\sto\scode. -D 2015-06-08T17:42:57.317 +C Avoid\spassing\sconstraints\sthat\sare\sunusable\sdue\sto\sLEFT\sor\sCROSS\sjoins\sto\svirtual\stable\sxBestIndex()\smethods. +D 2015-06-08T18:05:54.638 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a7b384855b72378fd860425b128ea5f75296e9d6 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -156,7 +156,7 @@ F ext/rtree/rtree8.test db79c812f9e4a11f9b1f3f9934007884610a713a F ext/rtree/rtree9.test b5eb13849545dfd271a54ff16784cb00d8792aea F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf F ext/rtree/rtreeB.test c85f9ce78766c4e68b8b89fbf2979ee9cfa82b4e -F ext/rtree/rtreeC.test df158dcc81f1a43ce7eef361af03c48ec91f1e06 +F ext/rtree/rtreeC.test 90aaaffe2fd4f0dcd12289cad5515f6d41f45ffd F ext/rtree/rtreeD.test 636630357638f5983701550b37f0f5867130d2ca F ext/rtree/rtreeE.test 45a147a64a76306172819562309681d8e90f94bb F ext/rtree/rtreeF.test 66deb9fd1611c7ca2e374adba63debdc2dbb12b4 @@ -327,7 +327,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c a328fcc3342044992644b6a11bf301593b8dafb4 +F src/where.c 38b2c4bea9e7a76f882d49c2808e0907e29e2a6d F src/whereInt.h 5f87e3c4b0551747d119730dfebddd3c54f04047 F src/wherecode.c 0669481cabaf5caf934b6bb825df15bc57f60d40 F src/whereexpr.c 9ce1c9cfedbf80c93c7d899497025ec8256ce652 @@ -1285,7 +1285,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 50f336818c8509d8b8bde282e9399d2b2b5ea70a -R 960d1cfe6672a4659b85889f9d77d89d -U mistachkin -Z 915f959f38ed01d6c5f7a7f0fd181c25 +P e49c291735e613e384f6da044ef865dd274cabc8 +R 861f3c87e22a2bd19cbd1623c84fcecb +T *branch * vtab-left-join +T *sym-vtab-left-join * +T -sym-trunk * +U dan +Z 3d7670af603531efb0f4fc0b8b662b61 diff --git a/manifest.uuid b/manifest.uuid index 3649605487..2e337e3eb9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e49c291735e613e384f6da044ef865dd274cabc8 \ No newline at end of file +80ee56dda7db3860f8be5f6968c8745138f8453f \ No newline at end of file diff --git a/src/where.c b/src/where.c index 5c5022c9f6..738c5dbdc4 100644 --- a/src/where.c +++ b/src/where.c @@ -757,6 +757,7 @@ end_auto_index_create: static sqlite3_index_info *allocateIndexInfo( Parse *pParse, WhereClause *pWC, + Bitmask mUnusable, /* Ignore terms with these prereqs */ struct SrcList_item *pSrc, ExprList *pOrderBy ){ @@ -773,6 +774,7 @@ static sqlite3_index_info *allocateIndexInfo( ** to this virtual table */ for(i=nTerm=0, pTerm=pWC->a; inTerm; i++, pTerm++){ if( pTerm->leftCursor != pSrc->iCursor ) continue; + if( pTerm->prereqRight & mUnusable ) continue; assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); testcase( pTerm->eOperator & WO_IN ); testcase( pTerm->eOperator & WO_ISNULL ); @@ -827,6 +829,7 @@ static sqlite3_index_info *allocateIndexInfo( for(i=j=0, pTerm=pWC->a; inTerm; i++, pTerm++){ u8 op; if( pTerm->leftCursor != pSrc->iCursor ) continue; + if( pTerm->prereqRight & mUnusable ) continue; assert( IsPowerOfTwo(pTerm->eOperator & ~WO_EQUIV) ); testcase( pTerm->eOperator & WO_IN ); testcase( pTerm->eOperator & WO_IS ); @@ -2666,10 +2669,32 @@ static int whereLoopAddBtree( /* ** Add all WhereLoop objects for a table of the join identified by ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. +** +** If there are no LEFT or CROSS JOIN joins in the query, both mExtra and +** mUnusable are set to 0. Otherwise, mExtra is a mask of all FROM clause +** entries that occur before the virtual table in the FROM clause and are +** separated from it by at least one LEFT or CROSS JOIN. Similarly, the +** mUnusable mask contains all FROM clause entries that occur after the +** virtual table and are separated from it by at least one LEFT or +** CROSS JOIN. +** +** For example, if the query were: +** +** ... FROM t1, t2 LEFT JOIN t3, t4, vt CROSS JOIN t5, t6; +** +** then mExtra corresponds to (t1, t2) and mUnusable to (t5, t6). +** +** All the tables in mExtra must be scanned before the current virtual +** table. So any terms for which all prerequisites are satisfied by +** mExtra may be specified as "usable" in all calls to xBestIndex. +** Conversely, all tables in mUnusable must be scanned after the current +** virtual table, so any terms for which the prerequisites overlap with +** mUnusable should always be configured as "not-usable" for xBestIndex. */ static int whereLoopAddVirtual( WhereLoopBuilder *pBuilder, /* WHERE clause information */ - Bitmask mExtra + Bitmask mExtra, /* Tables that must be scanned before this one */ + Bitmask mUnusable /* Tables that must be scanned after this one */ ){ WhereInfo *pWInfo; /* WHERE analysis context */ Parse *pParse; /* The parsing context */ @@ -2690,6 +2715,7 @@ static int whereLoopAddVirtual( WhereLoop *pNew; int rc = SQLITE_OK; + assert( (mExtra & mUnusable)==0 ); pWInfo = pBuilder->pWInfo; pParse = pWInfo->pParse; db = pParse->db; @@ -2698,7 +2724,7 @@ static int whereLoopAddVirtual( pSrc = &pWInfo->pTabList->a[pNew->iTab]; pTab = pSrc->pTab; assert( IsVirtual(pTab) ); - pIdxInfo = allocateIndexInfo(pParse, pWC, pSrc, pBuilder->pOrderBy); + pIdxInfo = allocateIndexInfo(pParse, pWC, mUnusable, pSrc,pBuilder->pOrderBy); if( pIdxInfo==0 ) return SQLITE_NOMEM; pNew->prereq = 0; pNew->rSetup = 0; @@ -2728,7 +2754,7 @@ static int whereLoopAddVirtual( if( (pTerm->eOperator & WO_IN)!=0 ){ seenIn = 1; } - if( pTerm->prereqRight!=0 ){ + if( (pTerm->prereqRight & ~mExtra)!=0 ){ seenVar = 1; }else if( (pTerm->eOperator & WO_IN)==0 ){ pIdxCons->usable = 1; @@ -2736,7 +2762,7 @@ static int whereLoopAddVirtual( break; case 1: /* Constants with IN operators */ assert( seenIn ); - pIdxCons->usable = (pTerm->prereqRight==0); + pIdxCons->usable = (pTerm->prereqRight & ~mExtra)==0; break; case 2: /* Variables without IN */ assert( seenVar ); @@ -2835,7 +2861,11 @@ whereLoopAddVtab_exit: ** Add WhereLoop entries to handle OR terms. This works for either ** btrees or virtual tables. */ -static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ +static int whereLoopAddOr( + WhereLoopBuilder *pBuilder, + Bitmask mExtra, + Bitmask mUnusable +){ WhereInfo *pWInfo = pBuilder->pWInfo; WhereClause *pWC; WhereLoop *pNew; @@ -2894,14 +2924,14 @@ static int whereLoopAddOr(WhereLoopBuilder *pBuilder, Bitmask mExtra){ #endif #ifndef SQLITE_OMIT_VIRTUALTABLE if( IsVirtual(pItem->pTab) ){ - rc = whereLoopAddVirtual(&sSubBuild, mExtra); + rc = whereLoopAddVirtual(&sSubBuild, mExtra, mUnusable); }else #endif { rc = whereLoopAddBtree(&sSubBuild, mExtra); } if( rc==SQLITE_OK ){ - rc = whereLoopAddOr(&sSubBuild, mExtra); + rc = whereLoopAddOr(&sSubBuild, mExtra, mUnusable); } assert( rc==SQLITE_OK || sCur.n==0 ); if( sCur.n==0 ){ @@ -2963,33 +2993,44 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ int iTab; SrcList *pTabList = pWInfo->pTabList; struct SrcList_item *pItem; + struct SrcList_item *pEnd = &pTabList->a[pWInfo->nLevel]; sqlite3 *db = pWInfo->pParse->db; - int nTabList = pWInfo->nLevel; int rc = SQLITE_OK; - u8 priorJoinType = 0; WhereLoop *pNew; + pNew = pBuilder->pNew; + whereLoopInit(pNew); + /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; whereLoopInit(pNew); - for(iTab=0, pItem=pTabList->a; iTaba; pItemiTab = iTab; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); - if( ((pItem->jointype|priorJoinType) & (JT_LEFT|JT_CROSS))!=0 ){ + if( (pItem->jointype & (JT_LEFT|JT_CROSS))!=0 ){ + /* This condition is true when pItem is the FROM clause term on the + ** right-hand-side of a LEFT or CROSS JOIN. */ mExtra = mPrior; } - priorJoinType = pItem->jointype; if( IsVirtual(pItem->pTab) ){ - rc = whereLoopAddVirtual(pBuilder, mExtra); + struct SrcList_item *p; + for(p=&pItem[1]; pjointype & (JT_LEFT|JT_CROSS)) ){ + mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); + } + } + rc = whereLoopAddVirtual(pBuilder, mExtra, mUnusable); }else{ rc = whereLoopAddBtree(pBuilder, mExtra); } if( rc==SQLITE_OK ){ - rc = whereLoopAddOr(pBuilder, mExtra); + rc = whereLoopAddOr(pBuilder, mExtra, mUnusable); } mPrior |= pNew->maskSelf; if( rc || db->mallocFailed ) break; } + whereLoopClear(db, pNew); return rc; } From 35175bf7ab1b4aa3e91119d7d8dde8292f891129 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 8 Jun 2015 18:48:29 +0000 Subject: [PATCH 20/28] If a query contains "FROM t1 LEFT JOIN t2, t3, t4", ensure that tables t3 and t4 are not scanned before t2. The trunk already does this. FossilOrigin-Name: 0d9edfab9fb61322620f188b48ae2a1798a07581 --- manifest | 17 +++++++---------- manifest.uuid | 2 +- src/where.c | 4 +++- test/join.test | 26 ++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index fb3c09a77c..6b7f8b83ec 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\spassing\sconstraints\sthat\sare\sunusable\sdue\sto\sLEFT\sor\sCROSS\sjoins\sto\svirtual\stable\sxBestIndex()\smethods. -D 2015-06-08T18:05:54.638 +C If\sa\squery\scontains\s"FROM\st1\sLEFT\sJOIN\st2,\st3,\st4",\sensure\sthat\stables\st3\sand\st4\sare\snot\sscanned\sbefore\st2.\sThe\strunk\salready\sdoes\sthis. +D 2015-06-08T18:48:29.533 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a7b384855b72378fd860425b128ea5f75296e9d6 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -327,7 +327,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c 38b2c4bea9e7a76f882d49c2808e0907e29e2a6d +F src/where.c d98dd9461feb44daabfa0fe64831970bc0daacf2 F src/whereInt.h 5f87e3c4b0551747d119730dfebddd3c54f04047 F src/wherecode.c 0669481cabaf5caf934b6bb825df15bc57f60d40 F src/whereexpr.c 9ce1c9cfedbf80c93c7d899497025ec8256ce652 @@ -709,7 +709,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 52d4d49f86d0cf46926672878c4eaf0da399104a +F test/join.test f9d4a28dec81c6e9dc21b73518e024d73b5ebf57 F test/join2.test f2171c265e57ee298a27e57e7051d22962f9f324 F test/join3.test 6f0c774ff1ba0489e6c88a3e77b9d3528fb4fda0 F test/join4.test 1a352e4e267114444c29266ce79e941af5885916 @@ -1285,10 +1285,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P e49c291735e613e384f6da044ef865dd274cabc8 -R 861f3c87e22a2bd19cbd1623c84fcecb -T *branch * vtab-left-join -T *sym-vtab-left-join * -T -sym-trunk * +P 80ee56dda7db3860f8be5f6968c8745138f8453f +R dd22f5dd58533915c3eebee09006a2ae U dan -Z 3d7670af603531efb0f4fc0b8b662b61 +Z 7d33e5ba0e6b939fee95e64c7940bec7 diff --git a/manifest.uuid b/manifest.uuid index 2e337e3eb9..150167c0c5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -80ee56dda7db3860f8be5f6968c8745138f8453f \ No newline at end of file +0d9edfab9fb61322620f188b48ae2a1798a07581 \ No newline at end of file diff --git a/src/where.c b/src/where.c index 738c5dbdc4..41ff393cde 100644 --- a/src/where.c +++ b/src/where.c @@ -2997,6 +2997,7 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ sqlite3 *db = pWInfo->pParse->db; int rc = SQLITE_OK; WhereLoop *pNew; + u8 priorJointype = 0; pNew = pBuilder->pNew; whereLoopInit(pNew); @@ -3008,11 +3009,12 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ Bitmask mUnusable = 0; pNew->iTab = iTab; pNew->maskSelf = sqlite3WhereGetMask(&pWInfo->sMaskSet, pItem->iCursor); - if( (pItem->jointype & (JT_LEFT|JT_CROSS))!=0 ){ + if( ((pItem->jointype|priorJointype) & (JT_LEFT|JT_CROSS))!=0 ){ /* This condition is true when pItem is the FROM clause term on the ** right-hand-side of a LEFT or CROSS JOIN. */ mExtra = mPrior; } + priorJointype = pItem->jointype; if( IsVirtual(pItem->pTab) ){ struct SrcList_item *p; for(p=&pItem[1]; p Date: Mon, 8 Jun 2015 19:15:50 +0000 Subject: [PATCH 21/28] Add the valgrindfuzz target to unix makefile. FossilOrigin-Name: e62aed01f1a6dbc12d6e21386c1671eb640b8d49 --- Makefile.in | 8 +++++--- main.mk | 6 ++++-- manifest | 16 ++++++++-------- manifest.uuid | 2 +- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Makefile.in b/Makefile.in index 1b7c7f9dc5..ded1687d34 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1004,9 +1004,12 @@ fulltestonly: $(TESTPROGS) ./testfixture$(TEXE) $(TOP)/test/full.test # Fuzz testing -fuzztest: fuzzcheck$(TEXE) +fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) ./fuzzcheck$(TEXE) $(FUZZDATA) +valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) + valgrind ./fuzzcheck$(TEXE) --cell-size-check --quiet $(FUZZDATA) + # This is the common case. Run many tests but not those that take # a really long time. # @@ -1016,8 +1019,7 @@ test: $(TESTPROGS) fuzztest # Run a test using valgrind. This can take a really long time # because valgrind is so much slower than a native machine. # -valgrindtest: $(TESTPROGS) fuzzcheck$(TEXE) - valgrind -v ./fuzzcheck$(TEXE) --cell-size-check --quiet $(FUZZDATA) +valgrindtest: $(TESTPROGS) valgrindfuzz OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind # A very fast test that checks basic sanity. The name comes from diff --git a/main.mk b/main.mk index 22fc700a75..b76972a9ed 100644 --- a/main.mk +++ b/main.mk @@ -682,14 +682,16 @@ queryplantest: testfixture$(EXE) sqlite3$(EXE) fuzztest: fuzzcheck$(EXE) $(FUZZDATA) ./fuzzcheck$(EXE) $(FUZZDATA) +valgrindfuzz: fuzzcheck$(EXE) $(FUZZDATA) + valgrind ./fuzzcheck$(EXE) --cell-size-check --quiet $(FUZZDATA) + test: $(TESTPROGS) 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: $(TESTPROGS) fuzzcheck$(EXE) $(FUZZDATA) - valgrind -v ./fuzzcheck$(EXE) --cell-size-check --quiet $(FUZZDATA) +valgrindtest: $(TESTPROGS) valgrindfuzz OMIT_MISUSE=1 valgrind -v ./testfixture$(EXE) $(TOP)/test/permutations.test valgrind # A very fast test that checks basic sanity. The name comes from diff --git a/manifest b/manifest index 899c066981..379ae835a6 100644 --- a/manifest +++ b/manifest @@ -1,7 +1,7 @@ -C Fix\stypo\sin\scomment.\s\sNo\schanges\sto\scode. -D 2015-06-08T17:42:57.317 +C Add\sthe\svalgrindfuzz\starget\sto\sunix\smakefile. +D 2015-06-08T19:15:50.266 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in a7b384855b72378fd860425b128ea5f75296e9d6 +F Makefile.in 580e006530fab67ccd34926ce2eda66d326af60f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.msc 5438dc167466f51349ab0c4497aef547d0c9352c F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858 @@ -171,7 +171,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk dc931768b88e4417bc2f8b2d45dba385ad29f727 +F main.mk 033741a45df95c577814914b13d182a0b6c7dc89 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk d5e22023b5238985bb54a72d33e0ac71fe4f8a32 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -1285,7 +1285,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 50f336818c8509d8b8bde282e9399d2b2b5ea70a -R 960d1cfe6672a4659b85889f9d77d89d -U mistachkin -Z 915f959f38ed01d6c5f7a7f0fd181c25 +P e49c291735e613e384f6da044ef865dd274cabc8 +R 038506d4cfda1e2a7849e18cec45efaf +U drh +Z dac87b83585efac2cb7ce09058568bbf diff --git a/manifest.uuid b/manifest.uuid index 3649605487..45549e71bb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e49c291735e613e384f6da044ef865dd274cabc8 \ No newline at end of file +e62aed01f1a6dbc12d6e21386c1671eb640b8d49 \ No newline at end of file From 4430b40934f9a5bb4a217123faddf0359e767b5e Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 9 Jun 2015 10:58:51 +0000 Subject: [PATCH 22/28] Remove some repeated lines of source code. Probably introduced by careless cut'n'pasting. FossilOrigin-Name: a34cd71c8aafaece04a2332a127e9b8e99c1403c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/where.c | 3 --- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 6b7f8b83ec..a11cdef71e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C If\sa\squery\scontains\s"FROM\st1\sLEFT\sJOIN\st2,\st3,\st4",\sensure\sthat\stables\st3\sand\st4\sare\snot\sscanned\sbefore\st2.\sThe\strunk\salready\sdoes\sthis. -D 2015-06-08T18:48:29.533 +C Remove\ssome\srepeated\slines\sof\ssource\scode.\sProbably\sintroduced\sby\scareless\scut'n'pasting. +D 2015-06-09T10:58:51.586 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in a7b384855b72378fd860425b128ea5f75296e9d6 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -327,7 +327,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c ce2cb2d06faab54d1bce3e739bec79e063dd9113 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c c253b95b4ee44b21c406e2a1052636c31ea27804 -F src/where.c d98dd9461feb44daabfa0fe64831970bc0daacf2 +F src/where.c 95c0fbfff7aef890b5da7293f6d85cd9a5f99af8 F src/whereInt.h 5f87e3c4b0551747d119730dfebddd3c54f04047 F src/wherecode.c 0669481cabaf5caf934b6bb825df15bc57f60d40 F src/whereexpr.c 9ce1c9cfedbf80c93c7d899497025ec8256ce652 @@ -1285,7 +1285,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 80ee56dda7db3860f8be5f6968c8745138f8453f -R dd22f5dd58533915c3eebee09006a2ae +P 0d9edfab9fb61322620f188b48ae2a1798a07581 +R 95c7a86e3c55ce5e80eb0382016d2fb7 U dan -Z 7d33e5ba0e6b939fee95e64c7940bec7 +Z e08af2de2874802b3cdcc1dde01f104f diff --git a/manifest.uuid b/manifest.uuid index 150167c0c5..e98d7dc3b7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0d9edfab9fb61322620f188b48ae2a1798a07581 \ No newline at end of file +a34cd71c8aafaece04a2332a127e9b8e99c1403c \ No newline at end of file diff --git a/src/where.c b/src/where.c index 41ff393cde..e32d176eac 100644 --- a/src/where.c +++ b/src/where.c @@ -2999,9 +2999,6 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ WhereLoop *pNew; u8 priorJointype = 0; - pNew = pBuilder->pNew; - whereLoopInit(pNew); - /* Loop over the tables in the join, from left to right */ pNew = pBuilder->pNew; whereLoopInit(pNew); From 17c0823bdaeadde5c68d4e1c9d9a0ddeb1f6a581 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 9 Jun 2015 15:58:28 +0000 Subject: [PATCH 23/28] Add the --output=$file and --verbose=(0|1|file) options to tester.tcl. FossilOrigin-Name: f7b2c70362f10ee0347c1d2318918ffefa53243d --- manifest | 14 ++-- manifest.uuid | 2 +- test/tester.tcl | 200 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 158 insertions(+), 58 deletions(-) diff --git a/manifest b/manifest index 379ae835a6..5c3fac5012 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\svalgrindfuzz\starget\sto\sunix\smakefile. -D 2015-06-08T19:15:50.266 +C Add\sthe\s--output=$file\sand\s--verbose=(0|1|file)\soptions\sto\stester.tcl. +D 2015-06-09T15:58:28.618 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 580e006530fab67ccd34926ce2eda66d326af60f F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -949,7 +949,7 @@ F test/tclsqlite.test 7fb866443c7deceed22b63948ccd6f76b52ad054 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 -F test/tester.tcl c18dbf42f4b0c1fb889b0efeb8a59d5143dd9828 +F test/tester.tcl ca396a3f867c1bd3603400ca8f17bbffd87985b7 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1285,7 +1285,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P e49c291735e613e384f6da044ef865dd274cabc8 -R 038506d4cfda1e2a7849e18cec45efaf -U drh -Z dac87b83585efac2cb7ce09058568bbf +P e62aed01f1a6dbc12d6e21386c1671eb640b8d49 +R f55cc3f41ca69cff9ff874d367e120de +U dan +Z 528ec808c863ae4b55820f5f3962de4a diff --git a/manifest.uuid b/manifest.uuid index 45549e71bb..0bf4f52403 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e62aed01f1a6dbc12d6e21386c1671eb640b8d49 \ No newline at end of file +f7b2c70362f10ee0347c1d2318918ffefa53243d \ No newline at end of file diff --git a/test/tester.tcl b/test/tester.tcl index 794ea4a406..a83054fbe7 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -81,6 +81,12 @@ # permutation # presql # +# Command to test whether or not --verbose=1 was specified on the command +# line (returns 0 for not-verbose, 1 for verbose and 2 for "verbose in the +# output file only"). +# +# verbose +# # Set the precision of FP arithmatic used by the interpreter. And # configure SQLite to take database file locks on the page that begins @@ -388,6 +394,9 @@ if {[info exists cmdlinearg]==0} { # --file-retry-delay=N # --start=[$permutation:]$testfile # --match=$pattern + # --verbose=$val + # --output=$filename + # --help # set cmdlinearg(soft-heap-limit) 0 set cmdlinearg(maxerror) 1000 @@ -399,6 +408,8 @@ if {[info exists cmdlinearg]==0} { set cmdlinearg(file-retry-delay) 0 set cmdlinearg(start) "" set cmdlinearg(match) "" + set cmdlinearg(verbose) "" + set cmdlinearg(output) "" set leftover [list] foreach a $argv { @@ -457,6 +468,22 @@ if {[info exists cmdlinearg]==0} { set ::G(match) $cmdlinearg(match) if {$::G(match) == ""} {unset ::G(match)} } + + {^-+output=.+$} { + foreach {dummy cmdlinearg(output)} [split $a =] break + if {$cmdlinearg(verbose)==""} { + set cmdlinearg(verbose) 2 + } + } + {^-+verbose=.+$} { + foreach {dummy cmdlinearg(verbose)} [split $a =] break + if {$cmdlinearg(verbose)=="file"} { + set cmdlinearg(verbose) 2 + } elseif {[string is boolean -strict $cmdlinearg(verbose)]==0} { + error "option --verbose= must be set to a boolean or to \"file\"" + } + } + default { lappend leftover $a } @@ -484,6 +511,16 @@ if {[info exists cmdlinearg]==0} { if {$cmdlinearg(malloctrace)} { sqlite3_memdebug_backtrace $cmdlinearg(backtrace) } + + if {$cmdlinearg(output)!=""} { + puts "Copying output to file $cmdlinearg(output)" + set ::G(output_fd) [open $cmdlinearg(output) w] + fconfigure $::G(output_fd) -buffering line + } + + if {$cmdlinearg(verbose)==""} { + set cmdlinearg(verbose) 1 + } } # Update the soft-heap-limit each time this script is run. In that @@ -554,7 +591,7 @@ proc fail_test {name} { set nFail [set_test_counter errors] if {$nFail>=$::cmdlinearg(maxerror)} { - puts "*** Giving up..." + output2 "*** Giving up..." finalize_testing } } @@ -562,7 +599,7 @@ proc fail_test {name} { # Remember a warning message to be displayed at the conclusion of all testing # proc warning {msg {append 1}} { - puts "Warning: $msg" + output2 "Warning: $msg" set warnList [set_test_counter warn_list] if {$append} { lappend warnList $msg @@ -577,6 +614,61 @@ proc incr_ntest {} { set_test_counter count [expr [set_test_counter count] + 1] } +# Return true if --verbose=1 was specified on the command line. Otherwise, +# return false. +# +proc verbose {} { + return $::cmdlinearg(verbose) +} + +# Use the following commands instead of [puts] for test output within +# this file. Test scripts can still use regular [puts], which is directed +# to stdout and, if one is open, the --output file. +# +# output1: output that should be printed if --verbose=1 was specified. +# output2: output that should be printed unconditionally. +# output2_if_no_verbose: output that should be printed only if --verbose=0. +# +proc output1 {args} { + set v [verbose] + if {$v==1} { + uplevel output2 $args + } elseif {$v==2} { + uplevel puts [lrange $args 0 end-1] $::G(output_fd) [lrange $args end end] + } +} +proc output2 {args} { + set nArg [llength $args] + uplevel puts $args +} +proc output2_if_no_verbose {args} { + set v [verbose] + if {$v==0} { + uplevel output2 $args + } elseif {$v==2} { + uplevel puts [lrange $args 0 end-1] stdout [lrange $args end end] + } +} + +# Override the [puts] command so that if no channel is explicitly +# specified the string is written to both stdout and to the file +# specified by "--output=", if any. +# +proc puts_override {args} { + set nArg [llength $args] + if {$nArg==1 || ($nArg==2 && [string first [lindex $args 0] -nonewline]==0)} { + uplevel puts_original $args + if {[info exists ::G(output_fd)]} { + uplevel puts [lrange $args 0 end-1] $::G(output_fd) [lrange $args end end] + } + } else { + # A channel was explicitly specified. + uplevel puts_original $args + } +} +rename puts puts_original +proc puts {args} { uplevel puts_override $args } + # Invoke the do_test procedure to run a single test # @@ -604,12 +696,13 @@ proc do_test {name cmd expected} { } incr_ntest - puts -nonewline $name... + output1 -nonewline $name... flush stdout if {![info exists ::G(match)] || [string match $::G(match) $name]} { if {[catch {uplevel #0 "$cmd;\n"} result]} { - puts "\nError: $result" + output2_if_no_verbose -nonewline $name... + output2 "\nError: $result" fail_test $name } else { if {[regexp {^~?/.*/$} $expected]} { @@ -653,14 +746,15 @@ proc do_test {name cmd expected} { # if {![info exists ::testprefix] || $::testprefix eq ""} { # error "no test prefix" # } - puts "\nExpected: \[$expected\]\n Got: \[$result\]" + output2_if_no_verbose -nonewline $name... + output2 "\nExpected: \[$expected\]\n Got: \[$result\]" fail_test $name } else { - puts " Ok" + output1 " Ok" } } } else { - puts " Omitted" + output1 " Omitted" omit_test $name "pattern mismatch" 0 } flush stdout @@ -837,7 +931,7 @@ proc delete_all_data {} { # Return the number of microseconds per statement. # proc speed_trial {name numstmt units sql} { - puts -nonewline [format {%-21.21s } $name...] + output2 -nonewline [format {%-21.21s } $name...] flush stdout set speed [time {sqlite3_exec_nr db $sql}] set tm [lindex $speed 0] @@ -847,13 +941,13 @@ proc speed_trial {name numstmt units sql} { set rate [format %20.5f [expr {1000000.0*$numstmt/$tm}]] } set u2 $units/s - puts [format {%12d uS %s %s} $tm $rate $u2] + output2 [format {%12d uS %s %s} $tm $rate $u2] global total_time set total_time [expr {$total_time+$tm}] lappend ::speed_trial_times $name $tm } proc speed_trial_tcl {name numstmt units script} { - puts -nonewline [format {%-21.21s } $name...] + output2 -nonewline [format {%-21.21s } $name...] flush stdout set speed [time {eval $script}] set tm [lindex $speed 0] @@ -863,7 +957,7 @@ proc speed_trial_tcl {name numstmt units script} { set rate [format %20.5f [expr {1000000.0*$numstmt/$tm}]] } set u2 $units/s - puts [format {%12d uS %s %s} $tm $rate $u2] + output2 [format {%12d uS %s %s} $tm $rate $u2] global total_time set total_time [expr {$total_time+$tm}] lappend ::speed_trial_times $name $tm @@ -875,19 +969,19 @@ proc speed_trial_init {name} { sqlite3 versdb :memory: set vers [versdb one {SELECT sqlite_source_id()}] versdb close - puts "SQLite $vers" + output2 "SQLite $vers" } proc speed_trial_summary {name} { global total_time - puts [format {%-21.21s %12d uS TOTAL} $name $total_time] + output2 [format {%-21.21s %12d uS TOTAL} $name $total_time] if { 0 } { sqlite3 versdb :memory: set vers [lindex [versdb one {SELECT sqlite_source_id()}] 0] versdb close - puts "CREATE TABLE IF NOT EXISTS time(version, script, test, us);" + output2 "CREATE TABLE IF NOT EXISTS time(version, script, test, us);" foreach {test us} $::speed_trial_times { - puts "INSERT INTO time VALUES('$vers', '$name', '$test', $us);" + output2 "INSERT INTO time VALUES('$vers', '$name', '$test', $us);" } } } @@ -931,75 +1025,75 @@ proc finalize_testing {} { } } if {$nKnown>0} { - puts "[expr {$nErr-$nKnown}] new errors and $nKnown known errors\ + output2 "[expr {$nErr-$nKnown}] new errors and $nKnown known errors\ out of $nTest tests" } else { - puts "$nErr errors out of $nTest tests" + output2 "$nErr errors out of $nTest tests" } if {$nErr>$nKnown} { - puts -nonewline "Failures on these tests:" + output2 -nonewline "Failures on these tests:" foreach x [set_test_counter fail_list] { - if {![info exists known_error($x)]} {puts -nonewline " $x"} + if {![info exists known_error($x)]} {output2 -nonewline " $x"} } - puts "" + output2 "" } foreach warning [set_test_counter warn_list] { - puts "Warning: $warning" + output2 "Warning: $warning" } run_thread_tests 1 if {[llength $omitList]>0} { - puts "Omitted test cases:" + output2 "Omitted test cases:" set prec {} foreach {rec} [lsort $omitList] { if {$rec==$prec} continue set prec $rec - puts [format { %-12s %s} [lindex $rec 0] [lindex $rec 1]] + output2 [format { %-12s %s} [lindex $rec 0] [lindex $rec 1]] } } if {$nErr>0 && ![working_64bit_int]} { - puts "******************************************************************" - puts "N.B.: The version of TCL that you used to build this test harness" - puts "is defective in that it does not support 64-bit integers. Some or" - puts "all of the test failures above might be a result from this defect" - puts "in your TCL build." - puts "******************************************************************" + output2 "******************************************************************" + output2 "N.B.: The version of TCL that you used to build this test harness" + output2 "is defective in that it does not support 64-bit integers. Some or" + output2 "all of the test failures above might be a result from this defect" + output2 "in your TCL build." + output2 "******************************************************************" } if {$::cmdlinearg(binarylog)} { vfslog finalize binarylog } if {$sqlite_open_file_count} { - puts "$sqlite_open_file_count files were left open" + output2 "$sqlite_open_file_count files were left open" incr nErr } if {[lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1]>0 || [sqlite3_memory_used]>0} { - puts "Unfreed memory: [sqlite3_memory_used] bytes in\ + output2 "Unfreed memory: [sqlite3_memory_used] bytes in\ [lindex [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] 1] allocations" incr nErr ifcapable memdebug||mem5||(mem3&&debug) { - puts "Writing unfreed memory log to \"./memleak.txt\"" + output2 "Writing unfreed memory log to \"./memleak.txt\"" sqlite3_memdebug_dump ./memleak.txt } } else { - puts "All memory allocations freed - no leaks" + output2 "All memory allocations freed - no leaks" ifcapable memdebug||mem5 { sqlite3_memdebug_dump ./memusage.txt } } show_memstats - puts "Maximum memory usage: [sqlite3_memory_highwater 1] bytes" - puts "Current memory usage: [sqlite3_memory_highwater] bytes" + output2 "Maximum memory usage: [sqlite3_memory_highwater 1] bytes" + output2 "Current memory usage: [sqlite3_memory_highwater] bytes" if {[info commands sqlite3_memdebug_malloc_count] ne ""} { - puts "Number of malloc() : [sqlite3_memdebug_malloc_count] calls" + output2 "Number of malloc() : [sqlite3_memdebug_malloc_count] calls" } if {$::cmdlinearg(malloctrace)} { - puts "Writing mallocs.sql..." + output2 "Writing mallocs.sql..." memdebug_log_sql sqlite3_memdebug_log stop sqlite3_memdebug_log clear if {[sqlite3_memory_used]>0} { - puts "Writing leaks.sql..." + output2 "Writing leaks.sql..." sqlite3_memdebug_log sync memdebug_log_sql leaks.sql } @@ -1020,30 +1114,30 @@ proc show_memstats {} { set y [sqlite3_status SQLITE_STATUS_MALLOC_SIZE 0] set val [format {now %10d max %10d max-size %10d} \ [lindex $x 1] [lindex $x 2] [lindex $y 2]] - puts "Memory used: $val" + output1 "Memory used: $val" set x [sqlite3_status SQLITE_STATUS_MALLOC_COUNT 0] set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]] - puts "Allocation count: $val" + output1 "Allocation count: $val" set x [sqlite3_status SQLITE_STATUS_PAGECACHE_USED 0] set y [sqlite3_status SQLITE_STATUS_PAGECACHE_SIZE 0] set val [format {now %10d max %10d max-size %10d} \ [lindex $x 1] [lindex $x 2] [lindex $y 2]] - puts "Page-cache used: $val" + output1 "Page-cache used: $val" set x [sqlite3_status SQLITE_STATUS_PAGECACHE_OVERFLOW 0] set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]] - puts "Page-cache overflow: $val" + output1 "Page-cache overflow: $val" set x [sqlite3_status SQLITE_STATUS_SCRATCH_USED 0] set val [format {now %10d max %10d} [lindex $x 1] [lindex $x 2]] - puts "Scratch memory used: $val" + output1 "Scratch memory used: $val" set x [sqlite3_status SQLITE_STATUS_SCRATCH_OVERFLOW 0] set y [sqlite3_status SQLITE_STATUS_SCRATCH_SIZE 0] set val [format {now %10d max %10d max-size %10d} \ [lindex $x 1] [lindex $x 2] [lindex $y 2]] - puts "Scratch overflow: $val" + output1 "Scratch overflow: $val" ifcapable yytrackmaxstackdepth { set x [sqlite3_status SQLITE_STATUS_PARSER_STACK 0] set val [format { max %10d} [lindex $x 2]] - puts "Parser stack depth: $val" + output2 "Parser stack depth: $val" } } @@ -1058,7 +1152,7 @@ proc execsql_timed {sql {db db}} { set x [uplevel [list $db eval $sql]] } 1] set tm [lindex $tm 0] - puts -nonewline " ([expr {$tm*0.001}]ms) " + output1 -nonewline " ([expr {$tm*0.001}]ms) " set x } @@ -1595,9 +1689,9 @@ proc do_ioerr_test {testname args} { set nowcksum [cksum] set res [expr {$nowcksum==$::checksum || $nowcksum==$::goodcksum}] if {$res==0} { - puts "now=$nowcksum" - puts "the=$::checksum" - puts "fwd=$::goodcksum" + output2 "now=$nowcksum" + output2 "the=$::checksum" + output2 "fwd=$::goodcksum" } set res } 1 @@ -1821,6 +1915,12 @@ proc slave_test_script {script} { interp eval tinterp [list set $var $value] } + # If output is being copied into a file, share the file-descriptor with + # the interpreter. + if {[info exists ::G(output_fd)]} { + interp share {} $::G(output_fd) tinterp + } + # The alias used to access the global test counters. tinterp alias set_test_counter set_test_counter @@ -1889,7 +1989,7 @@ proc slave_test_file {zFile} { # Add some info to the output. # - puts "Time: $tail $ms ms" + output2 "Time: $tail $ms ms" show_memstats } From 905da63a82e789d2f5decd74fff707488886287a Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 10 Jun 2015 18:53:09 +0000 Subject: [PATCH 24/28] "test" targets on all makefiles use --verbose=file --output=test-out.txt. Add the new "quicktest" target to all makefiles - designed to run in under three minutes. The --quick option on releasetest.tcl now uses quicktest. FossilOrigin-Name: 6ddef2ad35ceb5822fc14c65bc7c6a2662edb63c --- Makefile.in | 23 ++++++++++++++++------- Makefile.msc | 23 +++++++++++++++++------ main.mk | 28 +++++++++++++++++++++------- manifest | 27 ++++++++++++++------------- manifest.uuid | 2 +- test/analyzer1.test | 5 +++++ test/extraquick.test | 16 ++++++++++++++++ test/permutations.test | 17 ++++++++++++++--- test/releasetest.tcl | 7 +++++-- test/sqldiff1.test | 5 +++++ 10 files changed, 114 insertions(+), 39 deletions(-) create mode 100644 test/extraquick.test diff --git a/Makefile.in b/Makefile.in index ded1687d34..8952866dc6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -535,6 +535,10 @@ FUZZDATA = \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db +# Standard options to testfixture +# +TESTOPTS = --verbose=file --output=test-out.txt + # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # @@ -993,11 +997,11 @@ testfixture$(TEXE): $(TESTFIXTURE_SRC) # A very detailed test running most or all test cases fulltest: $(TESTPROGS) fuzztest - ./testfixture$(TEXE) $(TOP)/test/all.test + ./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS) # Really really long testing soaktest: $(TESTPROGS) - ./testfixture$(TEXE) $(TOP)/test/all.test -soak=1 + ./testfixture$(TEXE) $(TOP)/test/all.test -soak=1 $(TESTOPTS) # Do extra testing but not everything. fulltestonly: $(TESTPROGS) @@ -1010,24 +1014,29 @@ fuzztest: fuzzcheck$(TEXE) $(FUZZDATA) valgrindfuzz: fuzzcheck$(TEXT) $(FUZZDATA) valgrind ./fuzzcheck$(TEXE) --cell-size-check --quiet $(FUZZDATA) -# This is the common case. Run many tests but not those that take -# a really long time. +# Minimal testing that runs in less than 3 minutes +# +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) fuzztest - ./testfixture$(TEXE) $(TOP)/test/veryquick.test + ./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: $(TESTPROGS) valgrindfuzz - OMIT_MISUSE=1 valgrind -v ./testfixture$(TEXE) $(TOP)/test/permutations.test valgrind + 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: $(TESTPROGS) fuzzcheck$(TEXE) - ./testfixture$(TEXE) $(TOP)/test/main.test + ./testfixture$(TEXE) $(TOP)/test/main.test $(TESTOPTS) sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl echo "#define TCLSH 2" > $@ diff --git a/Makefile.msc b/Makefile.msc index c3272de0de..f29f66cce3 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -1203,6 +1203,9 @@ FUZZDATA = \ $(TOP)\test\fuzzdata2.db \ $(TOP)\test\fuzzdata3.db +# Standard options to testfixture +# +TESTOPTS = --verbose=file --output=test-out.txt # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. @@ -1677,28 +1680,36 @@ testfixture.exe: $(TESTFIXTURE_SRC) $(LIBRESOBJS) $(HDR) /link $(LTLINKOPTS) $(LTLIBPATHS) $(LIBRESOBJS) $(LTLIBS) $(TLIBS) extensiontest: testfixture.exe testloadext.dll - .\testfixture.exe $(TOP)\test\loadext.test + .\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS) fulltest: $(TESTPROGS) fuzztest - .\testfixture.exe $(TOP)\test\all.test + .\testfixture.exe $(TOP)\test\all.test $(TESTOPTS) soaktest: $(TESTPROGS) - .\testfixture.exe $(TOP)\test\all.test -soak=1 + .\testfixture.exe $(TOP)\test\all.test -soak=1 $(TESTOPTS) fulltestonly: $(TESTPROGS) fuzztest .\testfixture.exe $(TOP)\test\full.test queryplantest: testfixture.exe sqlite3.exe - .\testfixture.exe $(TOP)\test\permutations.test queryplanner + .\testfixture.exe $(TOP)\test\permutations.test queryplanner $(TESTOPTS) fuzztest: fuzzcheck.exe .\fuzzcheck.exe $(FUZZDATA) +# Minimal testing that runs in less than 3 minutes (on a fast machine) +# +quicktest: .\testfixture.exe + .\testfixture.exe $(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) fuzztest - .\testfixture.exe $(TOP)\test\veryquick.test + .\testfixture.exe $(TOP)\test\veryquick.test $(TESTOPTS) smoketest: $(TESTPROGS) - .\testfixture.exe $(TOP)\test\main.test + .\testfixture.exe $(TOP)\test\main.test $(TESTOPTS) sqlite3_analyzer.c: $(SQLITE3C) $(TOP)\src\tclsqlite.c $(TOP)\tool\spaceanal.tcl echo #define TCLSH 2 > $@ diff --git a/main.mk b/main.mk index b76972a9ed..3131386f3a 100644 --- a/main.mk +++ b/main.mk @@ -416,6 +416,10 @@ FUZZDATA = \ $(TOP)/test/fuzzdata2.db \ $(TOP)/test/fuzzdata3.db +# Standard options to testfixture +# +TESTOPTS = --verbose=file --output=test-out.txt + # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. # @@ -668,16 +672,16 @@ fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) fulltest: $(TESTPROGS) fuzztest - ./testfixture$(EXE) $(TOP)/test/all.test + ./testfixture$(EXE) $(TOP)/test/all.test $(TESTOPTS) soaktest: $(TESTPROGS) - ./testfixture$(EXE) $(TOP)/test/all.test -soak=1 + ./testfixture$(EXE) $(TOP)/test/all.test -soak=1 $(TESTOPTS) fulltestonly: $(TESTPROGS) fuzztest - ./testfixture$(EXE) $(TOP)/test/full.test + ./testfixture$(EXE) $(TOP)/test/full.test $(TESTOPTS) queryplantest: testfixture$(EXE) sqlite3$(EXE) - ./testfixture$(EXE) $(TOP)/test/permutations.test queryplanner + ./testfixture$(EXE) $(TOP)/test/permutations.test queryplanner $(TESTOPTS) fuzztest: fuzzcheck$(EXE) $(FUZZDATA) ./fuzzcheck$(EXE) $(FUZZDATA) @@ -685,21 +689,31 @@ fuzztest: fuzzcheck$(EXE) $(FUZZDATA) valgrindfuzz: fuzzcheck$(EXE) $(FUZZDATA) valgrind ./fuzzcheck$(EXE) --cell-size-check --quiet $(FUZZDATA) +# A very quick test using only testfixture and omitting all the slower +# tests. Designed to run in under 3 minutes on a workstation. +# +quicktest: ./testfixture$(EXE) + ./testfixture$(EXE) $(TOP)/test/extraquick.test $(TESTOPTS) + +# The default test case. Runs most of the faster standard TCL tests, +# and fuzz tests, and sqlite3_analyzer and sqldiff tests. +# test: $(TESTPROGS) fuzztest - ./testfixture$(EXE) $(TOP)/test/veryquick.test + ./testfixture$(EXE) $(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: $(TESTPROGS) valgrindfuzz - OMIT_MISUSE=1 valgrind -v ./testfixture$(EXE) $(TOP)/test/permutations.test valgrind + OMIT_MISUSE=1 valgrind -v \ + ./testfixture$(EXE) $(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: $(TESTPROGS) fuzzcheck$(EXE) - ./testfixture$(EXE) $(TOP)/test/main.test + ./testfixture$(EXE) $(TOP)/test/main.test $(TESTOPTS) # 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 diff --git a/manifest b/manifest index 5da0c00dd9..a38aca8867 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C Avoid\spassing\sconstraints\sthat\sare\sunusable\sdue\sto\sLEFT\sor\sCROSS\sjoins\sto\svirtual\stable\sxBestIndex()\smethods. -D 2015-06-10T14:27:40.648 +C "test"\stargets\son\sall\smakefiles\suse\s--verbose=file\s--output=test-out.txt.\nAdd\sthe\snew\s"quicktest"\starget\sto\sall\smakefiles\s-\sdesigned\sto\srun\sin\sunder\nthree\sminutes.\s\sThe\s--quick\soption\son\sreleasetest.tcl\snow\suses\squicktest. +D 2015-06-10T18:53:09.696 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f -F Makefile.in 580e006530fab67ccd34926ce2eda66d326af60f +F Makefile.in 1063c58075b7400d93326b0eb332b48a54f53025 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc 5438dc167466f51349ab0c4497aef547d0c9352c +F Makefile.msc 5a8418c81f736dfa953c809af1a48398017b3610 F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858 F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7 F VERSION ce0ae95abd7121c534f6917c1c8f2b70d9acd4db @@ -171,7 +171,7 @@ F ext/userauth/userauth.c 5fa3bdb492f481bbc1709fc83c91ebd13460c69e F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 033741a45df95c577814914b13d182a0b6c7dc89 +F main.mk 68f86c21505d6b66765a13c193f00a53dde6a212 F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea F mkopcodeh.awk d5e22023b5238985bb54a72d33e0ac71fe4f8a32 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -357,7 +357,7 @@ F test/analyzeC.test 555a6cc388b9818b6eda6df816f01ce0a75d3a93 F test/analyzeD.test 08f9d0bee4e118a66fff3a32d02dbe0ee0a2b594 F test/analyzeE.test 8684e8ac5722fb97c251887ad97e5d496a98af1d F test/analyzeF.test 7ccd7a04f7d3061bde1a8a4dacc4792edccf6bf2 -F test/analyzer1.test e3bccac3be49382050464952998a631bf51e3ce1 +F test/analyzer1.test 498e2ff4b62740c2751c3a2f8b744fe26689fae9 F test/async.test 1d0e056ba1bb9729283a0f22718d3a25e82c277b F test/async2.test c0a9bd20816d7d6a2ceca7b8c03d3d69c28ffb8b F test/async3.test d73a062002376d7edc1fe3edff493edbec1fc2f7 @@ -526,6 +526,7 @@ F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30 F test/expr.test 79c3e7502d9e571553b85f0ecc8ff2ac7d0e4931 F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9 +F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79 F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7 F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146 @@ -824,7 +825,7 @@ F test/pagesize.test 5769fc62d8c890a83a503f67d47508dfdc543305 F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff -F test/permutations.test 32e2b82e0dfbe5c6b6b38a5c1f4cac194298ad4e +F test/permutations.test 6b0f339a4d5f00041555a986dde8fbe8f54c25bc F test/pragma.test be7195f0aa72bdb8a512133e9640ac40f15b57a2 F test/pragma2.test f624a496a95ee878e81e59961eade66d5c00c028 F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c @@ -843,7 +844,7 @@ F test/randexpr1.test eda062a97e60f9c38ae8d806b03b0ddf23d796df F test/rdonly.test 64e2696c322e3538df0b1ed624e21f9a23ed9ff8 F test/regexp1.test 497ea812f264d12b6198d6e50a76be4a1973a9d8 F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 -F test/releasetest.tcl 3e906a8bbd047b8e1f035984fbdc96df4caaea47 +F test/releasetest.tcl 2aaffa548a8f8d10053b20bcf68a1b5a01081e51 F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea F test/rollback2.test fc14cf6d1a2b250d2735ef16124b971bce152f14 @@ -929,7 +930,7 @@ F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b F test/speedtest1.c 9f1b745c24886cced3f70ffc666300152a39013c F test/spellfix.test 24f676831acddd2f4056a598fd731a72c6311f49 -F test/sqldiff1.test e5ecfe95b3a2ff6380f0db6ea8bec246b675e122 +F test/sqldiff1.test 8f6bc7c6a5b3585d350d779c6078869ba402f8f5 F test/sqllimits1.test e05786eaed7950ff6a2d00031d001d8a26131e68 F test/stat.test 8de91498c99f5298b303f70f1d1f3b9557af91bf F test/statfault.test f525a7bf633e50afd027700e9a486090684b1ac1 @@ -1285,7 +1286,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P f7b2c70362f10ee0347c1d2318918ffefa53243d a34cd71c8aafaece04a2332a127e9b8e99c1403c -R 83db81ff2fb6c9dcf1dbb41c52657424 -U dan -Z 293899bbe176179f6b2abcd42b5d0831 +P 7b446771cadedafbe8924ad0658adc2597816dc7 +R e13907780a1cb22e147b44d8ea4a5351 +U drh +Z 0da5f15a574d2a2ef40a9dda668b3442 diff --git a/manifest.uuid b/manifest.uuid index ca59bdd454..3037113ee1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7b446771cadedafbe8924ad0658adc2597816dc7 \ No newline at end of file +6ddef2ad35ceb5822fc14c65bc7c6a2662edb63c \ No newline at end of file diff --git a/test/analyzer1.test b/test/analyzer1.test index 7da564ea2b..ac46704fba 100644 --- a/test/analyzer1.test +++ b/test/analyzer1.test @@ -24,6 +24,11 @@ if {$tcl_platform(platform)=="windows"} { } else { set PROG "./sqlite3_analyzer" } +if {![file exe $PROG]} { + puts "analyzer1 cannot run because $PROG is not available" + finish_test + return +} db close forcedelete test.db test.db-journal test.db-wal sqlite3 db test.db diff --git a/test/extraquick.test b/test/extraquick.test new file mode 100644 index 0000000000..f453564e7f --- /dev/null +++ b/test/extraquick.test @@ -0,0 +1,16 @@ +# +# 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 runs most of the tests run by veryquick.test except for those +# that take a long time. +# + +set testdir [file dirname $argv0] +source $testdir/permutations.test + +run_test_suite extraquick + +finish_test diff --git a/test/permutations.test b/test/permutations.test index 4b3ac6481b..01779ff50f 100644 --- a/test/permutations.test +++ b/test/permutations.test @@ -96,7 +96,7 @@ if {$::tcl_platform(platform)!="unix"} { set alltests [test_set $alltests -exclude { all.test async.test quick.test veryquick.test memleak.test permutations.test soak.test fts3.test - mallocAll.test rtree.test full.test + mallocAll.test rtree.test full.test extraquick.test }] set allquicktests [test_set $alltests -exclude { @@ -146,11 +146,22 @@ if {[info exists ::env(TEST_FAILURE)]} { lappend ::testsuitelist xxx test_suite "veryquick" -prefix "" -description { - "Very" quick test suite. Runs in less than 5 minutes on a workstation. + "Very" quick test suite. Runs in minutes on a workstation. This test suite is the same as the "quick" tests, except that some files that test malloc and IO errors are omitted. } -files [ - test_set $allquicktests -exclude *malloc* *ioerr* *fault* + test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* +] + +test_suite "extraquick" -prefix "" -description { + "Extra" quick test suite. Runs in a few minutes on a workstation. + This test suite is the same as the "veryquick" tests, except that + slower tests are omitted. +} -files [ + test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* \ + wal3.test fts4merge* sort2.test mmap1.test walcrash* \ + percentile.test where8m.test walcksum.test savepoint3.test \ + fuzzer1.test fuzzer3.test fts3expr3.test ] test_suite "mmap" -prefix "mm-" -description { diff --git a/test/releasetest.tcl b/test/releasetest.tcl index a120ddf336..6e475c9d29 100644 --- a/test/releasetest.tcl +++ b/test/releasetest.tcl @@ -547,7 +547,10 @@ proc process_options {argv} { puts " --srcdir $::SRCDIR" puts " --platform [list $platform]" puts " --config [list $config]" - if {$::QUICK} {puts " --quick"} + if {$::QUICK} { + if {$::QUICK==1} {puts " --quick"} + if {$::QUICK==2} {puts " --veryquick"} + } if {$::MSVC} {puts " --msvc"} if {$::BUILDONLY} {puts " --buildonly"} if {$::DRYRUN} {puts " --dryrun"} @@ -645,7 +648,7 @@ proc main {argv} { } if {$target ne "checksymbols"} { switch -- $::QUICK { - 1 {set target test} + 1 {set target quicktest} 2 {set target smoketest} } if {$::BUILDONLY} { diff --git a/test/sqldiff1.test b/test/sqldiff1.test index 723b7a5e13..3201fb3654 100644 --- a/test/sqldiff1.test +++ b/test/sqldiff1.test @@ -19,6 +19,11 @@ if {$tcl_platform(platform)=="windows"} { } else { set PROG "./sqldiff" } +if {![file exe $PROG]} { + puts "sqldiff cannot run because $PROG is not available" + finish_test + return +} db close forcedelete test.db test2.db sqlite3 db test.db From 033eb6c8d3f4b9c3a0f9343bcb349fbad6ac0b66 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Wed, 10 Jun 2015 22:03:40 +0000 Subject: [PATCH 25/28] Fix minor typo in the quicktest MSVC makefile target. FossilOrigin-Name: 75b65f9d49daaf48e97042cb82ea554e2ec74eec --- Makefile.msc | 2 +- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile.msc b/Makefile.msc index f29f66cce3..70c16b11c3 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -1699,7 +1699,7 @@ fuzztest: fuzzcheck.exe # Minimal testing that runs in less than 3 minutes (on a fast machine) # -quicktest: .\testfixture.exe +quicktest: testfixture.exe .\testfixture.exe $(TOP)\test\extraquick.test $(TESTOPTS) # This is the common case. Run many tests that do not take too long, diff --git a/manifest b/manifest index a38aca8867..7b46a7527c 100644 --- a/manifest +++ b/manifest @@ -1,9 +1,9 @@ -C "test"\stargets\son\sall\smakefiles\suse\s--verbose=file\s--output=test-out.txt.\nAdd\sthe\snew\s"quicktest"\starget\sto\sall\smakefiles\s-\sdesigned\sto\srun\sin\sunder\nthree\sminutes.\s\sThe\s--quick\soption\son\sreleasetest.tcl\snow\suses\squicktest. -D 2015-06-10T18:53:09.696 +C Fix\sminor\stypo\sin\sthe\squicktest\sMSVC\smakefile\starget. +D 2015-06-10T22:03:40.913 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 1063c58075b7400d93326b0eb332b48a54f53025 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 -F Makefile.msc 5a8418c81f736dfa953c809af1a48398017b3610 +F Makefile.msc b7db9ccbbad1c495b98e5326a06cac03aa206127 F Makefile.vxworks e1b65dea203f054e71653415bd8f96dcaed47858 F README.md 8ecc12493ff9f820cdea6520a9016001cb2e59b7 F VERSION ce0ae95abd7121c534f6917c1c8f2b70d9acd4db @@ -1286,7 +1286,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 7b446771cadedafbe8924ad0658adc2597816dc7 -R e13907780a1cb22e147b44d8ea4a5351 -U drh -Z 0da5f15a574d2a2ef40a9dda668b3442 +P 6ddef2ad35ceb5822fc14c65bc7c6a2662edb63c +R c63a194dd469f312ca0f35c47faf1707 +U mistachkin +Z c108f8ac4d75e13d11936c87d29e2e70 diff --git a/manifest.uuid b/manifest.uuid index 3037113ee1..d1f247c6bc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6ddef2ad35ceb5822fc14c65bc7c6a2662edb63c \ No newline at end of file +75b65f9d49daaf48e97042cb82ea554e2ec74eec \ No newline at end of file From 7b96f2fa7ecfdf2dd3f361e11a19e866ed20dd9a Mon Sep 17 00:00:00 2001 From: mistachkin Date: Wed, 10 Jun 2015 22:51:02 +0000 Subject: [PATCH 26/28] Remove possibly stray output from various tests. FossilOrigin-Name: f38e0be56fc086a3ce08134ade83ab61c9fca106 --- manifest | 29 ++++++++++++++++------------- manifest.uuid | 2 +- test/e_walauto.test | 1 - test/filectrl.test | 1 - test/fts3d.test | 2 +- test/fts4incr.test | 4 +++- test/index5.test | 6 ++++-- test/select8.test | 1 - test/shared4.test | 1 - test/tester.tcl | 18 +++++++++--------- 10 files changed, 34 insertions(+), 31 deletions(-) diff --git a/manifest b/manifest index 7b46a7527c..76f440746a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sminor\stypo\sin\sthe\squicktest\sMSVC\smakefile\starget. -D 2015-06-10T22:03:40.913 +C Remove\spossibly\sstray\soutput\sfrom\svarious\stests. +D 2015-06-10T22:51:02.529 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 1063c58075b7400d93326b0eb332b48a54f53025 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -510,7 +510,7 @@ F test/e_update.test 312cb8f5ccfe41515a6bb092f8ea562a9bd54d52 F test/e_uri.test 5ae33760fb2039c61aa2d90886f1664664173585 F test/e_vacuum.test 5bfbdc21b65c0abf24398d0ba31dc88d93ca77a9 F test/e_wal.test ae9a593207a77d711443ee69ffe081fda9243625 -F test/e_walauto.test 6544af03423abc61b53cfb976839385ddc2a0a70 +F test/e_walauto.test 280714ddf14e1a47dcbc59d515cd0b026dfd5567 F test/e_walckpt.test 65e29b6631e51f210f83e4ff11571e647ba93608 F test/e_walhook.test da3ea8b3483d1af72190337bda50155a91a4b664 F test/enc.test e54531cd6bf941ee6760be041dff19a104c7acea @@ -528,7 +528,7 @@ F test/expr.test 79c3e7502d9e571553b85f0ecc8ff2ac7d0e4931 F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9 F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79 F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7 -F test/filectrl.test 14fa712e42c4cb791e09dfd58a6a03efb47ef13a +F test/filectrl.test 7c13f96457435238da99aff7343ad6a3a4885787 F test/filefmt.test cb34663f126cbc2d358af552dcaf5c72769b0146 F test/fkey1.test de5b287f6a480b36bd51e8debcf48168e26e4ed2 F test/fkey2.test f3d27ecba480a348c328965d154214719bb158a9 @@ -603,7 +603,7 @@ F test/fts3conf.test ee8500c86dd58ec075e8831a1e216a79989436de F test/fts3corrupt.test 2710b77983cc7789295ddbffea52c1d3b7506dbb F test/fts3corrupt2.test 6d96efae2f8a6af3eeaf283aba437e6d0e5447ba F test/fts3cov.test e0fb00d8b715ddae4a94c305992dfc3ef70353d7 -F test/fts3d.test 95c17d1b67b33a5eac0bf5a0d11116a0c0ac7a3a +F test/fts3d.test d3e9c8fb75135ada06bf3bab4f9666224965d708 F test/fts3defer.test 0be4440b73a2e651fc1e472066686d6ada4b9963 F test/fts3defer2.test c540f5f5c2840f70c68fd9b597df817ec7170468 F test/fts3defer3.test dd53fc13223c6d8264a98244e9b19abd35ed71cd @@ -637,7 +637,7 @@ F test/fts4content.test abb0c77bc3da3df64fec72e00844d2257a90025d F test/fts4docid.test e33c383cfbdff0284685604d256f347a18fdbf01 F test/fts4growth.test df10fde9f47cf5c71861e63fd8efcd573c4f7e53 F test/fts4growth2.test 2f063be1902a73cd087355837c52fed42ac11a5d -F test/fts4incr.test 361960ed3550e781f3f313e17e2182ef9cefc0e9 +F test/fts4incr.test 4e353a0bd886ea984e56fce9e77724fc923b8d0d F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7 F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891 @@ -688,7 +688,7 @@ F test/index.test 4d990005a67a36984e4f1a5f1bdccea8d08da4ee F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index3.test b6ec456cf3b81d9a32123fe7e449bde434db338b F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 -F test/index5.test 25b0b451aceed4ac5f7d49f856f6de7257470b3e +F test/index5.test 8621491915800ec274609e42e02a97d67e9b13e7 F test/index6.test 3ae54e53c53f2adcacda269237d8e52bdb05a481 F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353 @@ -876,7 +876,7 @@ F test/select4.test 6d5bc6d178a367e8b48fa1c1d3ea12cae9c2d650 F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535 F test/select6.test 39eac4a5c03650b2b473c532882273283ee8b7a0 F test/select7.test 7fd2ef598cfabb6b9ff6ac13973b91d0527df49d -F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d +F test/select8.test 8c8f5ae43894c891efc5755ed905467d1d67ad5d F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95 F test/selectA.test e452bdb975f488ea46d091382a9185b5853ed2c7 F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25 @@ -889,7 +889,7 @@ F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118 F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746 F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879 F test/shared3.test fcd65cb11d189eff5f5c85cc4fad246fb0933108 -F test/shared4.test 72d90821e8d2fc918a08f16d32880868d8ee8e9d +F test/shared4.test c75f476804e76e26bf6fa0e7b421fb0ca7d07558 F test/shared6.test 866bb4982c45ce216c61ded5e8fde4e7e2f3ffa9 F test/shared7.test a81e99f83e6c51b02ac99c96fb3a2a7b5978c956 F test/shared8.test 00a07bf5e1337ecf72e94542bdefdc330d7a2538 @@ -950,7 +950,7 @@ F test/tclsqlite.test 7fb866443c7deceed22b63948ccd6f76b52ad054 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 -F test/tester.tcl ca396a3f867c1bd3603400ca8f17bbffd87985b7 +F test/tester.tcl d23d57063764471b6fb51276b851ac51d364db06 F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1286,7 +1286,10 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 6ddef2ad35ceb5822fc14c65bc7c6a2662edb63c -R c63a194dd469f312ca0f35c47faf1707 +P 75b65f9d49daaf48e97042cb82ea554e2ec74eec +R 7ce3aec9083e0231108814bdab12a834 +T *branch * testerOutput +T *sym-testerOutput * +T -sym-trunk * U mistachkin -Z c108f8ac4d75e13d11936c87d29e2e70 +Z db6ff78743d076544ff22113ea65f70d diff --git a/manifest.uuid b/manifest.uuid index d1f247c6bc..24021b6cbc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -75b65f9d49daaf48e97042cb82ea554e2ec74eec \ No newline at end of file +f38e0be56fc086a3ce08134ade83ab61c9fca106 \ No newline at end of file diff --git a/test/e_walauto.test b/test/e_walauto.test index a1f4eb7079..093b13f940 100644 --- a/test/e_walauto.test +++ b/test/e_walauto.test @@ -171,7 +171,6 @@ foreach {tn code} { # set ::busy_callback_count 0 proc busy_callback {args} { - puts Hello incr ::busy_callback_count return 0 } diff --git a/test/filectrl.test b/test/filectrl.test index 1d878bf968..28fecee92f 100644 --- a/test/filectrl.test +++ b/test/filectrl.test @@ -39,7 +39,6 @@ do_test filectrl-1.5 { do_test filectrl-1.6 { sqlite3 db test.db set fn [file_control_tempfilename db] - puts -nonewline \[$fn\] set fn } {/etilqs_/} db close diff --git a/test/fts3d.test b/test/fts3d.test index 5c04ead0a0..83af4d2a37 100644 --- a/test/fts3d.test +++ b/test/fts3d.test @@ -213,7 +213,7 @@ do_test fts3d-4.matches { {0 1 0 4 0 2 5 3 0 3 9 1 0 5 11 4} \ {0 0 0 4 0 4 5 2 0 3 8 1 0 5 10 4}] -puts [db eval {SELECT c FROM t1 } ] +db eval {SELECT c FROM t1 } check_terms_all fts3d-4.1 {a four is test that this was} check_doclist_all fts3d-4.1.1 a {[1 0[2]] [2 0[2]] [3 0[2]]} check_doclist_all fts3d-4.1.2 four {} diff --git a/test/fts4incr.test b/test/fts4incr.test index 17212efce7..92104888b4 100644 --- a/test/fts4incr.test +++ b/test/fts4incr.test @@ -47,7 +47,9 @@ foreach {tn q res} { do_execsql_test 2.$tn.$s $q $res set t($s) [lindex [time [list execsql $q] 100] 0] } - puts "with optimization: $t(0) without: $t(1)" + if {0} { + puts "with optimization: $t(0) without: $t(1)" + } } do_test 2.1 { diff --git a/test/index5.test b/test/index5.test index e369d75717..4c0aa0431e 100644 --- a/test/index5.test +++ b/test/index5.test @@ -67,8 +67,10 @@ do_test 1.3 { } set iPrev $iNext } - puts -nonewline \ - " (forward=$nForward, back=$nBackward, noncontiguous=$nNoncont)" + if {0} { + puts -nonewline \ + " (forward=$nForward, back=$nBackward, noncontiguous=$nNoncont)" + } expr {$nForward > 2*($nBackward + $nNoncont)} } {1} diff --git a/test/select8.test b/test/select8.test index 98626641bf..39b2739499 100644 --- a/test/select8.test +++ b/test/select8.test @@ -32,7 +32,6 @@ set result [execsql { FROM songs GROUP BY LOWER(artist) }] -puts result=$result do_test select8-1.1 { execsql { SELECT DISTINCT artist,sum(timesplayed) AS total diff --git a/test/shared4.test b/test/shared4.test index 83925b06e4..88959db42d 100644 --- a/test/shared4.test +++ b/test/shared4.test @@ -16,7 +16,6 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl db close -puts hello # This script is only valid if we are running shared-cache mode in a # threadsafe-capable database engine. diff --git a/test/tester.tcl b/test/tester.tcl index a83054fbe7..8fd53c8e42 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -1168,20 +1168,20 @@ proc catchsql {sql {db db}} { # Do an VDBE code dump on the SQL given # proc explain {sql {db db}} { - puts "" - puts "addr opcode p1 p2 p3 p4 p5 #" - puts "---- ------------ ------ ------ ------ --------------- -- -" + output1 "" + output1 "addr opcode p1 p2 p3 p4 p5 #" + output1 "---- ------------ ------ ------ ------ --------------- -- -" $db eval "explain $sql" {} { - puts [format {%-4d %-12.12s %-6d %-6d %-6d % -17s %s %s} \ + output1 [format {%-4d %-12.12s %-6d %-6d %-6d % -17s %s %s} \ $addr $opcode $p1 $p2 $p3 $p4 $p5 $comment ] } } proc explain_i {sql {db db}} { - puts "" - puts "addr opcode p1 p2 p3 p4 p5 #" - puts "---- ------------ ------ ------ ------ ---------------- -- -" + output1 "" + output1 "addr opcode p1 p2 p3 p4 p5 #" + output1 "---- ------------ ------ ------ ------ ---------------- -- -" # Set up colors for the different opcodes. Scheme is as follows: @@ -1254,11 +1254,11 @@ proc explain_i {sql {db db}} { set col "" catch { set col $color($opcode) } - puts [format {%-4d %s%s%-12.12s%s %-6d %-6d %-6d % -17s %s %s} \ + output1 [format {%-4d %s%s%-12.12s%s %-6d %-6d %-6d % -17s %s %s} \ $addr $I $col $opcode $D $p1 $p2 $p3 $p4 $p5 $comment ] } - puts "---- ------------ ------ ------ ------ ---------------- -- -" + output1 "---- ------------ ------ ------ ------ ---------------- -- -" } # Show the VDBE program for an SQL statement but omit the Trace From eeb31ff59bf8a3164cfc2aa43cd2fd0ed8512400 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Wed, 10 Jun 2015 23:02:38 +0000 Subject: [PATCH 27/28] More test output refinements. FossilOrigin-Name: e64a5681793238fa04fe3636f48d34b2dd36cdfa --- manifest | 19 ++++++++----------- manifest.uuid | 2 +- test/progress.test | 1 - test/tester.tcl | 20 ++++++++++---------- test/vtab1.test | 3 --- 5 files changed, 19 insertions(+), 26 deletions(-) diff --git a/manifest b/manifest index 76f440746a..88335ba49a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\spossibly\sstray\soutput\sfrom\svarious\stests. -D 2015-06-10T22:51:02.529 +C More\stest\soutput\srefinements. +D 2015-06-10T23:02:38.561 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 1063c58075b7400d93326b0eb332b48a54f53025 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -831,7 +831,7 @@ F test/pragma2.test f624a496a95ee878e81e59961eade66d5c00c028 F test/pragma3.test 6f849ccffeee7e496d2f2b5e74152306c0b8757c F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc F test/printf2.test 0b61566dd1c0f0b802f59dffa228c5dc5aa6b054 -F test/progress.test a282973d1d17f08071bc58a77d6b80f2a81c354d +F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca F test/quick.test 1681febc928d686362d50057c642f77a02c62e57 @@ -950,7 +950,7 @@ F test/tclsqlite.test 7fb866443c7deceed22b63948ccd6f76b52ad054 F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30 F test/temptrigger.test 8ec228b0db5d7ebc4ee9b458fc28cb9e7873f5e1 -F test/tester.tcl d23d57063764471b6fb51276b851ac51d364db06 +F test/tester.tcl b3a41e20f98a029a76e930b33d0711c5854267bb F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5 F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58 F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7 @@ -1148,7 +1148,7 @@ F test/vacuum4.test d3f8ecff345f166911568f397d2432c16d2867d9 F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 F test/view.test f311691d696a5cc27e3c1b875cec1b0866b4ccd9 -F test/vtab1.test dbe0e9e121102d0ba365f20d126a72676aa2343f +F test/vtab1.test 6210e076997f176bedc300a87ad6404651b601dd F test/vtab2.test f8cd1bb9aba7143eba97812d9617880a36d247ad F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e F test/vtab4.test 942f8b8280b3ea8a41dae20e7822d065ca1cb275 @@ -1286,10 +1286,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 75b65f9d49daaf48e97042cb82ea554e2ec74eec -R 7ce3aec9083e0231108814bdab12a834 -T *branch * testerOutput -T *sym-testerOutput * -T -sym-trunk * +P f38e0be56fc086a3ce08134ade83ab61c9fca106 +R 27c776937a2faf6a3c6ca0150fe1d26e U mistachkin -Z db6ff78743d076544ff22113ea65f70d +Z 4bdc8fbc12892afab86b92929a73ad3a diff --git a/manifest.uuid b/manifest.uuid index 24021b6cbc..ec8126b5c8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f38e0be56fc086a3ce08134ade83ab61c9fca106 \ No newline at end of file +e64a5681793238fa04fe3636f48d34b2dd36cdfa \ No newline at end of file diff --git a/test/progress.test b/test/progress.test index 993426aa2b..f6d7229243 100644 --- a/test/progress.test +++ b/test/progress.test @@ -164,7 +164,6 @@ do_test progress-1.7 { } set ::res [list] - explain {SELECT a, b, c FROM abc} db eval {SELECT a, b, c FROM abc} { lappend ::res $a $b $c db progress 5 "expr 1" diff --git a/test/tester.tcl b/test/tester.tcl index 8fd53c8e42..8022d6a538 100644 --- a/test/tester.tcl +++ b/test/tester.tcl @@ -1168,20 +1168,20 @@ proc catchsql {sql {db db}} { # Do an VDBE code dump on the SQL given # proc explain {sql {db db}} { - output1 "" - output1 "addr opcode p1 p2 p3 p4 p5 #" - output1 "---- ------------ ------ ------ ------ --------------- -- -" + output2 "" + output2 "addr opcode p1 p2 p3 p4 p5 #" + output2 "---- ------------ ------ ------ ------ --------------- -- -" $db eval "explain $sql" {} { - output1 [format {%-4d %-12.12s %-6d %-6d %-6d % -17s %s %s} \ + output2 [format {%-4d %-12.12s %-6d %-6d %-6d % -17s %s %s} \ $addr $opcode $p1 $p2 $p3 $p4 $p5 $comment ] } } proc explain_i {sql {db db}} { - output1 "" - output1 "addr opcode p1 p2 p3 p4 p5 #" - output1 "---- ------------ ------ ------ ------ ---------------- -- -" + output2 "" + output2 "addr opcode p1 p2 p3 p4 p5 #" + output2 "---- ------------ ------ ------ ------ ---------------- -- -" # Set up colors for the different opcodes. Scheme is as follows: @@ -1247,18 +1247,18 @@ proc explain_i {sql {db db}} { $db eval "explain $sql" {} { if {[info exists linebreak($addr)]} { - puts "" + output2 "" } set I [string repeat " " $x($addr)] set col "" catch { set col $color($opcode) } - output1 [format {%-4d %s%s%-12.12s%s %-6d %-6d %-6d % -17s %s %s} \ + output2 [format {%-4d %s%s%-12.12s%s %-6d %-6d %-6d % -17s %s %s} \ $addr $I $col $opcode $D $p1 $p2 $p3 $p4 $p5 $comment ] } - output1 "---- ------------ ------ ------ ------ ---------------- -- -" + output2 "---- ------------ ------ ------ ------ ---------------- -- -" } # Show the VDBE program for an SQL statement but omit the Trace diff --git a/test/vtab1.test b/test/vtab1.test index cd21153f06..84de4cffa5 100644 --- a/test/vtab1.test +++ b/test/vtab1.test @@ -56,9 +56,6 @@ ifcapable !vtab||!schema_pragmas { # We cannot create a virtual table if the module has not been registered. # do_test vtab1-1.1.1 { - explain { - CREATE VIRTUAL TABLE t1 USING echo; - } catchsql { CREATE VIRTUAL TABLE t1 USING echo; } From 72bc8208f01a8e476996db7c6de09ad61ed62d6f Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 11 Jun 2015 13:58:35 +0000 Subject: [PATCH 28/28] When generating code for partial indexes, be sure not to modify the index condition expression in the schema. FossilOrigin-Name: e63d01c69c3e50f49ee3022a519c4f3e91f00520 --- manifest | 22 +++++++++++----------- manifest.uuid | 2 +- src/delete.c | 4 ++-- src/expr.c | 15 +++++++++++++++ src/insert.c | 4 ++-- src/sqliteInt.h | 1 + test/index6.test | 19 +++++++++++++++++++ 7 files changed, 51 insertions(+), 16 deletions(-) diff --git a/manifest b/manifest index 7b46a7527c..913fd64a60 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sminor\stypo\sin\sthe\squicktest\sMSVC\smakefile\starget. -D 2015-06-10T22:03:40.913 +C When\sgenerating\scode\sfor\spartial\sindexes,\sbe\ssure\snot\sto\smodify\sthe\nindex\scondition\sexpression\sin\sthe\sschema. +D 2015-06-11T13:58:35.248 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 1063c58075b7400d93326b0eb332b48a54f53025 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -201,8 +201,8 @@ F src/complete.c a5cf5b4b56390cfb7b8636e8f7ddef90258dd575 F src/ctime.c 5a0b735dc95604766f5dac73973658eef782ee8b F src/date.c e4d50b3283696836ec1036b695ead9a19e37a5ac F src/dbstat.c f402e77e25089c6003d0c60b3233b9b3947d599a -F src/delete.c 37964e6c1d73ff49cbea9ff690c9605fb15f600e -F src/expr.c 0550baeca8dd7472e298d9e881e5e3484f7666f8 +F src/delete.c 8857a6f27560718f65d43bdbec86c967ae1f8dfa +F src/expr.c 710c764c1974b15a0e56b004ff9f5e6ceab3a854 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c c9b63a217d86582c22121699a47f22f524608869 F src/func.c 5b8b8e77a0fb644eaf8947d413804622e32692b6 @@ -210,7 +210,7 @@ F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c d6e1623a97ce33e9af2f1a0c1f0085a2f63327ef +F src/insert.c b5f8b35a1b7924020e48cade5b2b5017bca7906b F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 @@ -255,7 +255,7 @@ F src/shell.c 07dda7cd692911d2f22269953418d049f2e2c0ee F src/sqlite.h.in d165beeceb6b40af60f352a4d4e37e02d9af7df0 F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 2ebeb634e751a61a6f0eebfa0f4669f46a42f6cd -F src/sqliteInt.h 4c6731ce49b90582ea7d77c67b8792a4df8da237 +F src/sqliteInt.h 8f095bfe43ba68c32bac8d5349131ffacc660967 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e @@ -689,7 +689,7 @@ F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index3.test b6ec456cf3b81d9a32123fe7e449bde434db338b F test/index4.test ab92e736d5946840236cd61ac3191f91a7856bf6 F test/index5.test 25b0b451aceed4ac5f7d49f856f6de7257470b3e -F test/index6.test 3ae54e53c53f2adcacda269237d8e52bdb05a481 +F test/index6.test fbf45ceb39eb8a01b837d22623b93b208e6509ef F test/index7.test 9c6765a74fc3fcde7aebc5b3bd40d98df14a527c F test/indexedby.test 5f527a78bae74c61b8046ae3037f9dfb0bf0c353 F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d @@ -1286,7 +1286,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 6ddef2ad35ceb5822fc14c65bc7c6a2662edb63c -R c63a194dd469f312ca0f35c47faf1707 -U mistachkin -Z c108f8ac4d75e13d11936c87d29e2e70 +P 75b65f9d49daaf48e97042cb82ea554e2ec74eec +R d74aba000e40e2b28c1e25cf1d9fcc49 +U drh +Z 8cefff923a130826c381270a2faa270d diff --git a/manifest.uuid b/manifest.uuid index d1f247c6bc..4dd90d9982 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -75b65f9d49daaf48e97042cb82ea554e2ec74eec \ No newline at end of file +e63d01c69c3e50f49ee3022a519c4f3e91f00520 \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index ef6aace1c8..369cdaf6fe 100644 --- a/src/delete.c +++ b/src/delete.c @@ -798,8 +798,8 @@ int sqlite3GenerateIndexKey( *piPartIdxLabel = sqlite3VdbeMakeLabel(v); pParse->iPartIdxTab = iDataCur; sqlite3ExprCachePush(pParse); - sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, - SQLITE_JUMPIFNULL); + sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, + SQLITE_JUMPIFNULL); }else{ *piPartIdxLabel = 0; } diff --git a/src/expr.c b/src/expr.c index 89eee29ecd..06993e7371 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3702,6 +3702,21 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ sqlite3ReleaseTempReg(pParse, regFree2); } +/* +** Like sqlite3ExprIfFalse() except that a copy is made of pExpr before +** code generation, and that copy is deleted after code generation. This +** ensures that the original pExpr is unchanged. +*/ +void sqlite3ExprIfFalseDup(Parse *pParse, Expr *pExpr, int dest,int jumpIfNull){ + sqlite3 *db = pParse->db; + Expr *pCopy = sqlite3ExprDup(db, pExpr, 0); + if( db->mallocFailed==0 ){ + sqlite3ExprIfFalse(pParse, pCopy, dest, jumpIfNull); + } + sqlite3ExprDelete(db, pCopy); +} + + /* ** Do a deep comparison of two expression trees. Return 0 if the two ** expressions are completely identical. Return 1 if they differ only diff --git a/src/insert.c b/src/insert.c index 7e8741a9a2..16bf07cdfd 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1381,8 +1381,8 @@ void sqlite3GenerateConstraintChecks( if( pIdx->pPartIdxWhere ){ sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]); pParse->ckBase = regNewData+1; - sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk, - SQLITE_JUMPIFNULL); + sqlite3ExprIfFalseDup(pParse, pIdx->pPartIdxWhere, addrUniqueOk, + SQLITE_JUMPIFNULL); pParse->ckBase = 0; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 43e4b0be9b..2378376c28 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3326,6 +3326,7 @@ int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8); #define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */ void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); +void sqlite3ExprIfFalseDup(Parse*, Expr*, int, int); Table *sqlite3FindTable(sqlite3*,const char*, const char*); Table *sqlite3LocateTable(Parse*,int isView,const char*, const char*); Table *sqlite3LocateTableItem(Parse*,int isView,struct SrcList_item *); diff --git a/test/index6.test b/test/index6.test index 69fae49feb..e15820290e 100644 --- a/test/index6.test +++ b/test/index6.test @@ -327,4 +327,23 @@ do_execsql_test index6-8.2 { 3 three value 3 } +# 2015-06-11. Assertion fault found by AFL +# +do_execsql_test index6-9.1 { + CREATE TABLE t9(a int, b int, c int); + CREATE INDEX t9ca ON t9(c,a) WHERE a in (10,12,20); + INSERT INTO t9 VALUES(1,1,9),(10,2,35),(11,15,82),(20,19,5),(NULL,7,3); + UPDATE t9 SET b=c WHERE a in (10,12,20); + SELECT a,b,c,'|' FROM t9 ORDER BY a; +} {{} 7 3 | 1 1 9 | 10 35 35 | 11 15 82 | 20 5 5 |} +do_execsql_test index6-9.2 { + DROP TABLE t9; + CREATE TABLE t9(a int, b int, c int, PRIMARY KEY(a)) WITHOUT ROWID; + CREATE INDEX t9ca ON t9(c,a) WHERE a in (10,12,20); + INSERT INTO t9 VALUES(1,1,9),(10,2,35),(11,15,82),(20,19,5); + UPDATE t9 SET b=c WHERE a in (10,12,20); + SELECT a,b,c,'|' FROM t9 ORDER BY a; +} {1 1 9 | 10 35 35 | 11 15 82 | 20 5 5 |} + + finish_test