]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Try to take into account the cost of inner loops when selecting which table
authordrh <drh@noemail.net>
Fri, 9 Nov 2012 17:59:26 +0000 (17:59 +0000)
committerdrh <drh@noemail.net>
Fri, 9 Nov 2012 17:59:26 +0000 (17:59 +0000)
of a join to use for the outer loop.

FossilOrigin-Name: 942556342a332b04a11169bb04f387d741ef9488

manifest
manifest.uuid
src/sqliteInt.h
src/where.c
test/orderby1.test
test/whereE.test [new file with mode: 0644]
test/whereF.test [new file with mode: 0644]

index 46d197a9d4e6f42f91377b7e116744e20aeda036..65706de517d155dc97a285c0b7c90cd7d49f9db7 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Adjust\sthe\sSQLITE_DBSTATUS_STMT_USED\scalculation\sto\stake\sthe\smodified\susage\sof\ssqlite3VdbeClearObject()\sinto\saccount.
-D 2012-11-06T20:39:11.759
+C Try\sto\stake\sinto\saccount\sthe\scost\sof\sinner\sloops\swhen\sselecting\swhich\stable\nof\sa\sjoin\sto\suse\sfor\sthe\souter\sloop.
+D 2012-11-09T17:59:26.161
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 82c41c0ed4cc94dd3cc7d498575b84c57c2c2384
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -179,7 +179,7 @@ F src/shell.c 24cd0aa74aff73ea08594629faead564c4c2a286
 F src/sqlite.h.in c7be05ad191d2634292fcc77bdb2bcfa4526eb98
 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
-F src/sqliteInt.h f29ed6fbbf80a6d9ac8aae9998ecae2b8d72e0ae
+F src/sqliteInt.h 79c00e24d84541c3117ef34ce09c5749dcdcba25
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -249,7 +249,7 @@ F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
 F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2
 F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6
 F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
-F src/where.c 6a753aa008de6494e64dd265a27afbb0ad80ccf5
+F src/where.c b97f14d4ce618ceb18138238b1bd028cf02014b4
 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2
 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6
@@ -636,7 +636,7 @@ F test/notify3.test a86259abbfb923aa27d30f0fc038c88e5251488a
 F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
 F test/null.test a8b09b8ed87852742343b33441a9240022108993
 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
-F test/orderby1.test ef4f7c40df81b9a4303a718433d34052f07db47d
+F test/orderby1.test f33968647da5c546528fe4d2bf86c6a6a2e5a7ae
 F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04
 F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
 F test/pager1.test 07116f72a61960b882952e7472cc2846d161d6e2
@@ -974,6 +974,8 @@ F test/whereA.test 24c234263c8fe358f079d5e57d884fb569d2da0a
 F test/whereB.test 0def95db3bdec220a731c7e4bec5930327c1d8c5
 F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5
 F test/whereD.test 3f3ee93825c94804f1fc91eef2de0d365981759a
+F test/whereE.test 7bd34945797efef15819368479bacc34215e4e1d
+F test/whereF.test a0e296643cabe5278379bc1a0aa158cf3c54a1c9
 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
 F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9
 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
@@ -1022,7 +1024,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
-P 6b4979e86c05f2da2c5fff67ea7feec5fa56756a
-R 275b30fd4dabbb76a3c510773e928640
-U mistachkin
-Z 07851b8d86e7907c3dc0dd17f564d79e
+P 82eb7eadb8c76b3af8c811d791f87a634c35935f
+R 6e69028f10fbf48578845dd76c89b910
+T *branch * inner-loop-cost
+T *sym-inner-loop-cost *
+T -sym-trunk *
+U drh
+Z 386f6fc4840a28b57311013bb9458533
index 8c413f9a8d2500c6ad97ee16b82264b92947fe5c..85eae6eacda2f63871dbb178e118083f6dd90fd5 100644 (file)
@@ -1 +1 @@
-82eb7eadb8c76b3af8c811d791f87a634c35935f
\ No newline at end of file
+942556342a332b04a11169bb04f387d741ef9488
\ No newline at end of file
index e44ce7b7e8bd4b28697c9bbad851269bc55df108..eb779253c98344594f1a1ac33d45fedcd18f4a6c 100644 (file)
@@ -1967,6 +1967,7 @@ struct WhereLevel {
     } in;                 /* Used when plan.wsFlags&WHERE_IN_ABLE */
     Index *pCovidx;       /* Possible covering index for WHERE_MULTI_OR */
   } u;
+  double rOptCost;      /* "Optimal" cost for this level */
 
   /* The following field is really not part of the current level.  But
   ** we need a place to cache virtual table index information for each
index 38f6f1436fc444cf1fa1202a765c5cffbc97a5af..5fa40994fe524cd4488de04c49e05440dc24a422 100644 (file)
@@ -4744,6 +4744,16 @@ static void whereInfoFree(sqlite3 *db, WhereInfo *pWInfo){
   }
 }
 
+/*
+** Return TRUE if the wsFlags indicate that a full table scan (or a
+** full scan of a covering index) is indicated.
+*/
+static int isFullscan(unsigned wsFlags){
+  if( wsFlags & WHERE_COVER_SCAN ) return 1;
+  if( (wsFlags & WHERE_NOT_FULLSCAN)==0 ) return 1;
+  return 0;
+}
+
 
 /*
 ** Generate the beginning of the loop used for WHERE clause processing.
@@ -5102,6 +5112,19 @@ WhereInfo *sqlite3WhereBegin(
         if( isOptimal && (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)==0 ){
           notIndexed |= m;
         }
+        if( isOptimal ){
+          pWInfo->a[j].rOptCost = sWBI.cost.rCost;
+        }else if( iFrom<nTabList-1 ){
+          /* If two or more tables have nearly the same outer loop cost,
+          ** very different inner loop (optimal) cost, we want to choose
+          ** for the outer loop that table which benefits the least from
+          ** being in the inner loop.  The following code scales the 
+          ** outer loop cost estimate to accomplish that. */
+          WHERETRACE(("   scaling cost from %.1f to %.1f\n",
+                      sWBI.cost.rCost,
+                      sWBI.cost.rCost/pWInfo->a[j].rOptCost));
+          sWBI.cost.rCost /= pWInfo->a[j].rOptCost;
+        }
 
         /* Conditions under which this table becomes the best so far:
         **
@@ -5126,8 +5149,8 @@ WhereInfo *sqlite3WhereBegin(
         */
         if( (sWBI.cost.used&sWBI.notValid)==0                    /* (1) */
             && (bestJ<0 || (notIndexed&m)!=0                     /* (2) */
-                || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
-                || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
+                || isFullscan(bestPlan.plan.wsFlags)
+                || !isFullscan(sWBI.cost.plan.wsFlags))
             && (nUnconstrained==0 || sWBI.pSrc->pIndex==0        /* (3) */
                 || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
             && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan))   /* (4) */
index 2001e340097fd70318ac74780aa0d574632f9369..f459fc81950cca48ca35e11c78801e519500f761 100644 (file)
@@ -48,7 +48,7 @@ do_test 1.0 {
 } {}
 do_test 1.1a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
   }
 } {one-a one-c two-a two-b three-a three-c}
 
@@ -57,7 +57,7 @@ do_test 1.1a {
 do_test 1.1b {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
   }
 } {~/ORDER BY/}  ;# ORDER BY optimized out
 
@@ -66,7 +66,7 @@ do_test 1.1b {
 #
 do_test 1.2a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn
   }
 } {one-a one-c two-a two-b three-a three-c}
 
@@ -75,7 +75,7 @@ do_test 1.2a {
 do_test 1.2b {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn
   }
 } {/ORDER BY/}   ;# separate sorting pass due to "+" on ORDER BY terms
 
@@ -85,13 +85,13 @@ do_test 1.3a {
   optimization_control db order-by-idx-join 0
   db cache flush
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
   }
 } {one-a one-c two-a two-b three-a three-c}
 do_test 1.3b {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
   }
 } {/ORDER BY/}   ;# separate sorting pass due to disabled optimization
 optimization_control db all 1
@@ -101,53 +101,53 @@ db cache flush
 #
 do_test 1.4a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
   }
 } {three-a three-c two-a two-b one-a one-c}
 do_test 1.4b {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn
   }
 } {three-a three-c two-a two-b one-a one-c}  ;# verify same order after sorting
 do_test 1.4c {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
   }
 } {~/ORDER BY/}  ;# optimized out
 
 
 do_test 1.5a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
   }
 } {one-c one-a two-b two-a three-c three-a}
 do_test 1.5b {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC
   }
 } {one-c one-a two-b two-a three-c three-a}  ;# verify same order after sorting
 do_test 1.5c {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
   }
 } {~/ORDER BY/}  ;# optimized out
 
 do_test 1.6a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
   }
 } {three-c three-a two-b two-a one-c one-a}
 do_test 1.6b {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
   }
 } {three-c three-a two-b two-a one-c one-a}  ;# verify same order after sorting
 do_test 1.6c {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
   }
 } {~/ORDER BY/}  ;# ORDER BY optimized-out
 
@@ -183,7 +183,7 @@ do_test 2.0 {
 } {}
 do_test 2.1a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
   }
 } {one-a one-c two-a two-b three-a three-c}
 
@@ -192,19 +192,19 @@ do_test 2.1a {
 do_test 2.1b {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
   }
 } {~/ORDER BY/}  ;# ORDER BY optimized out
 
 do_test 2.1c {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn
   }
 } {one-a one-c two-a two-b three-a three-c}
 do_test 2.1d {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, aid, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, aid, tn
   }
 } {~/ORDER BY/}  ;# ORDER BY optimized out
 
@@ -213,7 +213,7 @@ do_test 2.1d {
 #
 do_test 2.2a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn
   }
 } {one-a one-c two-a two-b three-a three-c}
 
@@ -222,7 +222,7 @@ do_test 2.2a {
 do_test 2.2b {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn
   }
 } {/ORDER BY/}   ;# separate sorting pass due to "+" on ORDER BY terms
 
@@ -232,13 +232,13 @@ do_test 2.3a {
   optimization_control db order-by-idx-join 0
   db cache flush
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
   }
 } {one-a one-c two-a two-b three-a three-c}
 do_test 2.3b {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
   }
 } {/ORDER BY/}   ;# separate sorting pass due to disabled optimization
 optimization_control db all 1
@@ -248,53 +248,53 @@ db cache flush
 #
 do_test 2.4a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
   }
 } {three-a three-c two-a two-b one-a one-c}
 do_test 2.4b {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn
   }
 } {three-a three-c two-a two-b one-a one-c}  ;# verify same order after sorting
 do_test 2.4c {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
   }
 } {~/ORDER BY/}  ;# optimized out
 
 
 do_test 2.5a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
   }
 } {one-c one-a two-b two-a three-c three-a}
 do_test 2.5b {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC
   }
 } {one-c one-a two-b two-a three-c three-a}  ;# verify same order after sorting
 do_test 2.5c {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
   }
 } {~/ORDER BY/}  ;# optimized out
 
 do_test 2.6a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
   }
 } {three-c three-a two-b two-a one-c one-a}
 do_test 2.6b {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
   }
 } {three-c three-a two-b two-a one-c one-a}  ;# verify same order after sorting
 do_test 2.6c {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
   }
 } {~/ORDER BY/}  ;# ORDER BY optimized out
 
@@ -330,7 +330,7 @@ do_test 3.0 {
 } {}
 do_test 3.1a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
   }
 } {one-c one-a two-b two-a three-c three-a}
 
@@ -339,7 +339,7 @@ do_test 3.1a {
 do_test 3.1b {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
   }
 } {~/ORDER BY/}  ;# ORDER BY optimized out
 
@@ -348,7 +348,7 @@ do_test 3.1b {
 #
 do_test 3.2a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC
   }
 } {one-c one-a two-b two-a three-c three-a}
 
@@ -357,7 +357,7 @@ do_test 3.2a {
 do_test 3.2b {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn DESC
   }
 } {/ORDER BY/}   ;# separate sorting pass due to "+" on ORDER BY terms
 
@@ -367,13 +367,13 @@ do_test 3.3a {
   optimization_control db order-by-idx-join 0
   db cache flush
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
   }
 } {one-c one-a two-b two-a three-c three-a}
 do_test 3.3b {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn DESC
   }
 } {/ORDER BY/}   ;# separate sorting pass due to disabled optimization
 optimization_control db all 1
@@ -383,54 +383,54 @@ db cache flush
 #
 do_test 3.4a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
   }
 } {one-a one-c two-a two-b three-a three-c}
 do_test 3.4b {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title, +tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title, +tn
   }
 } {one-a one-c two-a two-b three-a three-c}  ;# verify same order after sorting
 do_test 3.4c {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title, tn
   }
 } {~/ORDER BY/}  ;# optimized out
 
 
 do_test 3.5a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
   }
 } {three-c three-a two-b two-a one-c one-a}
 do_test 3.5b {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn DESC
   }
 } {three-c three-a two-b two-a one-c one-a}  ;# verify same order after sorting
 do_test 3.5c {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn DESC
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn DESC
   }
 } {~/ORDER BY/}  ;# optimzed out
 
 
 do_test 3.6a {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
   }
 } {three-a three-c two-a two-b one-a one-c}
 do_test 3.6b {
   db eval {
-    SELECT name FROM album JOIN track USING (aid) ORDER BY +title DESC, +tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY +title DESC, +tn
   }
 } {three-a three-c two-a two-b one-a one-c}  ;# verify same order after sorting
 do_test 3.6c {
   db eval {
     EXPLAIN QUERY PLAN
-    SELECT name FROM album JOIN track USING (aid) ORDER BY title DESC, tn
+    SELECT name FROM album CROSS JOIN track USING (aid) ORDER BY title DESC, tn
   }
 } {~/ORDER BY/}  ;# inverted ASC/DESC is optimized out
 
diff --git a/test/whereE.test b/test/whereE.test
new file mode 100644 (file)
index 0000000..e686a46
--- /dev/null
@@ -0,0 +1,62 @@
+# 2012 November 9
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this file is testing the query planner to make sure it
+# is making good planning decisions.
+#
+
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set ::testprefix whereE
+
+do_execsql_test 1.1 {
+  CREATE TABLE t1(a,b);
+  INSERT INTO t1 VALUES(1,10), (2,20), (3,30), (2,22), (3, 33);
+  INSERT INTO t1 SELECT * FROM t1;
+  INSERT INTO t1 SELECT * FROM t1;
+  INSERT INTO t1 SELECT * FROM t1;
+  INSERT INTO t1 SELECT * FROM t1;
+  INSERT INTO t1 SELECT * FROM t1;
+  INSERT INTO t1 SELECT * FROM t1;
+  INSERT INTO t1 SELECT * FROM t1;
+  INSERT INTO t1 SELECT * FROM t1;
+  INSERT INTO t1 SELECT * FROM t1;
+  INSERT INTO t1 SELECT * FROM t1;
+  ALTER TABLE t1 ADD COLUMN c;
+  UPDATE t1 SET c=a*rowid+10000;
+  CREATE INDEX t1ab ON t1(a,b);
+  
+  CREATE TABLE t2(x,y);
+  INSERT INTO t2 VALUES(4,44),(5,55),(6,66),(7,77);
+  INSERT INTO t2 SELECT x+4, (x+4)*11 FROM t2;
+  INSERT INTO t2 SELECT x+8, (x+8)*11 FROM t2;
+  INSERT INTO t2 SELECT x+16, (x+16)*11 FROM t2;
+  INSERT INTO t2 SELECT x+32, (x+32)*11 FROM t2;
+  INSERT INTO t2 SELECT x+64, (x+32)*11 FROM t2;
+  ALTER TABLE t2 ADD COLUMN z;
+  UPDATE t2 SET z=2;
+  CREATE UNIQUE INDEX t2zx ON t2(z,x);
+
+  EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x;
+} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/}
+do_execsql_test 1.2 {
+  EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x;
+} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/}
+do_execsql_test 1.3 {
+  ANALYZE;
+  EXPLAIN QUERY PLAN SELECT x FROM t1, t2 WHERE a=z AND c=x;
+} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/}
+do_execsql_test 1.4 {
+  EXPLAIN QUERY PLAN SELECT x FROM t2, t1 WHERE a=z AND c=x;
+} {/.*SCAN TABLE t1 .*SEARCH TABLE t2 .*/}
+
+finish_test
diff --git a/test/whereF.test b/test/whereF.test
new file mode 100644 (file)
index 0000000..57bdbee
--- /dev/null
@@ -0,0 +1,115 @@
+# 2012 November 9
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# 
+# Test cases for query planning decisions.
+
+
+#
+# The tests in this file demonstrate the behaviour of the query planner
+# in determining the order in which joined tables are scanned.
+#
+# Assume there are two tables being joined - t1 and t2. Each has a cost
+# if it is the outer loop, and a cost if it is the inner loop. As follows:
+#
+#   t1(outer) - cost of scanning t1 as the outer loop.
+#   t1(inner) - cost of scanning t1 as the inner loop.
+#   t2(outer) - cost of scanning t2 as the outer loop.
+#   t2(inner) - cost of scanning t2 as the inner loop.
+#
+# Depending on the order in which the planner nests the scans, the total
+# cost of the join query is one of:
+#
+#   t1(outer) * t2(inner)
+#   t2(outer) * t1(inner)
+#
+# The tests in this file attempt to verify that the planner nests joins in
+# the correct order when the following are true:
+#
+#   + (t1(outer) * t2(inner)) > (t1(inner) * t2(outer)
+#   +  t1(outer) < t2(outer)
+#
+# In other words, when the best overall query plan has t2 as the outer loop,
+# but when the outer loop is considered independent of the inner, t1 is the
+# most efficient choice.
+#
+# In order to make them more predictable, automatic indexes are turned off for
+# the tests in this file.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+set testprefix x
+
+do_execsql_test 1.0 {
+  PRAGMA automatic_index = 0;
+  CREATE TABLE t1(a, b, c);
+  CREATE TABLE t2(d, e, f);
+  CREATE UNIQUE INDEX i1 ON t1(a);
+  CREATE UNIQUE INDEX i2 ON t2(d);
+} {}
+
+foreach {tn sql} {
+  1 "SELECT * FROM t1,           t2 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10"
+  2 "SELECT * FROM t2,           t1 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10"
+  3 "SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=t2.e AND t2.d<t1.b AND t1.c!=10"
+} {
+  do_test 1.$tn {
+    db eval "EXPLAIN QUERY PLAN $sql"
+   } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/}
+}
+
+do_execsql_test 2.0 {
+  DROP TABLE t1;
+  DROP TABLE t2;
+  CREATE TABLE t1(a, b, c);
+  CREATE TABLE t2(d, e, f);
+
+  CREATE UNIQUE INDEX i1 ON t1(a);
+  CREATE UNIQUE INDEX i2 ON t1(b);
+  CREATE UNIQUE INDEX i3 ON t2(d);
+} {}
+
+foreach {tn sql} {
+  1 "SELECT * FROM t1,           t2 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e"
+  2 "SELECT * FROM t2,           t1 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e"
+  3 "SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a>? AND t2.d>t1.c AND t1.b=t2.e"
+} {
+  do_test 2.$tn {
+    db eval "EXPLAIN QUERY PLAN $sql"
+   } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/}
+}
+
+do_execsql_test 3.0 {
+  DROP TABLE t1;
+  DROP TABLE t2;
+  CREATE TABLE t1(a, b, c);
+  CREATE TABLE t2(d, e, f);
+
+  CREATE UNIQUE INDEX i1 ON t1(a, b);
+  CREATE INDEX i2 ON t2(d);
+} {}
+
+foreach {tn sql} {
+  1 {SELECT t1.a, t1.b, t2.d, t2.e FROM t1, t2 
+     WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)}
+
+  2 {SELECT t1.a, t1.b, t2.d, t2.e FROM t2, t1 
+     WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)}
+
+  3 {SELECT t1.a, t1.b, t2.d, t2.e FROM t2 CROSS JOIN t1 
+     WHERE t2.d=t1.b AND t1.a=(t2.d+1) AND t1.b = (t2.e+1)}
+} {
+  do_test 3.$tn {
+    db eval "EXPLAIN QUERY PLAN $sql"
+   } {/.*SCAN TABLE t2 .*SEARCH TABLE t1 .*/}
+}
+
+finish_test