]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Untested incremental check-in. Basic infrastructure for geopoly in place,
authordrh <drh@noemail.net>
Fri, 25 May 2018 22:39:29 +0000 (22:39 +0000)
committerdrh <drh@noemail.net>
Fri, 25 May 2018 22:39:29 +0000 (22:39 +0000)
except for the MATCH operator.

FossilOrigin-Name: b27451910b6880b166d4777e05b14ab2731c3483b5ed0f42c459bbb61c6cd095

ext/rtree/geopoly.c
manifest
manifest.uuid

index f22f762e7ca04773eb2abebc67028952a67e68fe..427462b5601b513869ed25e27746af2f0d687068 100644 (file)
@@ -193,8 +193,9 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
 **
 ** If any error occurs, return NULL.
 */
-static GeoPoly *geopolyParseJson(const unsigned char *z){
+static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){
   GeoParse s;
+  int rc = SQLITE_OK;
   memset(&s, 0, sizeof(s));
   s.z = z;
   if( geopolySkipSpace(&s)=='[' ){
@@ -208,6 +209,7 @@ static GeoPoly *geopolyParseJson(const unsigned char *z){
         s.nAlloc = s.nAlloc*2 + 16;
         aNew = sqlite3_realloc64(s.a, s.nAlloc*sizeof(GeoCoord)*2 );
         if( aNew==0 ){
+          rc = SQLITE_NOMEM;
           s.nErr++;
           break;
         }
@@ -221,6 +223,7 @@ static GeoPoly *geopolyParseJson(const unsigned char *z){
         if( c==',' ) continue;
         if( c==']' ) break;
         s.nErr++;
+        rc = SQLITE_ERROR;
         goto parse_json_err;
       }
       if( geopolySkipSpace(&s)==',' ){
@@ -245,12 +248,15 @@ static GeoPoly *geopolyParseJson(const unsigned char *z){
       pOut->hdr[2] = (s.nVertex>>8)&0xff;
       pOut->hdr[3] = s.nVertex&0xff;
       sqlite3_free(s.a);
+      if( pRc ) *pRc = SQLITE_OK;
       return pOut;
     }else{
       s.nErr++;
+      rc = SQLITE_ERROR;
     }
   }
 parse_json_err:
+  if( pRc ) *pRc = rc;
   sqlite3_free(s.a);
   return 0;
 }
@@ -261,7 +267,11 @@ parse_json_err:
 ** return a pointer to that object.  Or if the input is not a well-formed
 ** polygon, put an error message in sqlite3_context and return NULL.
 */
-static GeoPoly *geopolyFuncParam(sqlite3_context *pCtx, sqlite3_value *pVal){
+static GeoPoly *geopolyFuncParam(
+  sqlite3_context *pCtx,      /* Context for error messages */
+  sqlite3_value *pVal,        /* The value to decode */
+  int *pRc                    /* Write error here */
+){
   GeoPoly *p = 0;
   int nByte;
   if( sqlite3_value_type(pVal)==SQLITE_BLOB
@@ -274,7 +284,10 @@ static GeoPoly *geopolyFuncParam(sqlite3_context *pCtx, sqlite3_value *pVal){
      && (nVertex*2*sizeof(GeoCoord) + 4)==nByte
     ){
       p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) );
-      if( p ){
+      if( p==0 ){
+        if( pRc ) *pRc = SQLITE_NOMEM;
+        if( pCtx ) sqlite3_result_error_nomem(pCtx);
+      }else{
         int x = 1;
         p->nVertex = nVertex;
         memcpy(p->hdr, a, nByte);
@@ -287,13 +300,15 @@ static GeoPoly *geopolyFuncParam(sqlite3_context *pCtx, sqlite3_value *pVal){
         }
       }
     }
+    if( pRc ) *pRc = SQLITE_OK;
+    return p;
   }else if( sqlite3_value_type(pVal)==SQLITE_TEXT ){
-    p = geopolyParseJson(sqlite3_value_text(pVal));
-  }
-  if( p==0 ){
-    sqlite3_result_error(pCtx, "not a valid polygon", -1);
+    return geopolyParseJson(sqlite3_value_text(pVal), pRc);
+  }else{
+    *pRc = SQLITE_ERROR;
+    if( pCtx!=0 ) sqlite3_result_error(pCtx, "not a valid polygon", -1);
+    return 0;
   }
-  return p;
 }
 
 /*
@@ -308,7 +323,7 @@ static void geopolyBlobFunc(
   int argc,
   sqlite3_value **argv
 ){
-  GeoPoly *p = geopolyFuncParam(context, argv[0]);
+  GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
   if( p ){
     sqlite3_result_blob(context, p->hdr, 
        4+8*p->nVertex, SQLITE_TRANSIENT);
@@ -327,7 +342,7 @@ static void geopolyJsonFunc(
   int argc,
   sqlite3_value **argv
 ){
-  GeoPoly *p = geopolyFuncParam(context, argv[0]);
+  GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
   if( p ){
     sqlite3 *db = sqlite3_context_db_handle(context);
     sqlite3_str *x = sqlite3_str_new(db);
@@ -353,7 +368,7 @@ static void geopolySvgFunc(
   int argc,
   sqlite3_value **argv
 ){
-  GeoPoly *p = geopolyFuncParam(context, argv[0]);
+  GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
   if( p ){
     sqlite3 *db = sqlite3_context_db_handle(context);
     sqlite3_str *x = sqlite3_str_new(db);
@@ -390,7 +405,7 @@ static void geopolyAreaFunc(
   int argc,
   sqlite3_value **argv
 ){
-  GeoPoly *p = geopolyFuncParam(context, argv[0]);
+  GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
   if( p ){
     double rArea = 0.0;
     int ii;
@@ -415,10 +430,11 @@ static void geopolyAreaFunc(
 static GeoPoly *geopolyBBox(
   sqlite3_context *context,   /* For recording the error */
   sqlite3_value *pPoly,       /* The polygon */
-  double *aCoord              /* Results here */
+  RtreeCoord *aCoord,         /* Results here */
+  int *pRc                    /* Error code here */
 ){
-  GeoPoly *p = geopolyFuncParam(context, pPoly);
-  GeoPoly *pOut;
+  GeoPoly *p = geopolyFuncParam(context, pPoly, pRc);
+  GeoPoly *pOut = 0;
   if( p ){
     int ii;
     float mnX, mxX, mnY, mxY;
@@ -432,11 +448,13 @@ static GeoPoly *geopolyBBox(
       if( r<mnY ) mnY = r;
       else if( r>mxY ) mxY = r;
     }
+    if( pRc ) *pRc = SQLITE_OK;
     if( aCoord==0 ){
       pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6);
       if( pOut==0 ){
         sqlite3_free(p);
-        sqlite3_result_error_nomem(context);
+        if( context ) sqlite3_result_error_nomem(context);
+        if( pRc ) *pRc = SQLITE_NOMEM;
         return 0;
       }
       pOut->nVertex = 4;
@@ -451,17 +469,15 @@ static GeoPoly *geopolyBBox(
       pOut->a[5] = mxY;
       pOut->a[6] = mnX;
       pOut->a[7] = mxY;
-      return pOut;
     }else{
       sqlite3_free(p);
-      aCoord[0] = mnX;
-      aCoord[1] = mxX;
-      aCoord[2] = mnY;
-      aCoord[3] = mxY;
-      return (GeoPoly*)aCoord;
+      aCoord[0].f = mnX;
+      aCoord[1].f = mxX;
+      aCoord[2].f = mnY;
+      aCoord[3].f = mxY;
     }
   }
-  return 0;
+  return pOut;
 }
 
 /*
@@ -472,7 +488,7 @@ static void geopolyBBoxFunc(
   int argc,
   sqlite3_value **argv
 ){
-  GeoPoly *p = geopolyBBox(context, argv[0], 0);
+  GeoPoly *p = geopolyBBox(context, argv[0], 0, 0);
   if( p ){
     sqlite3_result_blob(context, p->hdr, 
        4+8*p->nVertex, SQLITE_TRANSIENT);
@@ -530,7 +546,7 @@ static void geopolyWithinFunc(
   int argc,
   sqlite3_value **argv
 ){
-  GeoPoly *p = geopolyFuncParam(context, argv[0]);
+  GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
   double x0 = sqlite3_value_double(argv[1]);
   double y0 = sqlite3_value_double(argv[2]);
   if( p ){
@@ -874,8 +890,8 @@ static void geopolyOverlapFunc(
   int argc,
   sqlite3_value **argv
 ){
-  GeoPoly *p1 = geopolyFuncParam(context, argv[0]);
-  GeoPoly *p2 = geopolyFuncParam(context, argv[1]);
+  GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
+  GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
   if( p1 && p2 ){
     int x = geopolyOverlap(p1, p2);
     if( x<0 ){
@@ -955,12 +971,13 @@ static int geopolyInit(
   pSql = sqlite3_str_new(db);
   sqlite3_str_appendf(pSql, "CREATE TABLE x");
   cSep = '(';
+  pRtree->nAux = 1;   /* Add one for _shape */
   for(ii=3; ii<argc; ii++){
     pRtree->nAux++;
     sqlite3_str_appendf(pSql, "%c%s", cSep, argv[ii]+1);
     cSep = ',';
   }
-  sqlite3_str_appendf(pSql, "%c _poly HIDDEN, _bbox HIDDEN);", cSep);
+  sqlite3_str_appendf(pSql, "%c _shape, _bbox HIDDEN);", cSep);
   zSql = sqlite3_str_finish(pSql);
   if( !zSql ){
     rc = SQLITE_NOMEM;
@@ -1164,9 +1181,13 @@ static int geopolyUpdate(
 ){
   Rtree *pRtree = (Rtree *)pVtab;
   int rc = SQLITE_OK;
-//  RtreeCell cell;                 /* New cell to insert if nData>1 */
-//  int bHaveRowid = 0;             /* Set to 1 after new rowid is determined */
-//  int iShapeCol;                  /* Index of the _shape column */
+  RtreeCell cell;                 /* New cell to insert if nData>1 */
+  int iShapeCol;                  /* Index of the _shape column */
+  i64 oldRowid;                   /* The old rowid */
+  int oldRowidValid;              /* True if oldRowid is valid */
+  i64 newRowid;                   /* The new rowid */
+  int newRowidValid;              /* True if newRowid is valid */
+  int coordChange = 0;            /* Change in coordinates */
 
   if( pRtree->nNodeRef ){
     /* Unable to write to the btree while another cursor is reading from it,
@@ -1177,72 +1198,43 @@ static int geopolyUpdate(
   rtreeReference(pRtree);
   assert(nData>=1);
 
-//  cell.iRowid = 0;  /* Used only to suppress a compiler warning */
-//  iShapeCol = pRtree->nAux;
-
+  iShapeCol = pRtree->nAux;
   rc = SQLITE_ERROR;
-
-#if 0
-
-  /* Constraint handling. A write operation on an r-tree table may return
-  ** SQLITE_CONSTRAINT for two reasons:
-  **
-  **   1. A duplicate rowid value, or
-  **   2. The supplied data violates the "x2>=x1" constraint.
-  **
-  ** In the first case, if the conflict-handling mode is REPLACE, then
-  ** the conflicting row can be removed before proceeding. In the second
-  ** case, SQLITE_CONSTRAINT must be returned regardless of the
-  ** conflict-handling mode specified by the user.
-  */
-  if( nData>1 
-   && (!sqlite3_value_nochange(aData[iShapeCol+2])
+  oldRowidValid = sqlite3_value_type(aData[0])!=SQLITE_NULL;;
+  oldRowid = oldRowidValid ? sqlite3_value_int64(aData[0]) : 0;
+  newRowidValid = nData>1 && sqlite3_value_type(aData[1])!=SQLITE_NULL;
+  newRowid = newRowidValid ? sqlite3_value_int64(aData[1]) : 0;
+  cell.iRowid = newRowid;
+
+  if( nData>1                                           /* not a DELETE */
+   && (!oldRowidValid                                   /* INSERT */
+        || !sqlite3_value_nochange(aData[iShapeCol+2])  /* UPDATE _shape */
+        || oldRowid!=newRowid)                          /* Rowid change */
   ){
-
-#ifndef SQLITE_RTREE_INT_ONLY
-    if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
-      for(ii=0; ii<nn; ii+=2){
-        cell.aCoord[ii].f = rtreeValueDown(aData[ii+3]);
-        cell.aCoord[ii+1].f = rtreeValueUp(aData[ii+4]);
-        if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
-          rc = rtreeConstraintError(pRtree, ii+1);
-          goto constraint;
-        }
-      }
-    }else
-#endif
-    {
-      for(ii=0; ii<nn; ii+=2){
-        cell.aCoord[ii].i = sqlite3_value_int(aData[ii+3]);
-        cell.aCoord[ii+1].i = sqlite3_value_int(aData[ii+4]);
-        if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){
-          rc = rtreeConstraintError(pRtree, ii+1);
-          goto constraint;
-        }
+    geopolyBBox(0, aData[iShapeCol+2], cell.aCoord, &rc);
+    if( rc ){
+      if( rc==SQLITE_ERROR ){
+        pVtab->zErrMsg =
+          sqlite3_mprintf("_shape does not contain a valid polygon");
       }
+      return rc;
     }
+    coordChange = 1;
 
     /* If a rowid value was supplied, check if it is already present in 
     ** the table. If so, the constraint has failed. */
-    if( sqlite3_value_type(aData[2])!=SQLITE_NULL ){
-      cell.iRowid = sqlite3_value_int64(aData[2]);
-      if( sqlite3_value_type(aData[0])==SQLITE_NULL
-       || sqlite3_value_int64(aData[0])!=cell.iRowid
-      ){
-        int steprc;
-        sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid);
-        steprc = sqlite3_step(pRtree->pReadRowid);
-        rc = sqlite3_reset(pRtree->pReadRowid);
-        if( SQLITE_ROW==steprc ){
-          if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
-            rc = rtreeDeleteRowid(pRtree, cell.iRowid);
-          }else{
-            rc = rtreeConstraintError(pRtree, 0);
-            goto constraint;
-          }
+    if( oldRowidValid && oldRowid!=newRowid ){
+      int steprc;
+      sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid);
+      steprc = sqlite3_step(pRtree->pReadRowid);
+      rc = sqlite3_reset(pRtree->pReadRowid);
+      if( SQLITE_ROW==steprc ){
+        if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
+          rc = rtreeDeleteRowid(pRtree, cell.iRowid);
+        }else{
+          rc = rtreeConstraintError(pRtree, 0);
         }
       }
-      bHaveRowid = 1;
     }
   }
 
@@ -1250,24 +1242,18 @@ static int geopolyUpdate(
   ** record to delete from the r-tree table. The following block does
   ** just that.
   */
-  if( sqlite3_value_type(aData[0])!=SQLITE_NULL ){
-    rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(aData[0]));
+  if( rc==SQLITE_OK && (nData==1 || coordChange) ){
+    rc = rtreeDeleteRowid(pRtree, oldRowid);
   }
 
   /* If the aData[] array contains more than one element, elements
   ** (aData[2]..aData[argc-1]) contain a new record to insert into
   ** the r-tree structure.
   */
-  if( rc==SQLITE_OK && nData>1 ){
+  if( rc==SQLITE_OK && nData>1 && coordChange ){
     /* Insert the new record into the r-tree */
     RtreeNode *pLeaf = 0;
-
-    /* Figure out the rowid of the new row. */
-    if( bHaveRowid==0 ){
-      rc = newRowid(pRtree, &cell.iRowid);
-    }
     *pRowid = cell.iRowid;
-
     if( rc==SQLITE_OK ){
       rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf);
     }
@@ -1280,19 +1266,23 @@ static int geopolyUpdate(
         rc = rc2;
       }
     }
-    if( pRtree->nAux ){
-      sqlite3_stmt *pUp = pRtree->pWriteAux;
-      int jj;
-      sqlite3_bind_int64(pUp, 1, *pRowid);
-      for(jj=0; jj<pRtree->nAux; jj++){
-        sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]);
-      }
+  }
+
+  /* Change the data */
+  if( rc==SQLITE_OK && pRtree->nAux>0 ){
+    sqlite3_stmt *pUp = pRtree->pWriteAux;
+    int jj;
+    int nChange = 0;
+    sqlite3_bind_int64(pUp, 1, newRowid);
+    for(jj=0; jj<pRtree->nAux; jj++){
+      if( !sqlite3_value_nochange(aData[jj+2]) ) nChange++;
+      sqlite3_bind_value(pUp, jj+2, aData[jj+2]);
+    }
+    if( nChange ){
       sqlite3_step(pUp);
       rc = sqlite3_reset(pUp);
     }
   }
-constraint:
-#endif /* 0 */
 
   rtreeRelease(pRtree);
   return rc;
index 042bcab12b25f6ac0118d1630d771c76110d8abc..44b42dc0f8b38b67e167af2a3f9e579eafead0f1 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Incremental\scheck-in:\sProgress\stoward\simplementing\sthe\sgeopoly\svtab.
-D 2018-05-25T20:53:42.012
+C Untested\sincremental\scheck-in.\s\sBasic\sinfrastructure\sfor\sgeopoly\sin\splace,\nexcept\sfor\sthe\sMATCH\soperator.
+D 2018-05-25T22:39:29.495
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in 51407f0e371dcb9e65d368bd4f1a08fc17ef8361ff11aac9356f0f63693b38dd
@@ -355,7 +355,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 bf7a5fc70df145e83b60abd3e9828ad036921a9603087f5f108e054d75f12abc
+F ext/rtree/geopoly.c e1b192440686ee041f94a510298f5d1d44e24f5c777674c1d00be616c6ac9633
 F ext/rtree/rtree.c 2fd3c149c6fc4d3fdf602dc610b34ad9abdf75cca26d0c362f903aa02ea2ef47
 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349
@@ -1730,7 +1730,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 0593aac88a8c25ddafba4c29a181ee083dfc3dab44335feb6f12fdea6ce7fb27
-R 36e4ed5dc1a640520059a271545fd8c3
+P 9b7d6f986a19f8fbe26d880dc368870a10df80e06097be34ee3639f78c50be61
+R ac42d4684558c7281aaaaec9453f13e7
 U drh
-Z b8c6ea17872c9a8b20afb569a3513051
+Z b54e65d1af2e3764e8c52f03dab6b0ff
index 52355d0aedf1df71ea37b49197e24bde1cf1f25a..78ee84ffb17201e3a77c8e14f157958fb7db43f4 100644 (file)
@@ -1 +1 @@
-9b7d6f986a19f8fbe26d880dc368870a10df80e06097be34ee3639f78c50be61
\ No newline at end of file
+b27451910b6880b166d4777e05b14ab2731c3483b5ed0f42c459bbb61c6cd095
\ No newline at end of file