]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Enhance the geopoly virtual table so that it does a better job of optimizing
authordrh <drh@noemail.net>
Sat, 25 Aug 2018 23:03:27 +0000 (23:03 +0000)
committerdrh <drh@noemail.net>
Sat, 25 Aug 2018 23:03:27 +0000 (23:03 +0000)
geopoly_within() queries.

FossilOrigin-Name: 1f717385340f295064a7649cfc36ad048573cbacb6faa20f5c6067328c40c745

ext/rtree/geopoly.c
ext/rtree/visual01.txt
manifest
manifest.uuid

index 1ebca66259d9675dea41c11ae6fcc75bcf1b59c4..8b4246858eae062e1d0c0bca46635a7d0d0b1c0d 100644 (file)
@@ -1109,7 +1109,9 @@ static int geopolyConnect(
 **      1         rowid lookup
 **      2         search for objects overlapping the same bounding box
 **                that contains polygon argv[0]
-**      3         full table scan
+**      3         search for objects overlapping the same bounding box
+**                that contains polygon argv[0]
+**      4         full table scan
 */
 static int geopolyFilter(
   sqlite3_vtab_cursor *pVtabCursor,     /* The cursor to initialize */
@@ -1159,7 +1161,7 @@ static int geopolyFilter(
     ** with the configured constraints. 
     */
     rc = nodeAcquire(pRtree, 1, 0, &pRoot);
-    if( rc==SQLITE_OK && idxNum==2 ){
+    if( rc==SQLITE_OK && idxNum<=3 ){
       RtreeCoord bbox[4];
       RtreeConstraint *p;
       assert( argc==1 );
@@ -1174,21 +1176,41 @@ static int geopolyFilter(
       }else{
         memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*4);
         memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1));
-        p->op = 'B';
-        p->iCoord = 0;
-        p->u.rValue = bbox[1].f;
-        p++;
-        p->op = 'D';
-        p->iCoord = 1;
-        p->u.rValue = bbox[0].f;
-        p++;
-        p->op = 'B';
-        p->iCoord = 2;
-        p->u.rValue = bbox[3].f;
-        p++;
-        p->op = 'D';
-        p->iCoord = 3;
-        p->u.rValue = bbox[2].f;
+        if( idxNum==2 ){
+          /* Overlap query */
+          p->op = 'B';
+          p->iCoord = 0;
+          p->u.rValue = bbox[1].f;
+          p++;
+          p->op = 'D';
+          p->iCoord = 1;
+          p->u.rValue = bbox[0].f;
+          p++;
+          p->op = 'B';
+          p->iCoord = 2;
+          p->u.rValue = bbox[3].f;
+          p++;
+          p->op = 'D';
+          p->iCoord = 3;
+          p->u.rValue = bbox[2].f;
+        }else{
+          /* Within query */
+          p->op = 'D';
+          p->iCoord = 0;
+          p->u.rValue = bbox[0].f;
+          p++;
+          p->op = 'B';
+          p->iCoord = 1;
+          p->u.rValue = bbox[1].f;
+          p++;
+          p->op = 'D';
+          p->iCoord = 2;
+          p->u.rValue = bbox[2].f;
+          p++;
+          p->op = 'B';
+          p->iCoord = 3;
+          p->u.rValue = bbox[3].f;
+        }
       }
     }
     if( rc==SQLITE_OK ){
@@ -1218,15 +1240,17 @@ static int geopolyFilter(
 **
 **   idxNum     idxStr        Strategy
 **   ------------------------------------------------
-**     1        Unused        Direct lookup by rowid.
-**     2        Unused        R-tree query
-**     3        Unused        full-table scan.
+**     1        "rowid"       Direct lookup by rowid.
+**     2        "rtree"       R-tree overlap query using geopoly_overlap()
+**     3        "rtree"       R-tree within query using geopoly_within()
+**     4        "fullscan"    full-table scan.
 **   ------------------------------------------------
 */
 static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
   int ii;
   int iRowidTerm = -1;
   int iFuncTerm = -1;
+  int idxNum = 0;
 
   for(ii=0; ii<pIdxInfo->nConstraint; ii++){
     struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
@@ -1235,8 +1259,12 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
       iRowidTerm = ii;
       break;
     }
-    if( p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION ){
+    if( p->iColumn==0 && p->op>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){
+      /* p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION for geopoly_overlap()
+      ** p->op==(SQLITE_INDEX_CONTRAINT_FUNCTION+1) for geopoly_within().
+      ** See geopolyFindFunction() */
       iFuncTerm = ii;
+      idxNum = p->op - SQLITE_INDEX_CONSTRAINT_FUNCTION + 2;
     }
   }
 
@@ -1251,7 +1279,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
     return SQLITE_OK;
   }
   if( iFuncTerm>=0 ){
-    pIdxInfo->idxNum = 2;
+    pIdxInfo->idxNum = idxNum;
     pIdxInfo->idxStr = "rtree";
     pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1;
     pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0;
@@ -1259,7 +1287,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
     pIdxInfo->estimatedRows = 10;
     return SQLITE_OK;
   }
-  pIdxInfo->idxNum = 3;
+  pIdxInfo->idxNum = 4;
   pIdxInfo->idxStr = "fullscan";
   pIdxInfo->estimatedCost = 3000000.0;
   pIdxInfo->estimatedRows = 100000;
@@ -1461,7 +1489,7 @@ static int geopolyFindFunction(
   if( nArg==2 && sqlite3_stricmp(zName, "geopoly_within")==0 ){
     *pxFunc = geopolyWithinFunc;
     *ppArg = 0;
-    return SQLITE_INDEX_CONSTRAINT_FUNCTION;
+    return SQLITE_INDEX_CONSTRAINT_FUNCTION+1;
   }
   return 0;
 }
index 9aafb14dc36f4391d5056bf685a0c851316c5fb8..f9692714a640e66dc2d986213eedb5c8dae907db 100644 (file)
@@ -396,6 +396,34 @@ SELECT geopoly_svg(poly,
   FROM querypoly;
 .print '</svg>'
 
+.print '<h1>Bounding-Box Overlap Query</h1>'
+.print '<pre>'
+EXPLAIN QUERY PLAN
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       )
+  FROM geo1, querypoly
+ WHERE geopoly_overlap(geopoly_bbox(_shape), geopoly_bbox(poly));
+.print '</pre>'
+.print '<svg width="1000" height="800" style="border:1px solid black">'
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       ),
+       geopoly_svg(geopoly_bbox(_shape),
+         'style="fill:none;stroke:black;stroke-width:1"'
+       )
+  FROM geo1, querypoly
+ WHERE geopoly_overlap(geopoly_bbox(_shape), geopoly_bbox(poly));
+SELECT geopoly_svg(poly, 
+         printf('style="fill:%s;fill-opacity:0.5;"',clr)
+       )
+  FROM querypoly;
+SELECT geopoly_svg(geopoly_bbox(poly),
+         'style="fill:none;stroke:black;stroke-width:3"'
+       )
+  FROM querypoly;
+.print '</svg>'
+
 .print '<h1>Within Query</h1>'
 .print '<pre>'
 EXPLAIN QUERY PLAN
@@ -417,6 +445,34 @@ SELECT geopoly_svg(poly,
   FROM querypoly;
 .print '</svg>'
 
+.print '<h1>Bounding-Box WITHIN Query</h1>'
+.print '<pre>'
+EXPLAIN QUERY PLAN
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       )
+  FROM geo1, querypoly
+ WHERE geopoly_within(geopoly_bbox(_shape), geopoly_bbox(poly));
+.print '</pre>'
+.print '<svg width="1000" height="800" style="border:1px solid black">'
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       ),
+       geopoly_svg(geopoly_bbox(_shape),
+         'style="fill:none;stroke:black;stroke-width:1"'
+       )
+  FROM geo1, querypoly
+ WHERE geopoly_within(geopoly_bbox(_shape), geopoly_bbox(poly));
+SELECT geopoly_svg(poly, 
+         printf('style="fill:%s;fill-opacity:0.5;"',clr)
+       )
+  FROM querypoly;
+SELECT geopoly_svg(geopoly_bbox(poly),
+         'style="fill:none;stroke:black;stroke-width:3"'
+       )
+  FROM querypoly;
+.print '</svg>'
+
 .print '<h1>Not Overlap Query</h1>'
 .print '<pre>'
 EXPLAIN QUERY PLAN
index 4be8e181d68ff7d3b6752394692b2d738ba3a410..ac0fba20746fd486ecc4da320e410d8923f45e8e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Provide\sthe\stwo-argument\sgeopoly_within(P1,P2)\sroutine\sthat\sdetermines\sif\npolygon\sP2\sis\scontained\swithin\spolygon\sP1.\s\sMake\sthis\sfunction\savailable\sto\nthe\squery\splanner\sfor\soptimized\srtree\slookups.\s\sUpdate\sthe\svisual01.txt\nscript\sto\sverify\sthat\sthe\snew\sfunctionality\sactually\sworks.
-D 2018-08-25T19:51:49.457
+C Enhance\sthe\sgeopoly\svirtual\stable\sso\sthat\sit\sdoes\sa\sbetter\sjob\sof\soptimizing\ngeopoly_within()\squeries.
+D 2018-08-25T23:03:27.261
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f
@@ -359,7 +359,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782
 F ext/repair/test/checkindex01.test 6945d0ffc0c1dc993b2ce88036b26e0f5d6fcc65da70fc9df27c2647bb358b0f
 F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
-F ext/rtree/geopoly.c b495718226257fe7a69df3367ae9a440a81f99e63013177cb327fbc8a12a1d92
+F ext/rtree/geopoly.c a265dcbd7131b3bc92e081a17deb9b502c4f5eb8f21084f8e337013b9ff3a44a
 F ext/rtree/rtree.c f3c2f1b5eea75b98d4d3dcdec2ebf2a69c036b53f2f3d196e61bf5016298255f
 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349
@@ -386,7 +386,7 @@ F ext/rtree/rtreeconnect.test 225ad3fcb483d36cbee423a25052a6bbae762c9576ae926833
 F ext/rtree/sqlite3rtree.h 9c5777af3d2921c7b4ae4954e8e5697502289d28
 F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
 F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
-F ext/rtree/visual01.txt c5cceddea30ab74099365a54ee8850f085d01503050353240eda48b6062ad3f4
+F ext/rtree/visual01.txt 9852cd026953dd0e6fcfae49f72f51b3b9a42f11f2f38720e9f6d4993d862802
 F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a
 F ext/session/session1.test 4532116484f525110eb4cfff7030c59354c0cde9def4d109466b0df2b35ad5cc
 F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0
@@ -1757,7 +1757,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P d49be9838d237b57ba1f12ed00e2d3411314ee1b9c30ef7bbaf65aca20d0870e
-R d6a6a8b236c31c3e94eaf646cbba5241
+P 6eb5d09b7f9d9bf8edbf993dccc2e2f702b95ba96cf68445609feb0ccc3ac0f7
+R 163f1378dd6b33d45a7ba74154a94c1d
 U drh
-Z 150d6fa9f487a014f94bf1a66214204f
+Z 9fe6062c3d32e76299fd6a57239e260e
index c25d834242823dfb1c6bd6d4aefb6b7ae8f5c6c6..79c7afc57f362e48cde8ede87821bf151e4ffa93 100644 (file)
@@ -1 +1 @@
-6eb5d09b7f9d9bf8edbf993dccc2e2f702b95ba96cf68445609feb0ccc3ac0f7
\ No newline at end of file
+1f717385340f295064a7649cfc36ad048573cbacb6faa20f5c6067328c40c745
\ No newline at end of file