From 748b8fda902827d513530846aa6112300eeeaccc Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 25 May 2018 19:22:47 +0000 Subject: [PATCH 01/33] Forward port the geopoly extension functions into the r-tree extension, with the idea of creating a new spatial index based on simply polygons. FossilOrigin-Name: 0593aac88a8c25ddafba4c29a181ee083dfc3dab44335feb6f12fdea6ce7fb27 --- Makefile.in | 6 +- Makefile.msc | 6 +- configure | 44 ++- configure.ac | 10 + ext/rtree/geopoly.c | 853 ++++++++++++++++++++++++++++++++++++++++++++ ext/rtree/rtree.c | 9 + main.mk | 6 +- manifest | 28 +- manifest.uuid | 2 +- tool/mksqlite3c.tcl | 3 +- 10 files changed, 933 insertions(+), 34 deletions(-) create mode 100644 ext/rtree/geopoly.c diff --git a/Makefile.in b/Makefile.in index ac84fe832c..b8bcbd6864 100644 --- a/Makefile.in +++ b/Makefile.in @@ -349,7 +349,8 @@ SRC += \ $(TOP)/ext/icu/icu.c SRC += \ $(TOP)/ext/rtree/rtree.h \ - $(TOP)/ext/rtree/rtree.c + $(TOP)/ext/rtree/rtree.c \ + $(TOP)/ext/rtree/geopoly.c SRC += \ $(TOP)/ext/session/sqlite3session.c \ $(TOP)/ext/session/sqlite3session.h @@ -549,7 +550,8 @@ EXTHDR += \ $(TOP)/ext/fts3/fts3_hash.h \ $(TOP)/ext/fts3/fts3_tokenizer.h EXTHDR += \ - $(TOP)/ext/rtree/rtree.h + $(TOP)/ext/rtree/rtree.h \ + $(TOP)/ext/rtree/geopoly.c EXTHDR += \ $(TOP)/ext/icu/sqliteicu.h EXTHDR += \ diff --git a/Makefile.msc b/Makefile.msc index 8513996b6a..0c58cb181d 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -338,7 +338,7 @@ SQLITE_TCL_DEP = !IFNDEF OPT_FEATURE_FLAGS !IF $(MINIMAL_AMALGAMATION)==0 OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3=1 -OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 +OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_GEOPOLY=1 !ENDIF OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_COLUMN_METADATA=1 !ENDIF @@ -1400,6 +1400,7 @@ SRC09 = \ $(TOP)\ext\fts3\fts3_tokenizer.h \ $(TOP)\ext\icu\sqliteicu.h \ $(TOP)\ext\rtree\rtree.h \ + $(TOP)\ext\rtree\geopoly.c \ $(TOP)\ext\rbu\sqlite3rbu.h \ $(TOP)\ext\session\sqlite3session.h @@ -1573,7 +1574,8 @@ EXTHDR = $(EXTHDR) \ $(TOP)\ext\fts3\fts3_hash.h \ $(TOP)\ext\fts3\fts3_tokenizer.h EXTHDR = $(EXTHDR) \ - $(TOP)\ext\rtree\rtree.h + $(TOP)\ext\rtree\rtree.h \ + $(TOP)\ext\rtree\geopoly.c EXTHDR = $(EXTHDR) \ $(TOP)\ext\icu\sqliteicu.h EXTHDR = $(EXTHDR) \ diff --git a/configure b/configure index ea1160120f..c2a232b53c 100755 --- a/configure +++ b/configure @@ -911,6 +911,7 @@ enable_fts4 enable_fts5 enable_json1 enable_update_limit +enable_geopoly enable_rtree enable_session enable_gcov @@ -1563,6 +1564,7 @@ Optional Features: --enable-fts5 Enable the FTS5 extension --enable-json1 Enable the JSON1 extension --enable-update-limit Enable the UPDATE/DELETE LIMIT clause + --enable-geopoly Enable the GEOPOLY extension --enable-rtree Enable the RTREE extension --enable-session Enable the SESSION extension --enable-gcov Enable coverage testing using gcov @@ -3932,13 +3934,13 @@ if ${lt_cv_nm_interface+:} false; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:3935: $ac_compile\"" >&5) + (eval echo "\"\$as_me:3937: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:3938: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:3940: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:3941: output\"" >&5) + (eval echo "\"\$as_me:3943: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -5144,7 +5146,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5147 "configure"' > conftest.$ac_ext + echo '#line 5149 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -6669,11 +6671,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:6672: $lt_compile\"" >&5) + (eval echo "\"\$as_me:6674: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:6676: \$? = $ac_status" >&5 + echo "$as_me:6678: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7008,11 +7010,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7011: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7013: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7015: \$? = $ac_status" >&5 + echo "$as_me:7017: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7113,11 +7115,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7116: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7118: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7120: \$? = $ac_status" >&5 + echo "$as_me:7122: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -7168,11 +7170,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7171: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7173: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7175: \$? = $ac_status" >&5 + echo "$as_me:7177: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -9548,7 +9550,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9551 "configure" +#line 9553 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -9644,7 +9646,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 9647 "configure" +#line 9649 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11630,6 +11632,20 @@ if test "${enable_udlimit}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" fi +######### +# See whether we should enable GEOPOLY +# Check whether --enable-geopoly was given. +if test "${enable_geopoly+set}" = set; then : + enableval=$enable_geopoly; enable_geopoly=yes +else + enable_geopoly=no +fi + +if test "${enable_geopoly}" = "yes" ; then + OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY" + enable_rtree=yes +fi + ######### # See whether we should enable RTREE # Check whether --enable-rtree was given. diff --git a/configure.ac b/configure.ac index 7089772d19..f9e347d969 100644 --- a/configure.ac +++ b/configure.ac @@ -660,6 +660,16 @@ if test "${enable_udlimit}" = "yes" ; then OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT" fi +######### +# See whether we should enable GEOPOLY +AC_ARG_ENABLE(geopoly, AC_HELP_STRING([--enable-geopoly], + [Enable the GEOPOLY extension]), + [enable_geopoly=yes],[enable_geopoly=no]) +if test "${enable_geopoly}" = "yes" ; then + OPT_FEATURE_FLAGS="${OPT_FEATURE_FLAGS} -DSQLITE_ENABLE_GEOPOLY" + enable_rtree=yes +fi + ######### # See whether we should enable RTREE AC_ARG_ENABLE(rtree, AC_HELP_STRING([--enable-rtree], diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c new file mode 100644 index 0000000000..3808871135 --- /dev/null +++ b/ext/rtree/geopoly.c @@ -0,0 +1,853 @@ +/* +** 2018-05-25 +** +** 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 an alternative R-Tree virtual table that +** uses polygons to express the boundaries of 2-dimensional objects. +** +** This file is #include-ed onto the end of "rtree.c" so that it has +** access to all of the R-Tree internals. +*/ +#include + +/* Enable -DGEOPOLY_ENABLE_DEBUG for debugging facilities */ +#ifdef GEOPOLY_ENABLE_DEBUG + static int geo_debug = 0; +# define GEODEBUG(X) if(geo_debug)printf X +#else +# define GEODEBUG(X) +#endif + +#ifndef JSON_NULL /* The following stuff repeats things found in json1 */ +/* +** Versions of isspace(), isalnum() and isdigit() to which it is safe +** to pass signed char values. +*/ +#ifdef sqlite3Isdigit + /* Use the SQLite core versions if this routine is part of the + ** SQLite amalgamation */ +# define safe_isdigit(x) sqlite3Isdigit(x) +# define safe_isalnum(x) sqlite3Isalnum(x) +# define safe_isxdigit(x) sqlite3Isxdigit(x) +#else + /* Use the standard library for separate compilation */ +#include /* amalgamator: keep */ +# define safe_isdigit(x) isdigit((unsigned char)(x)) +# define safe_isalnum(x) isalnum((unsigned char)(x)) +# define safe_isxdigit(x) isxdigit((unsigned char)(x)) +#endif + +/* +** Growing our own isspace() routine this way is twice as fast as +** the library isspace() function. +*/ +static const char geopolyIsSpace[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define safe_isspace(x) (geopolyIsSpace[(unsigned char)x]) +#endif /* JSON NULL - back to original code */ + +/* Compiler and version */ +#ifndef GCC_VERSION +#if defined(__GNUC__) && !defined(SQLITE_DISABLE_INTRINSIC) +# define GCC_VERSION (__GNUC__*1000000+__GNUC_MINOR__*1000+__GNUC_PATCHLEVEL__) +#else +# define GCC_VERSION 0 +#endif +#endif +#ifndef MSVC_VERSION +#if defined(_MSC_VER) && !defined(SQLITE_DISABLE_INTRINSIC) +# define MSVC_VERSION _MSC_VER +#else +# define MSVC_VERSION 0 +#endif +#endif + +/* Datatype for coordinates +*/ +typedef float GeoCoord; + +/* +** Internal representation of a polygon. +** +** The polygon consists of a sequence of vertexes. There is a line +** segment between each pair of vertexes, and one final segment from +** the last vertex back to the first. (This differs from the GeoJSON +** standard in which the final vertex is a repeat of the first.) +** +** The polygon follows the right-hand rule. The area to the right of +** each segment is "outside" and the area to the left is "inside". +** +** The on-disk representation consists of a 4-byte header followed by +** the values. The 4-byte header is: +** +** encoding (1 byte) 0=big-endian, 1=little-endian +** nvertex (3 bytes) Number of vertexes as a big-endian integer +*/ +typedef struct GeoPoly GeoPoly; +struct GeoPoly { + int nVertex; /* Number of vertexes */ + unsigned char hdr[4]; /* Header for on-disk representation */ + GeoCoord a[2]; /* 2*nVertex values. X (longitude) first, then Y */ +}; + +/* +** State of a parse of a GeoJSON input. +*/ +typedef struct GeoParse GeoParse; +struct GeoParse { + const unsigned char *z; /* Unparsed input */ + int nVertex; /* Number of vertexes in a[] */ + int nAlloc; /* Space allocated to a[] */ + int nErr; /* Number of errors encountered */ + GeoCoord *a; /* Array of vertexes. From sqlite3_malloc64() */ +}; + +/* Do a 4-byte byte swap */ +static void geopolySwab32(unsigned char *a){ + unsigned char t = a[0]; + a[0] = a[3]; + a[3] = t; + t = a[1]; + a[1] = a[2]; + a[2] = t; +} + +/* Skip whitespace. Return the next non-whitespace character. */ +static char geopolySkipSpace(GeoParse *p){ + while( p->z[0] && safe_isspace(p->z[0]) ) p->z++; + return p->z[0]; +} + +/* Parse out a number. Write the value into *pVal if pVal!=0. +** return non-zero on success and zero if the next token is not a number. +*/ +static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ + const unsigned char *z = p->z; + char c = geopolySkipSpace(p); + int j; + int seenDP = 0; + int seenE = 0; + assert( '-' < '0' ); + if( c<='0' ){ + j = c=='-'; + if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0; + } + j = 1; + for(;; j++){ + c = z[j]; + if( c>='0' && c<='9' ) continue; + if( c=='.' ){ + if( z[j-1]=='-' ) return 0; + if( seenDP ) return 0; + seenDP = 1; + continue; + } + if( c=='e' || c=='E' ){ + if( z[j-1]<'0' ) return 0; + if( seenE ) return -1; + seenDP = seenE = 1; + c = z[j+1]; + if( c=='+' || c=='-' ){ + j++; + c = z[j+1]; + } + if( c<'0' || c>'9' ) return 0; + continue; + } + break; + } + if( z[j-1]<'0' ) return 0; + if( pVal ) *pVal = atof((const char*)p->z); + p->z += j; + return 1; +} + +/* +** If the input is a well-formed JSON array of coordinates, where each +** coordinate is itself a two-value array, then convert the JSON into +** a GeoPoly object and return a pointer to that object. +** +** If any error occurs, return NULL. +*/ +static GeoPoly *geopolyParseJson(const unsigned char *z){ + GeoParse s; + memset(&s, 0, sizeof(s)); + s.z = z; + if( geopolySkipSpace(&s)=='[' ){ + s.z++; + while( geopolySkipSpace(&s)=='[' ){ + int ii = 0; + char c; + s.z++; + if( s.nVertex<=s.nAlloc ){ + GeoCoord *aNew; + s.nAlloc = s.nAlloc*2 + 16; + aNew = sqlite3_realloc64(s.a, s.nAlloc*sizeof(GeoCoord)*2 ); + if( aNew==0 ){ + s.nErr++; + break; + } + s.a = aNew; + } + while( geopolyParseNumber(&s, ii<=1 ? &s.a[s.nVertex*2+ii] : 0) ){ + ii++; + if( ii==2 ) s.nVertex++; + c = geopolySkipSpace(&s); + s.z++; + if( c==',' ) continue; + if( c==']' ) break; + s.nErr++; + goto parse_json_err; + } + if( geopolySkipSpace(&s)==',' ){ + s.z++; + continue; + } + break; + } + if( geopolySkipSpace(&s)==']' && s.nVertex>=4 ){ + int nByte; + GeoPoly *pOut; + int x = (s.nVertex-1)*2; + if( s.a[x]==s.a[0] && s.a[x+1]==s.a[1] ) s.nVertex--; + nByte = sizeof(GeoPoly) * (s.nVertex-1)*2*sizeof(GeoCoord); + pOut = sqlite3_malloc64( nByte ); + x = 1; + if( pOut==0 ) goto parse_json_err; + pOut->nVertex = s.nVertex; + memcpy(pOut->a, s.a, s.nVertex*2*sizeof(GeoCoord)); + pOut->hdr[0] = *(unsigned char*)&x; + pOut->hdr[1] = (s.nVertex>>16)&0xff; + pOut->hdr[2] = (s.nVertex>>8)&0xff; + pOut->hdr[3] = s.nVertex&0xff; + sqlite3_free(s.a); + return pOut; + }else{ + s.nErr++; + } + } +parse_json_err: + sqlite3_free(s.a); + return 0; +} + +/* +** Given a function parameter, try to interpret it as a polygon, either +** in the binary format or JSON text. Compute a GeoPoly object and +** 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){ + GeoPoly *p = 0; + int nByte; + if( sqlite3_value_type(pVal)==SQLITE_BLOB + && (nByte = sqlite3_value_bytes(pVal))>=(4+6*sizeof(GeoCoord)) + ){ + const unsigned char *a = sqlite3_value_blob(pVal); + int nVertex; + nVertex = (a[1]<<16) + (a[2]<<8) + a[3]; + if( (a[0]==0 && a[0]==1) + && (nVertex*2*sizeof(GeoCoord) + 4)==nByte + ){ + p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) ); + if( p ){ + int x = 1; + p->nVertex = nVertex; + memcpy(p->hdr, a, nByte); + if( a[0] != *(unsigned char*)&x ){ + int ii; + for(ii=0; iia[ii]); + } + p->hdr[0] ^= 1; + } + } + } + }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 p; +} + +/* +** Implementation of the geopoly_blob(X) function. +** +** If the input is a well-formed Geopoly BLOB or JSON string +** then return the BLOB representation of the polygon. Otherwise +** return NULL. +*/ +static void geopolyBlobFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0]); + if( p ){ + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } +} + +/* +** SQL function: geopoly_json(X) +** +** Interpret X as a polygon and render it as a JSON array +** of coordinates. Or, if X is not a valid polygon, return NULL. +*/ +static void geopolyJsonFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0]); + if( p ){ + sqlite3 *db = sqlite3_context_db_handle(context); + sqlite3_str *x = sqlite3_str_new(db); + int i; + sqlite3_str_append(x, "[", 1); + for(i=0; inVertex; i++){ + sqlite3_str_appendf(x, "[%!g,%!g],", p->a[i*2], p->a[i*2+1]); + } + sqlite3_str_appendf(x, "[%!g,%!g]]", p->a[0], p->a[1]); + sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); + sqlite3_free(p); + } +} + +/* +** SQL function: geopoly_svg(X, ....) +** +** Interpret X as a polygon and render it as a SVG . +** Additional arguments are added as attributes to the . +*/ +static void geopolySvgFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0]); + if( p ){ + sqlite3 *db = sqlite3_context_db_handle(context); + sqlite3_str *x = sqlite3_str_new(db); + int i; + char cSep = '\''; + sqlite3_str_appendf(x, "a[i*2], p->a[i*2+1]); + cSep = ' '; + } + sqlite3_str_appendf(x, " %g,%g'", p->a[0], p->a[1]); + for(i=1; i"); + sqlite3_result_text(context, sqlite3_str_finish(x), -1, sqlite3_free); + sqlite3_free(p); + } +} + +/* +** Implementation of the geopoly_area(X) function. +** +** If the input is a well-formed Geopoly BLOB then return the area +** enclosed by the polygon. If the polygon circulates clockwise instead +** of counterclockwise (as it should) then return the negative of the +** enclosed area. Otherwise return NULL. +*/ +static void geopolyAreaFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0]); + if( p ){ + double rArea = 0.0; + int ii; + for(ii=0; iinVertex-1; ii++){ + rArea += (p->a[ii*2] - p->a[ii*2+2]) /* (x0 - x1) */ + * (p->a[ii*2+1] + p->a[ii*2+3]) /* (y0 + y1) */ + * 0.5; + } + rArea += (p->a[ii*2] - p->a[0]) /* (xN - x0) */ + * (p->a[ii*2+1] + p->a[1]) /* (yN + y0) */ + * 0.5; + sqlite3_result_double(context, rArea); + sqlite3_free(p); + } +} + +/* +** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2). +** Returns: +** +** +2 x0,y0 is on the line segement +** +** +1 x0,y0 is beneath line segment +** +** 0 x0,y0 is not on or beneath the line segment or the line segment +** is vertical and x0,y0 is not on the line segment +** +** The left-most coordinate min(x1,x2) is not considered to be part of +** the line segment for the purposes of this analysis. +*/ +static int pointBeneathLine( + double x0, double y0, + double x1, double y1, + double x2, double y2 +){ + double y; + if( x0==x1 && y0==y1 ) return 2; + if( x1x2 ) return 0; + }else if( x1>x2 ){ + if( x0<=x2 || x0>x1 ) return 0; + }else{ + /* Vertical line segment */ + if( x0!=x1 ) return 0; + if( y0y1 && y0>y2 ) return 0; + return 2; + } + y = y1 + (y2-y1)*(x0-x1)/(x2-x1); + if( y0==y ) return 2; + if( y0nVertex-1; ii++){ + v = pointBeneathLine(x0,y0,p->a[ii*2],p->a[ii*2+1], + p->a[ii*2+2],p->a[ii*2+3]); + if( v==2 ) break; + cnt += v; + } + if( v!=2 ){ + v = pointBeneathLine(x0,y0,p->a[ii*2],p->a[ii*2+1], + p->a[0],p->a[1]); + } + if( v==2 ){ + sqlite3_result_int(context, 1); + }else if( ((v+cnt)&1)==0 ){ + sqlite3_result_int(context, 0); + }else{ + sqlite3_result_int(context, 2); + } + sqlite3_free(p); + } +} + +/* Objects used by the overlap algorihm. */ +typedef struct GeoEvent GeoEvent; +typedef struct GeoSegment GeoSegment; +typedef struct GeoOverlap GeoOverlap; +struct GeoEvent { + double x; /* X coordinate at which event occurs */ + int eType; /* 0 for ADD, 1 for REMOVE */ + GeoSegment *pSeg; /* The segment to be added or removed */ + GeoEvent *pNext; /* Next event in the sorted list */ +}; +struct GeoSegment { + double C, B; /* y = C*x + B */ + double y; /* Current y value */ + float y0; /* Initial y value */ + unsigned char side; /* 1 for p1, 2 for p2 */ + unsigned int idx; /* Which segment within the side */ + GeoSegment *pNext; /* Next segment in a list sorted by y */ +}; +struct GeoOverlap { + GeoEvent *aEvent; /* Array of all events */ + GeoSegment *aSegment; /* Array of all segments */ + int nEvent; /* Number of events */ + int nSegment; /* Number of segments */ +}; + +/* +** Add a single segment and its associated events. +*/ +static void geopolyAddOneSegment( + GeoOverlap *p, + GeoCoord x0, + GeoCoord y0, + GeoCoord x1, + GeoCoord y1, + unsigned char side, + unsigned int idx +){ + GeoSegment *pSeg; + GeoEvent *pEvent; + if( x0==x1 ) return; /* Ignore vertical segments */ + if( x0>x1 ){ + GeoCoord t = x0; + x0 = x1; + x1 = t; + t = y0; + y0 = y1; + y1 = t; + } + pSeg = p->aSegment + p->nSegment; + p->nSegment++; + pSeg->C = (y1-y0)/(x1-x0); + pSeg->B = y1 - x1*pSeg->C; + pSeg->y0 = y0; + pSeg->side = side; + pSeg->idx = idx; + pEvent = p->aEvent + p->nEvent; + p->nEvent++; + pEvent->x = x0; + pEvent->eType = 0; + pEvent->pSeg = pSeg; + pEvent = p->aEvent + p->nEvent; + p->nEvent++; + pEvent->x = x1; + pEvent->eType = 1; + pEvent->pSeg = pSeg; +} + + + +/* +** Insert all segments and events for polygon pPoly. +*/ +static void geopolyAddSegments( + GeoOverlap *p, /* Add segments to this Overlap object */ + GeoPoly *pPoly, /* Take all segments from this polygon */ + unsigned char side /* The side of pPoly */ +){ + unsigned int i; + GeoCoord *x; + for(i=0; inVertex-1; i++){ + x = pPoly->a + (i*2); + geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i); + } + x = pPoly->a + (i*2); + geopolyAddOneSegment(p, x[0], x[1], pPoly->a[0], pPoly->a[1], side, i); +} + +/* +** Merge two lists of sorted events by X coordinate +*/ +static GeoEvent *geopolyEventMerge(GeoEvent *pLeft, GeoEvent *pRight){ + GeoEvent head, *pLast; + head.pNext = 0; + pLast = &head; + while( pRight && pLeft ){ + if( pRight->x <= pLeft->x ){ + pLast->pNext = pRight; + pLast = pRight; + pRight = pRight->pNext; + }else{ + pLast->pNext = pLeft; + pLast = pLeft; + pLeft = pLeft->pNext; + } + } + pLast->pNext = pRight ? pRight : pLeft; + return head.pNext; +} + +/* +** Sort an array of nEvent event objects into a list. +*/ +static GeoEvent *geopolySortEventsByX(GeoEvent *aEvent, int nEvent){ + int mx = 0; + int i, j; + GeoEvent *p; + GeoEvent *a[50]; + for(i=0; ipNext = 0; + for(j=0; j=mx ) mx = j+1; + } + p = 0; + for(i=0; iy - pLeft->y; + if( r==0.0 ) r = pRight->C - pLeft->C; + if( r<0.0 ){ + pLast->pNext = pRight; + pLast = pRight; + pRight = pRight->pNext; + }else{ + pLast->pNext = pLeft; + pLast = pLeft; + pLeft = pLeft->pNext; + } + } + pLast->pNext = pRight ? pRight : pLeft; + return head.pNext; +} + +/* +** Sort a list of GeoSegments in order of increasing Y and in the event of +** a tie, increasing C (slope). +*/ +static GeoSegment *geopolySortSegmentsByYAndC(GeoSegment *pList){ + int mx = 0; + int i; + GeoSegment *p; + GeoSegment *a[50]; + while( pList ){ + p = pList; + pList = pList->pNext; + p->pNext = 0; + for(i=0; i=mx ) mx = i+1; + } + p = 0; + for(i=0; inVertex + p2->nVertex + 2; + GeoOverlap *p; + int nByte; + GeoEvent *pThisEvent; + double rX; + int rc = 0; + int needSort = 0; + GeoSegment *pActive = 0; + GeoSegment *pSeg; + unsigned char aOverlap[4]; + + nByte = sizeof(GeoEvent)*nVertex*2 + + sizeof(GeoSegment)*nVertex + + sizeof(GeoOverlap); + p = sqlite3_malloc( nByte ); + if( p==0 ) return -1; + p->aEvent = (GeoEvent*)&p[1]; + p->aSegment = (GeoSegment*)&p->aEvent[nVertex*2]; + p->nEvent = p->nSegment = 0; + geopolyAddSegments(p, p1, 1); + geopolyAddSegments(p, p2, 2); + pThisEvent = geopolySortEventsByX(p->aEvent, p->nEvent); + rX = pThisEvent->x==0.0 ? -1.0 : 0.0; + memset(aOverlap, 0, sizeof(aOverlap)); + while( pThisEvent ){ + if( pThisEvent->x!=rX ){ + GeoSegment *pPrev = 0; + int iMask = 0; + GEODEBUG(("Distinct X: %g\n", pThisEvent->x)); + rX = pThisEvent->x; + if( needSort ){ + GEODEBUG(("SORT\n")); + pActive = geopolySortSegmentsByYAndC(pActive); + needSort = 0; + } + for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ + if( pPrev ){ + if( pPrev->y!=pSeg->y ){ + GEODEBUG(("MASK: %d\n", iMask)); + aOverlap[iMask] = 1; + } + } + iMask ^= pSeg->side; + pPrev = pSeg; + } + pPrev = 0; + for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ + double y = pSeg->C*rX + pSeg->B; + GEODEBUG(("Segment %d.%d %g->%g\n", pSeg->side, pSeg->idx, pSeg->y, y)); + pSeg->y = y; + if( pPrev ){ + if( pPrev->y>pSeg->y && pPrev->side!=pSeg->side ){ + rc = 1; + GEODEBUG(("Crossing: %d.%d and %d.%d\n", + pPrev->side, pPrev->idx, + pSeg->side, pSeg->idx)); + goto geopolyOverlapDone; + }else if( pPrev->y!=pSeg->y ){ + GEODEBUG(("MASK: %d\n", iMask)); + aOverlap[iMask] = 1; + } + } + iMask ^= pSeg->side; + pPrev = pSeg; + } + } + GEODEBUG(("%s %d.%d C=%g B=%g\n", + pThisEvent->eType ? "RM " : "ADD", + pThisEvent->pSeg->side, pThisEvent->pSeg->idx, + pThisEvent->pSeg->C, + pThisEvent->pSeg->B)); + if( pThisEvent->eType==0 ){ + /* Add a segment */ + pSeg = pThisEvent->pSeg; + pSeg->y = pSeg->y0; + pSeg->pNext = pActive; + pActive = pSeg; + needSort = 1; + }else{ + /* Remove a segment */ + if( pActive==pThisEvent->pSeg ){ + pActive = pActive->pNext; + }else{ + for(pSeg=pActive; pSeg; pSeg=pSeg->pNext){ + if( pSeg->pNext==pThisEvent->pSeg ){ + pSeg->pNext = pSeg->pNext->pNext; + break; + } + } + } + } + pThisEvent = pThisEvent->pNext; + } + if( aOverlap[3]==0 ){ + rc = 0; + }else if( aOverlap[1]!=0 && aOverlap[2]==0 ){ + rc = 3; + }else if( aOverlap[1]==0 && aOverlap[2]!=0 ){ + rc = 2; + }else if( aOverlap[1]==0 && aOverlap[2]==0 ){ + rc = 4; + }else{ + rc = 1; + } + +geopolyOverlapDone: + sqlite3_free(p); + return rc; +} + +/* +** SQL function: geopoly_overlap(P1,P2) +** +** Determine whether or not P1 and P2 overlap. Return value: +** +** 0 The two polygons are disjoint +** 1 They overlap +** 2 P1 is completely contained within P2 +** 3 P2 is completely contained within P1 +** 4 P1 and P2 are the same polygon +** NULL Either P1 or P2 or both are not valid polygons +*/ +static void geopolyOverlapFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p1 = geopolyFuncParam(context, argv[0]); + GeoPoly *p2 = geopolyFuncParam(context, argv[1]); + if( p1 && p2 ){ + int x = geopolyOverlap(p1, p2); + if( x<0 ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_int(context, x); + } + } + sqlite3_free(p1); + sqlite3_free(p2); +} + +/* +** Enable or disable debugging output +*/ +static void geopolyDebugFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ +#ifdef GEOPOLY_ENABLE_DEBUG + geo_debug = sqlite3_value_int(argv[0]); +#endif +} + +static int sqlite3_geopoly_init(sqlite3 *db){ + int rc = SQLITE_OK; + static const struct { + void (*xFunc)(sqlite3_context*,int,sqlite3_value**); + int nArg; + const char *zName; + } aFunc[] = { + { geopolyAreaFunc, 1, "geopoly_area" }, + { geopolyBlobFunc, 1, "geopoly_blob" }, + { geopolyJsonFunc, 1, "geopoly_json" }, + { geopolySvgFunc, -1, "geopoly_svg" }, + { geopolyWithinFunc, 3, "geopoly_within" }, + { geopolyOverlapFunc, 2, "geopoly_overlap" }, + { geopolyDebugFunc, 1, "geopoly_debug" }, + }; + int i; + for(i=0; i Date: Fri, 25 May 2018 20:53:42 +0000 Subject: [PATCH 02/33] Incremental check-in: Progress toward implementing the geopoly vtab. FossilOrigin-Name: 9b7d6f986a19f8fbe26d880dc368870a10df80e06097be34ee3639f78c50be61 --- ext/rtree/geopoly.c | 502 +++++++++++++++++++++++++++++++++++++++++++- manifest | 15 +- manifest.uuid | 2 +- 3 files changed, 508 insertions(+), 11 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 3808871135..f22f762e7c 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -270,7 +270,7 @@ static GeoPoly *geopolyFuncParam(sqlite3_context *pCtx, sqlite3_value *pVal){ const unsigned char *a = sqlite3_value_blob(pVal); int nVertex; nVertex = (a[1]<<16) + (a[2]<<8) + a[3]; - if( (a[0]==0 && a[0]==1) + if( (a[0]==0 || a[0]==1) && (nVertex*2*sizeof(GeoCoord) + 4)==nByte ){ p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) ); @@ -407,6 +407,79 @@ static void geopolyAreaFunc( } } +/* +** Compute a bound-box on a polygon. Return a new GeoPoly object +** that describes the bounding box. Or, if aCoord is not a NULL pointer +** fill it in with the bounding box instead. +*/ +static GeoPoly *geopolyBBox( + sqlite3_context *context, /* For recording the error */ + sqlite3_value *pPoly, /* The polygon */ + double *aCoord /* Results here */ +){ + GeoPoly *p = geopolyFuncParam(context, pPoly); + GeoPoly *pOut; + if( p ){ + int ii; + float mnX, mxX, mnY, mxY; + mnX = mxX = p->a[0]; + mnY = mxY = p->a[1]; + for(ii=1; iinVertex; ii++){ + double r = p->a[ii*2]; + if( rmxX ) mxX = r; + r = p->a[ii*2+1]; + if( rmxY ) mxY = r; + } + if( aCoord==0 ){ + pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6); + if( pOut==0 ){ + sqlite3_free(p); + sqlite3_result_error_nomem(context); + return 0; + } + pOut->nVertex = 4; + pOut->hdr[1] = 0; + pOut->hdr[2] = 0; + pOut->hdr[3] = 4; + pOut->a[0] = mnX; + pOut->a[1] = mnY; + pOut->a[2] = mxX; + pOut->a[3] = mnY; + pOut->a[4] = mxX; + 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; + } + } + return 0; +} + +/* +** Implementation of the geopoly_bbox(X) SQL function. +*/ +static void geopolyBBoxFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyBBox(context, argv[0], 0); + if( p ){ + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } +} + /* ** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2). ** Returns: @@ -828,6 +901,429 @@ static void geopolyDebugFunc( #endif } +/* +** This function is the implementation of both the xConnect and xCreate +** methods of the geopoly virtual table. +** +** argv[0] -> module name +** argv[1] -> database name +** argv[2] -> table name +** argv[...] -> column names... +*/ +static int geopolyInit( + sqlite3 *db, /* Database connection */ + void *pAux, /* One of the RTREE_COORD_* constants */ + int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */ + sqlite3_vtab **ppVtab, /* OUT: New virtual table */ + char **pzErr, /* OUT: Error message, if any */ + int isCreate /* True for xCreate, false for xConnect */ +){ + int rc = SQLITE_OK; + Rtree *pRtree; + int nDb; /* Length of string argv[1] */ + int nName; /* Length of string argv[2] */ + sqlite3_str *pSql; + char *zSql; + int ii; + char cSep; + + sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); + + /* Allocate the sqlite3_vtab structure */ + nDb = (int)strlen(argv[1]); + nName = (int)strlen(argv[2]); + pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); + if( !pRtree ){ + return SQLITE_NOMEM; + } + memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); + pRtree->nBusy = 1; + pRtree->base.pModule = &rtreeModule; + pRtree->zDb = (char *)&pRtree[1]; + pRtree->zName = &pRtree->zDb[nDb+1]; + pRtree->eCoordType = RTREE_COORD_REAL32; + pRtree->nDim = 2; + pRtree->nDim2 = 4; + memcpy(pRtree->zDb, argv[1], nDb); + memcpy(pRtree->zName, argv[2], nName); + + + /* Create/Connect to the underlying relational database schema. If + ** that is successful, call sqlite3_declare_vtab() to configure + ** the r-tree table schema. + */ + pSql = sqlite3_str_new(db); + sqlite3_str_appendf(pSql, "CREATE TABLE x"); + cSep = '('; + for(ii=3; iinAux++; + sqlite3_str_appendf(pSql, "%c%s", cSep, argv[ii]+1); + cSep = ','; + } + sqlite3_str_appendf(pSql, "%c _poly HIDDEN, _bbox HIDDEN);", cSep); + zSql = sqlite3_str_finish(pSql); + if( !zSql ){ + rc = SQLITE_NOMEM; + }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + } + sqlite3_free(zSql); + if( rc ) goto geopolyInit_fail; + pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; + + /* Figure out the node size to use. */ + rc = getNodeSize(db, pRtree, isCreate, pzErr); + if( rc ) goto geopolyInit_fail; + rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate); + if( rc ){ + *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); + goto geopolyInit_fail; + } + + *ppVtab = (sqlite3_vtab *)pRtree; + return SQLITE_OK; + +geopolyInit_fail: + if( rc==SQLITE_OK ) rc = SQLITE_ERROR; + assert( *ppVtab==0 ); + assert( pRtree->nBusy==1 ); + rtreeRelease(pRtree); + return rc; +} + + +/* +** GEOPOLY virtual table module xCreate method. +*/ +static int geopolyCreate( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 1); +} + +/* +** GEOPOLY virtual table module xConnect method. +*/ +static int geopolyConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + return geopolyInit(db, pAux, argc, argv, ppVtab, pzErr, 0); +} + + +/* +** GEOPOLY virtual table module xBestIndex method. There are three +** table scan strategies to choose from (in order from most to +** least desirable): +** +** idxNum idxStr Strategy +** ------------------------------------------------ +** 1 Unused Direct lookup by rowid. +** 2 'Fx' shape query +** 2 '' full-table scan. +** ------------------------------------------------ +** +** If strategy 1 is used, then idxStr is not meaningful. If strategy +** 2 is used, idxStr is either the two-byte string 'Fx' or an empty +** string. +*/ +static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ + Rtree *pRtree = (Rtree*)tab; + int rc = SQLITE_OK; + int ii; + int bMatch = 0; /* True if there exists a MATCH constraint */ + i64 nRow; /* Estimated rows returned by this scan */ + + int iIdx = 0; + char zIdxStr[3]; + memset(zIdxStr, 0, sizeof(zIdxStr)); + + /* Check if there exists a MATCH constraint - even an unusable one. If there + ** is, do not consider the lookup-by-rowid plan as using such a plan would + ** require the VDBE to evaluate the MATCH constraint, which is not currently + ** possible. */ + for(ii=0; iinConstraint; ii++){ + if( pIdxInfo->aConstraint[ii].op==SQLITE_INDEX_CONSTRAINT_MATCH ){ + bMatch = 1; + } + } + + assert( pIdxInfo->idxStr==0 ); + for(ii=0; iinConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){ + struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; + + if( bMatch==0 + && p->usable + && p->iColumn<0 + && p->op==SQLITE_INDEX_CONSTRAINT_EQ + ){ + /* We have an equality constraint on the rowid. Use strategy 1. */ + int jj; + for(jj=0; jjaConstraintUsage[jj].argvIndex = 0; + pIdxInfo->aConstraintUsage[jj].omit = 0; + } + pIdxInfo->idxNum = 1; + pIdxInfo->aConstraintUsage[ii].argvIndex = 1; + pIdxInfo->aConstraintUsage[jj].omit = 1; + + /* This strategy involves a two rowid lookups on an B-Tree structures + ** and then a linear search of an R-Tree node. This should be + ** considered almost as quick as a direct rowid lookup (for which + ** sqlite uses an internal cost of 0.0). It is expected to return + ** a single row. + */ + pIdxInfo->estimatedCost = 30.0; + pIdxInfo->estimatedRows = 1; + pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; + return SQLITE_OK; + } + + /* A MATCH operator against the _shape column */ + if( p->usable + && p->iColumn==pRtree->nAux + && p->op==SQLITE_INDEX_CONSTRAINT_MATCH + ){ + zIdxStr[0] = RTREE_MATCH; + zIdxStr[1] = 'x'; + zIdxStr[2] = 0; + pIdxInfo->aConstraintUsage[ii].argvIndex = 0; + pIdxInfo->aConstraintUsage[ii].omit = 1; + } + } + + pIdxInfo->idxNum = 2; + pIdxInfo->needToFreeIdxStr = 1; + if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){ + return SQLITE_NOMEM; + } + + nRow = pRtree->nRowEst/100 + 5; + pIdxInfo->estimatedCost = (double)6.0 * (double)nRow; + pIdxInfo->estimatedRows = nRow; + + return rc; +} + + +/* +** GEOPOLY virtual table module xColumn method. +*/ +static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ + Rtree *pRtree = (Rtree *)cur->pVtab; + RtreeCursor *pCsr = (RtreeCursor *)cur; + RtreeSearchPoint *p = rtreeSearchPointFirst(pCsr); + int rc = SQLITE_OK; + RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); + + if( rc ) return rc; + if( p==0 ) return SQLITE_OK; + if( i<=pRtree->nAux ){ + if( !pCsr->bAuxValid ){ + if( pCsr->pReadAux==0 ){ + rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0, + &pCsr->pReadAux, 0); + if( rc ) return rc; + } + sqlite3_bind_int64(pCsr->pReadAux, 1, + nodeGetRowid(pRtree, pNode, p->iCell)); + rc = sqlite3_step(pCsr->pReadAux); + if( rc==SQLITE_ROW ){ + pCsr->bAuxValid = 1; + }else{ + sqlite3_reset(pCsr->pReadAux); + if( rc==SQLITE_DONE ) rc = SQLITE_OK; + return rc; + } + } + sqlite3_result_value(ctx, + sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1)); + }else{ + /* Must be the _bbox column */ + } + return SQLITE_OK; +} + + +/* +** The xUpdate method for GEOPOLY module virtual tables. +*/ +static int geopolyUpdate( + sqlite3_vtab *pVtab, + int nData, + sqlite3_value **aData, + sqlite_int64 *pRowid +){ + 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 */ + + if( pRtree->nNodeRef ){ + /* Unable to write to the btree while another cursor is reading from it, + ** since the write might do a rebalance which would disrupt the read + ** cursor. */ + return SQLITE_LOCKED_VTAB; + } + rtreeReference(pRtree); + assert(nData>=1); + +// cell.iRowid = 0; /* Used only to suppress a compiler warning */ +// 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]) + ){ + +#ifndef SQLITE_RTREE_INT_ONLY + if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ + for(ii=0; iicell.aCoord[ii+1].f ){ + rc = rtreeConstraintError(pRtree, ii+1); + goto constraint; + } + } + }else +#endif + { + for(ii=0; iicell.aCoord[ii+1].i ){ + rc = rtreeConstraintError(pRtree, ii+1); + goto constraint; + } + } + } + + /* 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; + } + } + } + bHaveRowid = 1; + } + } + + /* If aData[0] is not an SQL NULL value, it is the rowid of a + ** 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 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 ){ + /* 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); + } + if( rc==SQLITE_OK ){ + int rc2; + pRtree->iReinsertHeight = -1; + rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); + rc2 = nodeRelease(pRtree, pLeaf); + if( rc==SQLITE_OK ){ + rc = rc2; + } + } + if( pRtree->nAux ){ + sqlite3_stmt *pUp = pRtree->pWriteAux; + int jj; + sqlite3_bind_int64(pUp, 1, *pRowid); + for(jj=0; jjnAux; jj++){ + sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]); + } + sqlite3_step(pUp); + rc = sqlite3_reset(pUp); + } + } +constraint: +#endif /* 0 */ + + rtreeRelease(pRtree); + return rc; +} + +static sqlite3_module geopolyModule = { + 2, /* iVersion */ + geopolyCreate, /* xCreate - create a table */ + geopolyConnect, /* xConnect - connect to an existing table */ + geopolyBestIndex, /* xBestIndex - Determine search strategy */ + rtreeDisconnect, /* xDisconnect - Disconnect from a table */ + rtreeDestroy, /* xDestroy - Drop a table */ + rtreeOpen, /* xOpen - open a cursor */ + rtreeClose, /* xClose - close a cursor */ + rtreeFilter, /* xFilter - configure scan constraints */ + rtreeNext, /* xNext - advance a cursor */ + rtreeEof, /* xEof */ + geopolyColumn, /* xColumn - read data */ + rtreeRowid, /* xRowid - read data */ + geopolyUpdate, /* xUpdate - write data */ + rtreeBeginTransaction, /* xBegin - begin transaction */ + rtreeEndTransaction, /* xSync - sync transaction */ + rtreeEndTransaction, /* xCommit - commit transaction */ + rtreeEndTransaction, /* xRollback - rollback transaction */ + 0, /* xFindFunction - function overloading */ + rtreeRename, /* xRename - rename the table */ + rtreeSavepoint, /* xSavepoint */ + 0, /* xRelease */ + 0, /* xRollbackTo */ +}; + static int sqlite3_geopoly_init(sqlite3 *db){ int rc = SQLITE_OK; static const struct { @@ -842,6 +1338,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){ { geopolyWithinFunc, 3, "geopoly_within" }, { geopolyOverlapFunc, 2, "geopoly_overlap" }, { geopolyDebugFunc, 1, "geopoly_debug" }, + { geopolyBBoxFunc, 1, "geopoly_bbox" }, }; int i; for(i=0; i Date: Fri, 25 May 2018 22:39:29 +0000 Subject: [PATCH 03/33] Untested incremental check-in. Basic infrastructure for geopoly in place, except for the MATCH operator. FossilOrigin-Name: b27451910b6880b166d4777e05b14ab2731c3483b5ed0f42c459bbb61c6cd095 --- ext/rtree/geopoly.c | 200 +++++++++++++++++++++----------------------- manifest | 12 +-- manifest.uuid | 2 +- 3 files changed, 102 insertions(+), 112 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index f22f762e7c..427462b560 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -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)); + 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; } - if( p==0 ){ - sqlite3_result_error(pCtx, "not a valid polygon", -1); - } - 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( rmxY ) 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; iinAux++; 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; + 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 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]) + 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; iicell.aCoord[ii+1].f ){ - rc = rtreeConstraintError(pRtree, ii+1); - goto constraint; - } - } - }else -#endif - { - for(ii=0; iicell.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; jjnAux; 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; jjnAux; 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; diff --git a/manifest b/manifest index 042bcab12b..44b42dc0f8 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 52355d0aed..78ee84ffb1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9b7d6f986a19f8fbe26d880dc368870a10df80e06097be34ee3639f78c50be61 \ No newline at end of file +b27451910b6880b166d4777e05b14ab2731c3483b5ed0f42c459bbb61c6cd095 \ No newline at end of file From f403e1af0b74300b93395d4feea8e813d43aa749 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 26 May 2018 12:21:21 +0000 Subject: [PATCH 04/33] Minor correction. FossilOrigin-Name: f20d9a99a477e1d592edb37d741d9d07b015d6772b4c8cf1541ef290d600ca6b --- ext/rtree/geopoly.c | 2 +- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 427462b560..2effb59f87 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -1109,7 +1109,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ && p->iColumn==pRtree->nAux && p->op==SQLITE_INDEX_CONSTRAINT_MATCH ){ - zIdxStr[0] = RTREE_MATCH; + zIdxStr[0] = RTREE_QUERY; zIdxStr[1] = 'x'; zIdxStr[2] = 0; pIdxInfo->aConstraintUsage[ii].argvIndex = 0; diff --git a/manifest b/manifest index 44b42dc0f8..ead659468d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Untested\sincremental\scheck-in.\s\sBasic\sinfrastructure\sfor\sgeopoly\sin\splace,\nexcept\sfor\sthe\sMATCH\soperator. -D 2018-05-25T22:39:29.495 +C Minor\scorrection. +D 2018-05-26T12:21:21.540 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 e1b192440686ee041f94a510298f5d1d44e24f5c777674c1d00be616c6ac9633 +F ext/rtree/geopoly.c 66b0192b554aa344e64aa9e086b8bd8509fa53c82830d698a71f61ac830328cf 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 9b7d6f986a19f8fbe26d880dc368870a10df80e06097be34ee3639f78c50be61 -R ac42d4684558c7281aaaaec9453f13e7 +P b27451910b6880b166d4777e05b14ab2731c3483b5ed0f42c459bbb61c6cd095 +R 0e7fa04f7ff537a47acee804207d1995 U drh -Z b54e65d1af2e3764e8c52f03dab6b0ff +Z e132f6a792319f62f6944c0a7e6e7692 diff --git a/manifest.uuid b/manifest.uuid index 78ee84ffb1..c1b230bdb5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b27451910b6880b166d4777e05b14ab2731c3483b5ed0f42c459bbb61c6cd095 \ No newline at end of file +f20d9a99a477e1d592edb37d741d9d07b015d6772b4c8cf1541ef290d600ca6b \ No newline at end of file From 59155065e07a468e1a74f3a90cc2dc612287a6bf Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 26 May 2018 18:03:48 +0000 Subject: [PATCH 05/33] Experimental change that allows overloaded functions to be analyzed by the xBestIndex method and used by the xFilter method of a virtual table. FossilOrigin-Name: a353b1d7ee6c5989ba1b98a3990c9a4c2ff39ae66572fd1200606e8ef585e5fa --- manifest | 19 ++++++++++------- manifest.uuid | 2 +- src/expr.c | 2 +- src/sqlite.h.in | 1 + src/whereexpr.c | 57 +++++++++++++++++++++++++++++++++++++++++-------- 5 files changed, 62 insertions(+), 19 deletions(-) diff --git a/manifest b/manifest index 1867640d1d..b86958ab3e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Store\sapplication-defined\sfunction\snames\sas\slower-case\sto\savoid\sthe\sneed\nfor\scase\sconversions\sbefore\scalling\sxFindFunction\son\svirtual\stables.\nAvoid\susing\slookaside\sto\sstore\sthe\sdestructors\sfor\sapplication\sdefined\nfunctions,\sas\slookaside\sshould\sbe\sreserved\sfor\stransient\sallocations. -D 2018-05-26T16:00:26.368 +C Experimental\schange\sthat\sallows\soverloaded\sfunctions\sto\sbe\sanalyzed\sby\nthe\sxBestIndex\smethod\sand\sused\sby\sthe\sxFilter\smethod\sof\sa\svirtual\stable. +D 2018-05-26T18:03:48.120 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in bfc40f350586923e0419d2ea4b559c37ec10ee4b6e210e08c14401f8e340f0da @@ -446,7 +446,7 @@ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 F src/dbpage.c 8db4c97f630e7d83f884ea75caf1ffd0988c160e9d530194d93721c80821e0f6 F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91 F src/delete.c 4c8c7604277a2041647f96b78f4b9a47858e9217e4fb333d35e7b5ab32c5b57f -F src/expr.c af4a81a385277510bfc56df87c25d76fc365f98c33bc8797c4a8d84b88e31013 +F src/expr.c 81b3925fb84e226d230eb59d8ef8d680b22a121410934545ba026027d5fe03df F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c d617daf66b5515e2b42c1405b2b4984c30ca50fb705ab164271a9bf66c69e331 F src/func.c e2e3c02621a528a472933fd4733a5da635676f1461be73293f6e9f62f18d4eaa @@ -496,7 +496,7 @@ F src/resolve.c 6415381a0e9d22c0e7cba33ca4a53f81474190862f5d4838190f5eb5b0b47bc9 F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac F src/select.c a35d462ee7a3c0856ad7a9d9c8921fbf3d91d911a8f39ad9d61302eb43b24a71 F src/shell.c.in 51c100206f4b7f86cd9affd80b764825e0edc36ca0190c442e4ca7994611bfe2 -F src/sqlite.h.in db327b5de56909e060da241ff89cc3726eadf98e9eb17386fc831bbce80e0820 +F src/sqlite.h.in 9823d4fee4b4d56d210a2f603c255af3c984c3cacb14a841d35c5bb27707055b F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7 F src/sqliteInt.h d2bd297dba08f2390a91c31ff775e0964e9663df5b2910a569fe6f830b8b2beb @@ -581,7 +581,7 @@ F src/walker.c da987a20d40145c0a03c07d8fefcb2ed363becc7680d0500d9c79915591f5b1f F src/where.c 60ec752fcbe9f9e0271ac60548d159a540a1ee47a4f9fedc85e88a3d0e392dd1 F src/whereInt.h cbae2bcd37cfebdb7812a8b188cdb19634ced2b9346470d1c270556b0c33ea53 F src/wherecode.c 728c7f70731430ccdac807a79969873e1af6968bf1c4745dff3f9dd35f636cc8 -F src/whereexpr.c e90b2e76dcabc81edff56633bf281bc01d93b71e0c81482dc06925ce39f5844a +F src/whereexpr.c a6994e3a616f33e885becc2d6a4377ce5aea92b6e2dff96de3a8dd986ed3113f F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d @@ -1729,7 +1729,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 27b4fa5dd0defc6ddaf5d8cde6a1e1162b70d99bfdc69c1d2290621a6d23ed91 -R d728fa434c4672bbeedeb70c9aae9549 +P 777189ce88799f93f393fd14fd716111c85bcdcb23690fd561f78ea2bd2ce5da +R 287ad6e657f697576be6591ee557b37e +T *branch * vtab-func-constraint +T *sym-vtab-func-constraint * +T -sym-trunk * U drh -Z 593bd01a2c2330ddb0f8d8891bce9a51 +Z 1dcaa168f6b87a9c36f55e4d22ec80f8 diff --git a/manifest.uuid b/manifest.uuid index 2496e83258..bf9a43fb0d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -777189ce88799f93f393fd14fd716111c85bcdcb23690fd561f78ea2bd2ce5da \ No newline at end of file +a353b1d7ee6c5989ba1b98a3990c9a4c2ff39ae66572fd1200606e8ef585e5fa \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 6aff83a256..a45f38f9c7 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3903,7 +3903,7 @@ expr_code_doover: ** "glob(B,A). We want to use the A in "A glob B" to test ** for function overloading. But we use the B term in "glob(B,A)". */ - if( nFarg>=2 && (pExpr->flags & EP_InfixFunc) ){ + if( nFarg>=2 && ExprHasProperty(pExpr, EP_InfixFunc) ){ pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[1].pExpr); }else if( nFarg>0 ){ pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr); diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 64e929a89e..979b974699 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -6323,6 +6323,7 @@ struct sqlite3_index_info { #define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70 #define SQLITE_INDEX_CONSTRAINT_ISNULL 71 #define SQLITE_INDEX_CONSTRAINT_IS 72 +#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150 /* ** CAPI3REF: Register A Virtual Table Implementation diff --git a/src/whereexpr.c b/src/whereexpr.c index 29750080a1..b177a7d995 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -338,6 +338,7 @@ static int isLikeOrGlob( ** If the expression matches none of the patterns above, return 0. */ static int isAuxiliaryVtabOperator( + sqlite3 *db, /* Parsing context */ Expr *pExpr, /* Test this expression */ unsigned char *peOp2, /* OUT: 0 for MATCH, or else an op2 value */ Expr **ppLeft, /* Column expression to left of MATCH/op2 */ @@ -361,16 +362,54 @@ static int isAuxiliaryVtabOperator( if( pList==0 || pList->nExpr!=2 ){ return 0; } + + /* Built-in operators MATCH, GLOB, LIKE, and REGEXP attach to a + ** virtual table on their second argument, which is the same as + ** the left-hand side operand in their in-fix form. + ** + ** vtab_column MATCH expression + ** MATCH(expression,vtab_column) + */ pCol = pList->a[1].pExpr; - if( pCol->op!=TK_COLUMN || !IsVirtual(pCol->pTab) ){ - return 0; + if( pCol->op==TK_COLUMN && IsVirtual(pCol->pTab) ){ + for(i=0; iu.zToken, aOp[i].zOp)==0 ){ + *peOp2 = aOp[i].eOp2; + *ppRight = pList->a[0].pExpr; + *ppLeft = pCol; + return 1; + } + } } - for(i=0; iu.zToken, aOp[i].zOp)==0 ){ - *peOp2 = aOp[i].eOp2; - *ppRight = pList->a[0].pExpr; - *ppLeft = pCol; - return 1; + + /* We can also match against the first column of overloaded + ** functions where xFindFunction returns a value of at least + ** SQLITE_INDEX_CONSTRAINT_FUNCTION. + ** + ** OVERLOADED(vtab_column,expression) + ** + ** Historically, xFindFunction expected to see lower-case function + ** names. But for this use case, xFindFunction is expected to deal + ** with function names in an arbitrary case. + */ + pCol = pList->a[0].pExpr; + if( pCol->op==TK_COLUMN && IsVirtual(pCol->pTab) ){ + sqlite3_vtab *pVtab; + sqlite3_module *pMod; + void (*xNotUsed)(sqlite3_context*,int,sqlite3_value**); + void *pNotUsed; + pVtab = sqlite3GetVTable(db, pCol->pTab)->pVtab; + assert( pVtab!=0 ); + assert( pVtab->pModule!=0 ); + pMod = (sqlite3_module *)pVtab->pModule; + if( pMod->xFindFunction!=0 ){ + i = pMod->xFindFunction(pVtab,2, pExpr->u.zToken, &xNotUsed, &pNotUsed); + if( i>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){ + *peOp2 = i; + *ppRight = pList->a[1].pExpr; + *ppLeft = pCol; + return 1; + } } } }else if( pExpr->op==TK_NE || pExpr->op==TK_ISNOT || pExpr->op==TK_NOTNULL ){ @@ -1230,7 +1269,7 @@ static void exprAnalyze( */ if( pWC->op==TK_AND ){ Expr *pRight = 0, *pLeft = 0; - int res = isAuxiliaryVtabOperator(pExpr, &eOp2, &pLeft, &pRight); + int res = isAuxiliaryVtabOperator(db, pExpr, &eOp2, &pLeft, &pRight); while( res-- > 0 ){ int idxNew; WhereTerm *pNewTerm; From 48e4ef56c3dbbd9748f47cddaee7dd1539d8c50c Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 28 May 2018 13:23:23 +0000 Subject: [PATCH 06/33] Untested incremental check-in. Add the geopoly_xform() function. Complete basic logic for the geopoly virtual table. FossilOrigin-Name: ed06cc32568a3abaa0535b379e0ee3b04ffb7582dcda6405670620d1fbe8996c --- ext/rtree/geopoly.c | 326 ++++++++++++++++++++++++++++++++------------ manifest | 12 +- manifest.uuid | 2 +- 3 files changed, 243 insertions(+), 97 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 2effb59f87..b5b6282163 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -392,6 +392,51 @@ static void geopolySvgFunc( } } +/* +** SQL Function: geopoly_xform(poly, A, B, C, D, E, F) +** +** Transform and/or translate a polygon as follows: +** +** x1 = A*x0 + B*y0 + E +** y1 = C*x0 + D*y0 + F +** +** For a translation: +** +** geopoly_xform(poly, 1, 0, 0, 1, x-offset, y-offset) +** +** Rotate by R around the point (0,0): +** +** geopoly_xform(poly, cos(R), sin(R), sin(R), cos(R), 0, 0) +*/ +static void geopolyXformFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + double A = sqlite3_value_double(argv[1]); + double B = sqlite3_value_double(argv[2]); + double C = sqlite3_value_double(argv[3]); + double D = sqlite3_value_double(argv[4]); + double E = sqlite3_value_double(argv[5]); + double F = sqlite3_value_double(argv[7]); + GeoCoord x1, y1, x0, y0; + int ii; + if( p ){ + for(ii=0; iinVertex; ii++){ + x0 = p->a[ii*2]; + y0 = p->a[ii*2+1]; + x1 = A*x0 + B*y0 + E; + y1 = C*x0 + D*y0 + F; + p->a[ii*2] = x1; + p->a[ii*2+1] = y1; + } + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } +} + /* ** Implementation of the geopoly_area(X) function. ** @@ -941,7 +986,6 @@ static int geopolyInit( sqlite3_str *pSql; char *zSql; int ii; - char cSep; sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); @@ -969,15 +1013,13 @@ static int geopolyInit( ** the r-tree table schema. */ pSql = sqlite3_str_new(db); - sqlite3_str_appendf(pSql, "CREATE TABLE x"); - cSep = '('; + sqlite3_str_appendf(pSql, "CREATE TABLE x(_shape"); pRtree->nAux = 1; /* Add one for _shape */ for(ii=3; iinAux++; - sqlite3_str_appendf(pSql, "%c%s", cSep, argv[ii]+1); - cSep = ','; + sqlite3_str_appendf(pSql, ",%s", argv[ii]+1); } - sqlite3_str_appendf(pSql, "%c _shape, _bbox HIDDEN);", cSep); + sqlite3_str_appendf(pSql, ",_bbox HIDDEN);"); zSql = sqlite3_str_finish(pSql); if( !zSql ){ rc = SQLITE_NOMEM; @@ -1036,98 +1078,165 @@ static int geopolyConnect( } +/* +** GEOPOLY virtual table module xFilter method. +** +** Query plans: +** +** 1 rowid lookup +** 2 search for objects overlapping the same bounding box +** that contains polygon argv[0] +** 3 full table scan +*/ +static int geopolyFilter( + sqlite3_vtab_cursor *pVtabCursor, /* The cursor to initialize */ + int idxNum, /* Query plan */ + const char *idxStr, /* Not Used */ + int argc, sqlite3_value **argv /* Parameters to the query plan */ +){ + Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; + RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; + RtreeNode *pRoot = 0; + int rc = SQLITE_OK; + int iCell = 0; + sqlite3_stmt *pStmt; + + rtreeReference(pRtree); + + /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ + freeCursorConstraints(pCsr); + sqlite3_free(pCsr->aPoint); + pStmt = pCsr->pReadAux; + memset(pCsr, 0, sizeof(RtreeCursor)); + pCsr->base.pVtab = (sqlite3_vtab*)pRtree; + pCsr->pReadAux = pStmt; + + pCsr->iStrategy = idxNum; + if( idxNum==1 ){ + /* Special case - lookup by rowid. */ + RtreeNode *pLeaf; /* Leaf on which the required cell resides */ + RtreeSearchPoint *p; /* Search point for the leaf */ + i64 iRowid = sqlite3_value_int64(argv[0]); + i64 iNode = 0; + rc = findLeafNode(pRtree, iRowid, &pLeaf, &iNode); + if( rc==SQLITE_OK && pLeaf!=0 ){ + p = rtreeSearchPointNew(pCsr, RTREE_ZERO, 0); + assert( p!=0 ); /* Always returns pCsr->sPoint */ + pCsr->aNode[0] = pLeaf; + p->id = iNode; + p->eWithin = PARTLY_WITHIN; + rc = nodeRowidIndex(pRtree, pLeaf, iRowid, &iCell); + p->iCell = (u8)iCell; + RTREE_QUEUE_TRACE(pCsr, "PUSH-F1:"); + }else{ + pCsr->atEOF = 1; + } + }else{ + /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array + ** with the configured constraints. + */ + rc = nodeAcquire(pRtree, 1, 0, &pRoot); + if( rc==SQLITE_OK && idxNum==2 ){ + RtreeCoord bbox[4]; + RtreeConstraint *p; + assert( argc==1 ); + geopolyBBox(0, argv[0], bbox, &rc); + if( rc ){ + return rc; + } + pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4); + pCsr->nConstraint = 4; + if( p==0 ){ + rc = SQLITE_NOMEM; + }else{ + memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc); + memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); + p->op = 'B'; + p->iCoord = 'a'; + p->u.rValue = bbox[0].f; + p++; + p->op = 'D'; + p->iCoord = 'b'; + p->u.rValue = bbox[1].f; + p++; + p->op = 'B'; + p->iCoord = 'c'; + p->u.rValue = bbox[2].f; + p++; + p->op = 'D'; + p->iCoord = 'd'; + p->u.rValue = bbox[3].f; + } + } + if( rc==SQLITE_OK ){ + RtreeSearchPoint *pNew; + pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1)); + if( pNew==0 ) return SQLITE_NOMEM; + pNew->id = 1; + pNew->iCell = 0; + pNew->eWithin = PARTLY_WITHIN; + assert( pCsr->bPoint==1 ); + pCsr->aNode[0] = pRoot; + pRoot = 0; + RTREE_QUEUE_TRACE(pCsr, "PUSH-Fm:"); + rc = rtreeStepToLeaf(pCsr); + } + } + + nodeRelease(pRtree, pRoot); + rtreeRelease(pRtree); + return rc; +} + /* -** GEOPOLY virtual table module xBestIndex method. There are three +** Rtree virtual table module xBestIndex method. There are three ** table scan strategies to choose from (in order from most to ** least desirable): ** ** idxNum idxStr Strategy ** ------------------------------------------------ ** 1 Unused Direct lookup by rowid. -** 2 'Fx' shape query -** 2 '' full-table scan. +** 2 Unused R-tree query +** 3 Unused full-table scan. ** ------------------------------------------------ -** -** If strategy 1 is used, then idxStr is not meaningful. If strategy -** 2 is used, idxStr is either the two-byte string 'Fx' or an empty -** string. */ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ - Rtree *pRtree = (Rtree*)tab; - int rc = SQLITE_OK; int ii; - int bMatch = 0; /* True if there exists a MATCH constraint */ - i64 nRow; /* Estimated rows returned by this scan */ + int iRowidTerm = -1; + int iFuncTerm = -1; - int iIdx = 0; - char zIdxStr[3]; - memset(zIdxStr, 0, sizeof(zIdxStr)); - - /* Check if there exists a MATCH constraint - even an unusable one. If there - ** is, do not consider the lookup-by-rowid plan as using such a plan would - ** require the VDBE to evaluate the MATCH constraint, which is not currently - ** possible. */ for(ii=0; iinConstraint; ii++){ - if( pIdxInfo->aConstraint[ii].op==SQLITE_INDEX_CONSTRAINT_MATCH ){ - bMatch = 1; - } - } - - assert( pIdxInfo->idxStr==0 ); - for(ii=0; iinConstraint && iIdx<(int)(sizeof(zIdxStr)-1); ii++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; - - if( bMatch==0 - && p->usable - && p->iColumn<0 - && p->op==SQLITE_INDEX_CONSTRAINT_EQ - ){ - /* We have an equality constraint on the rowid. Use strategy 1. */ - int jj; - for(jj=0; jjaConstraintUsage[jj].argvIndex = 0; - pIdxInfo->aConstraintUsage[jj].omit = 0; - } - pIdxInfo->idxNum = 1; - pIdxInfo->aConstraintUsage[ii].argvIndex = 1; - pIdxInfo->aConstraintUsage[jj].omit = 1; - - /* This strategy involves a two rowid lookups on an B-Tree structures - ** and then a linear search of an R-Tree node. This should be - ** considered almost as quick as a direct rowid lookup (for which - ** sqlite uses an internal cost of 0.0). It is expected to return - ** a single row. - */ - pIdxInfo->estimatedCost = 30.0; - pIdxInfo->estimatedRows = 1; - pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; - return SQLITE_OK; + if( !p->usable ) continue; + if( p->iColumn<0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ + iRowidTerm = ii; + break; } - - /* A MATCH operator against the _shape column */ - if( p->usable - && p->iColumn==pRtree->nAux - && p->op==SQLITE_INDEX_CONSTRAINT_MATCH - ){ - zIdxStr[0] = RTREE_QUERY; - zIdxStr[1] = 'x'; - zIdxStr[2] = 0; - pIdxInfo->aConstraintUsage[ii].argvIndex = 0; - pIdxInfo->aConstraintUsage[ii].omit = 1; + if( p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION ){ + iFuncTerm = ii; } } - pIdxInfo->idxNum = 2; - pIdxInfo->needToFreeIdxStr = 1; - if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){ - return SQLITE_NOMEM; + if( iRowidTerm>=0 ){ + pIdxInfo->idxNum = 1; + pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1; + pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1; + pIdxInfo->estimatedCost = 30.0; + pIdxInfo->estimatedRows = 1; + pIdxInfo->idxFlags = SQLITE_INDEX_SCAN_UNIQUE; + return SQLITE_OK; } - - nRow = pRtree->nRowEst/100 + 5; - pIdxInfo->estimatedCost = (double)6.0 * (double)nRow; - pIdxInfo->estimatedRows = nRow; - - return rc; + if( iFuncTerm>=0 ){ + pIdxInfo->idxNum = 2; + pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1; + pIdxInfo->estimatedCost = 300.0; + pIdxInfo->estimatedRows = 10; + return SQLITE_OK; + } + pIdxInfo->idxNum = 3; + pIdxInfo->estimatedCost = 3000000.0; + pIdxInfo->estimatedRows = 100000; + return SQLITE_OK; } @@ -1172,6 +1281,24 @@ static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ /* ** The xUpdate method for GEOPOLY module virtual tables. +** +** For DELETE: +** +** argv[0] = the rowid to be deleted +** +** For INSERT: +** +** argv[0] = SQL NULL +** argv[1] = rowid to insert, or an SQL NULL to select automatically +** argv[2] = _shape column +** argv[3] = first application-defined column.... +** +** For UPDATE: +** +** argv[0] = rowid to modify. Never NULL +** argv[1] = rowid after the change. Never NULL +** argv[2] = new value for _shape +** argv[3] = new value for first application-defined column.... */ static int geopolyUpdate( sqlite3_vtab *pVtab, @@ -1182,7 +1309,6 @@ static int geopolyUpdate( Rtree *pRtree = (Rtree *)pVtab; int rc = SQLITE_OK; 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 */ @@ -1198,7 +1324,6 @@ static int geopolyUpdate( rtreeReference(pRtree); assert(nData>=1); - iShapeCol = pRtree->nAux; rc = SQLITE_ERROR; oldRowidValid = sqlite3_value_type(aData[0])!=SQLITE_NULL;; oldRowid = oldRowidValid ? sqlite3_value_int64(aData[0]) : 0; @@ -1206,12 +1331,12 @@ static int geopolyUpdate( 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 */ + if( nData>1 /* not a DELETE */ + && (!oldRowidValid /* INSERT */ + || !sqlite3_value_nochange(aData[2]) /* UPDATE _shape */ + || oldRowid!=newRowid) /* Rowid change */ ){ - geopolyBBox(0, aData[iShapeCol+2], cell.aCoord, &rc); + geopolyBBox(0, aData[2], cell.aCoord, &rc); if( rc ){ if( rc==SQLITE_ERROR ){ pVtab->zErrMsg = @@ -1223,7 +1348,7 @@ static int geopolyUpdate( /* If a rowid value was supplied, check if it is already present in ** the table. If so, the constraint has failed. */ - if( oldRowidValid && oldRowid!=newRowid ){ + if( newRowidValid ){ int steprc; sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); steprc = sqlite3_step(pRtree->pReadRowid); @@ -1269,7 +1394,7 @@ static int geopolyUpdate( } /* Change the data */ - if( rc==SQLITE_OK && pRtree->nAux>0 ){ + if( rc==SQLITE_OK ){ sqlite3_stmt *pUp = pRtree->pWriteAux; int jj; int nChange = 0; @@ -1288,6 +1413,26 @@ static int geopolyUpdate( return rc; } +/* +** Report that geopoly_overlap() is an overloaded function suitable +** for use in xBestIndex. +*/ +static int geopolyFindFunction( + sqlite3_vtab *pVtab, + int nArg, + const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg +){ + if( sqlite3_stricmp(zName, "geopoly_overlap")==0 ){ + *pxFunc = geopolyOverlapFunc; + *ppArg = 0; + return SQLITE_INDEX_CONSTRAINT_FUNCTION; + } + return 0; +} + + static sqlite3_module geopolyModule = { 2, /* iVersion */ geopolyCreate, /* xCreate - create a table */ @@ -1297,7 +1442,7 @@ static sqlite3_module geopolyModule = { rtreeDestroy, /* xDestroy - Drop a table */ rtreeOpen, /* xOpen - open a cursor */ rtreeClose, /* xClose - close a cursor */ - rtreeFilter, /* xFilter - configure scan constraints */ + geopolyFilter, /* xFilter - configure scan constraints */ rtreeNext, /* xNext - advance a cursor */ rtreeEof, /* xEof */ geopolyColumn, /* xColumn - read data */ @@ -1307,7 +1452,7 @@ static sqlite3_module geopolyModule = { rtreeEndTransaction, /* xSync - sync transaction */ rtreeEndTransaction, /* xCommit - commit transaction */ rtreeEndTransaction, /* xRollback - rollback transaction */ - 0, /* xFindFunction - function overloading */ + geopolyFindFunction, /* xFindFunction - function overloading */ rtreeRename, /* xRename - rename the table */ rtreeSavepoint, /* xSavepoint */ 0, /* xRelease */ @@ -1329,6 +1474,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){ { geopolyOverlapFunc, 2, "geopoly_overlap" }, { geopolyDebugFunc, 1, "geopoly_debug" }, { geopolyBBoxFunc, 1, "geopoly_bbox" }, + { geopolyXformFunc, 7, "geopoly_xform" }, }; int i; for(i=0; i Date: Mon, 28 May 2018 23:59:03 +0000 Subject: [PATCH 07/33] The geopoly virtual table seems to be working. But only thinly tested so far. FossilOrigin-Name: 4288f1ad5966701eac4cfe3061e8ce98e34e0d6c112307668729642a06458d5f --- ext/rtree/geopoly.c | 39 +++-- ext/rtree/rtree.c | 4 +- ext/rtree/visual01.txt | 389 +++++++++++++++++++++++++++++++++++++++++ manifest | 15 +- manifest.uuid | 2 +- 5 files changed, 421 insertions(+), 28 deletions(-) create mode 100644 ext/rtree/visual01.txt diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index b5b6282163..9e8de3cfee 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -406,7 +406,7 @@ static void geopolySvgFunc( ** ** Rotate by R around the point (0,0): ** -** geopoly_xform(poly, cos(R), sin(R), sin(R), cos(R), 0, 0) +** geopoly_xform(poly, cos(R), sin(R), -sin(R), cos(R), 0, 0) */ static void geopolyXformFunc( sqlite3_context *context, @@ -419,7 +419,7 @@ static void geopolyXformFunc( double C = sqlite3_value_double(argv[3]); double D = sqlite3_value_double(argv[4]); double E = sqlite3_value_double(argv[5]); - double F = sqlite3_value_double(argv[7]); + double F = sqlite3_value_double(argv[6]); GeoCoord x1, y1, x0, y0; int ii; if( p ){ @@ -1017,7 +1017,7 @@ static int geopolyInit( pRtree->nAux = 1; /* Add one for _shape */ for(ii=3; iinAux++; - sqlite3_str_appendf(pSql, ",%s", argv[ii]+1); + sqlite3_str_appendf(pSql, ",%s", argv[ii]); } sqlite3_str_appendf(pSql, ",_bbox HIDDEN);"); zSql = sqlite3_str_finish(pSql); @@ -1149,23 +1149,23 @@ static int geopolyFilter( if( p==0 ){ rc = SQLITE_NOMEM; }else{ - memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*argc); + memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*4); memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1)); p->op = 'B'; - p->iCoord = 'a'; - p->u.rValue = bbox[0].f; - p++; - p->op = 'D'; - p->iCoord = '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 = 'c'; - p->u.rValue = bbox[2].f; + p->iCoord = 2; + p->u.rValue = bbox[3].f; p++; p->op = 'D'; - p->iCoord = 'd'; - p->u.rValue = bbox[3].f; + p->iCoord = 3; + p->u.rValue = bbox[2].f; } } if( rc==SQLITE_OK ){ @@ -1228,7 +1228,8 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ } if( iFuncTerm>=0 ){ pIdxInfo->idxNum = 2; - pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1; + pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1; + pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0; pIdxInfo->estimatedCost = 300.0; pIdxInfo->estimatedRows = 10; return SQLITE_OK; @@ -1270,8 +1271,7 @@ static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ return rc; } } - sqlite3_result_value(ctx, - sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1)); + sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pReadAux, i+2)); }else{ /* Must be the _bbox column */ } @@ -1367,7 +1367,7 @@ static int geopolyUpdate( ** record to delete from the r-tree table. The following block does ** just that. */ - if( rc==SQLITE_OK && (nData==1 || coordChange) ){ + if( rc==SQLITE_OK && (nData==1 || (coordChange && oldRowidValid)) ){ rc = rtreeDeleteRowid(pRtree, oldRowid); } @@ -1378,6 +1378,9 @@ static int geopolyUpdate( if( rc==SQLITE_OK && nData>1 && coordChange ){ /* Insert the new record into the r-tree */ RtreeNode *pLeaf = 0; + if( !newRowidValid ){ + rc = rtreeNewRowid(pRtree, &cell.iRowid); + } *pRowid = cell.iRowid; if( rc==SQLITE_OK ){ rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); @@ -1398,7 +1401,7 @@ static int geopolyUpdate( sqlite3_stmt *pUp = pRtree->pWriteAux; int jj; int nChange = 0; - sqlite3_bind_int64(pUp, 1, newRowid); + sqlite3_bind_int64(pUp, 1, cell.iRowid); for(jj=0; jjnAux; jj++){ if( !sqlite3_value_nochange(aData[jj+2]) ) nChange++; sqlite3_bind_value(pUp, jj+2, aData[jj+2]); diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index d817823f96..091c0bc6b4 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -2893,7 +2893,7 @@ static int reinsertNodeContent(Rtree *pRtree, RtreeNode *pNode){ /* ** Select a currently unused rowid for a new r-tree record. */ -static int newRowid(Rtree *pRtree, i64 *piRowid){ +static int rtreeNewRowid(Rtree *pRtree, i64 *piRowid){ int rc; sqlite3_bind_null(pRtree->pWriteRowid, 1); sqlite3_bind_null(pRtree->pWriteRowid, 2); @@ -3180,7 +3180,7 @@ static int rtreeUpdate( /* Figure out the rowid of the new row. */ if( bHaveRowid==0 ){ - rc = newRowid(pRtree, &cell.iRowid); + rc = rtreeNewRowid(pRtree, &cell.iRowid); } *pRowid = cell.iRowid; diff --git a/ext/rtree/visual01.txt b/ext/rtree/visual01.txt new file mode 100644 index 0000000000..bb3e4af5b5 --- /dev/null +++ b/ext/rtree/visual01.txt @@ -0,0 +1,389 @@ +#!sqlite3 +# +# This is a visual test case for the geopoly virtual table. +# +# Run this script in the sqlite3 CLI, and redirect output into an +# HTML file. This display the HTML in a webbrowser. +# + +/* Test data. +** Lots of shapes to be displayed over a 1000x800 canvas. +*/ +CREATE TEMP TABLE basis(name TEXT, jshape TEXT); +INSERT INTO basis(name,jshape) VALUES + ('box-20','[[0,0],[20,0],[20,20],[0,20],[0,0]]'), + ('house-70','[[0,0],[50,0],[50,50],[25,70],[0,50],[0,0]]'), + ('line-40','[[0,0],[40,0],[40,5],[0,5],[0,0]]'), + ('line-80','[[0,0],[80,0],[80,7],[0,7],[0,0]]'), + ('arrow-50','[[0,0],[25,25],[0,50],[15,25],[0,0]]'), + ('triangle-30','[[0,0],[30,0],[15,30],[0,0]]'), + ('angle-30','[[0,0],[30,0],[30,30],[26,30],[26,4],[0,4],[0,0]]'), + ('star-10','[[1,0],[5,2],[9,0],[7,4],[10,8],[7,7],[5,10],[3,7],[0,8],[3,4],[1,0]]'); +CREATE TEMP TABLE xform(A,B,C,D,clr); +INSERT INTO xform(A,B,clr) VALUES + (1,0,'black'), + (0.707,0.707,'blue'), + (0.5,0.866,'red'), + (-0.866,0.5,'green'); +CREATE TEMP TABLE xyoff(id1,id2,xoff,yoff,PRIMARY KEY(id1,id2,xoff,yoff)) + WITHOUT ROWID; +INSERT INTO xyoff VALUES(1,1,811,659); +INSERT INTO xyoff VALUES(1,1,235,550); +INSERT INTO xyoff VALUES(1,1,481,620); +INSERT INTO xyoff VALUES(1,1,106,494); +INSERT INTO xyoff VALUES(1,1,487,106); +INSERT INTO xyoff VALUES(1,1,817,595); +INSERT INTO xyoff VALUES(1,1,240,504); +INSERT INTO xyoff VALUES(1,1,806,457); +INSERT INTO xyoff VALUES(1,1,608,107); +INSERT INTO xyoff VALUES(1,1,768,662); +INSERT INTO xyoff VALUES(1,2,808,528); +INSERT INTO xyoff VALUES(1,2,768,528); +INSERT INTO xyoff VALUES(1,2,771,171); +INSERT INTO xyoff VALUES(1,2,275,671); +INSERT INTO xyoff VALUES(1,2,326,336); +INSERT INTO xyoff VALUES(1,2,690,688); +INSERT INTO xyoff VALUES(1,2,597,239); +INSERT INTO xyoff VALUES(1,2,317,528); +INSERT INTO xyoff VALUES(1,2,366,223); +INSERT INTO xyoff VALUES(1,2,621,154); +INSERT INTO xyoff VALUES(1,3,829,469); +INSERT INTO xyoff VALUES(1,3,794,322); +INSERT INTO xyoff VALUES(1,3,358,387); +INSERT INTO xyoff VALUES(1,3,184,444); +INSERT INTO xyoff VALUES(1,3,729,500); +INSERT INTO xyoff VALUES(1,3,333,523); +INSERT INTO xyoff VALUES(1,3,117,595); +INSERT INTO xyoff VALUES(1,3,496,201); +INSERT INTO xyoff VALUES(1,3,818,601); +INSERT INTO xyoff VALUES(1,3,541,343); +INSERT INTO xyoff VALUES(1,4,603,248); +INSERT INTO xyoff VALUES(1,4,761,649); +INSERT INTO xyoff VALUES(1,4,611,181); +INSERT INTO xyoff VALUES(1,4,607,233); +INSERT INTO xyoff VALUES(1,4,860,206); +INSERT INTO xyoff VALUES(1,4,310,231); +INSERT INTO xyoff VALUES(1,4,727,539); +INSERT INTO xyoff VALUES(1,4,660,661); +INSERT INTO xyoff VALUES(1,4,403,133); +INSERT INTO xyoff VALUES(1,4,619,331); +INSERT INTO xyoff VALUES(2,1,712,578); +INSERT INTO xyoff VALUES(2,1,567,313); +INSERT INTO xyoff VALUES(2,1,231,423); +INSERT INTO xyoff VALUES(2,1,490,175); +INSERT INTO xyoff VALUES(2,1,898,353); +INSERT INTO xyoff VALUES(2,1,589,483); +INSERT INTO xyoff VALUES(2,1,188,462); +INSERT INTO xyoff VALUES(2,1,720,106); +INSERT INTO xyoff VALUES(2,1,793,380); +INSERT INTO xyoff VALUES(2,1,154,396); +INSERT INTO xyoff VALUES(2,2,324,218); +INSERT INTO xyoff VALUES(2,2,120,327); +INSERT INTO xyoff VALUES(2,2,655,133); +INSERT INTO xyoff VALUES(2,2,516,603); +INSERT INTO xyoff VALUES(2,2,529,572); +INSERT INTO xyoff VALUES(2,2,481,212); +INSERT INTO xyoff VALUES(2,2,802,107); +INSERT INTO xyoff VALUES(2,2,234,509); +INSERT INTO xyoff VALUES(2,2,501,269); +INSERT INTO xyoff VALUES(2,2,349,553); +INSERT INTO xyoff VALUES(2,3,495,685); +INSERT INTO xyoff VALUES(2,3,897,372); +INSERT INTO xyoff VALUES(2,3,350,681); +INSERT INTO xyoff VALUES(2,3,832,257); +INSERT INTO xyoff VALUES(2,3,778,149); +INSERT INTO xyoff VALUES(2,3,683,426); +INSERT INTO xyoff VALUES(2,3,693,217); +INSERT INTO xyoff VALUES(2,3,746,317); +INSERT INTO xyoff VALUES(2,3,805,369); +INSERT INTO xyoff VALUES(2,3,336,585); +INSERT INTO xyoff VALUES(2,4,890,255); +INSERT INTO xyoff VALUES(2,4,556,565); +INSERT INTO xyoff VALUES(2,4,865,555); +INSERT INTO xyoff VALUES(2,4,230,293); +INSERT INTO xyoff VALUES(2,4,247,251); +INSERT INTO xyoff VALUES(2,4,730,563); +INSERT INTO xyoff VALUES(2,4,318,282); +INSERT INTO xyoff VALUES(2,4,220,431); +INSERT INTO xyoff VALUES(2,4,828,336); +INSERT INTO xyoff VALUES(2,4,278,525); +INSERT INTO xyoff VALUES(3,1,324,656); +INSERT INTO xyoff VALUES(3,1,625,362); +INSERT INTO xyoff VALUES(3,1,155,570); +INSERT INTO xyoff VALUES(3,1,267,433); +INSERT INTO xyoff VALUES(3,1,599,121); +INSERT INTO xyoff VALUES(3,1,873,498); +INSERT INTO xyoff VALUES(3,1,789,520); +INSERT INTO xyoff VALUES(3,1,656,378); +INSERT INTO xyoff VALUES(3,1,831,601); +INSERT INTO xyoff VALUES(3,1,256,471); +INSERT INTO xyoff VALUES(3,2,332,258); +INSERT INTO xyoff VALUES(3,2,305,463); +INSERT INTO xyoff VALUES(3,2,796,341); +INSERT INTO xyoff VALUES(3,2,830,229); +INSERT INTO xyoff VALUES(3,2,413,271); +INSERT INTO xyoff VALUES(3,2,269,140); +INSERT INTO xyoff VALUES(3,2,628,441); +INSERT INTO xyoff VALUES(3,2,747,643); +INSERT INTO xyoff VALUES(3,2,584,435); +INSERT INTO xyoff VALUES(3,2,784,314); +INSERT INTO xyoff VALUES(3,3,722,233); +INSERT INTO xyoff VALUES(3,3,815,421); +INSERT INTO xyoff VALUES(3,3,401,267); +INSERT INTO xyoff VALUES(3,3,451,650); +INSERT INTO xyoff VALUES(3,3,329,485); +INSERT INTO xyoff VALUES(3,3,878,370); +INSERT INTO xyoff VALUES(3,3,162,616); +INSERT INTO xyoff VALUES(3,3,844,183); +INSERT INTO xyoff VALUES(3,3,161,216); +INSERT INTO xyoff VALUES(3,3,176,676); +INSERT INTO xyoff VALUES(3,4,780,128); +INSERT INTO xyoff VALUES(3,4,566,121); +INSERT INTO xyoff VALUES(3,4,646,120); +INSERT INTO xyoff VALUES(3,4,223,557); +INSERT INTO xyoff VALUES(3,4,251,117); +INSERT INTO xyoff VALUES(3,4,139,209); +INSERT INTO xyoff VALUES(3,4,813,597); +INSERT INTO xyoff VALUES(3,4,454,538); +INSERT INTO xyoff VALUES(3,4,616,198); +INSERT INTO xyoff VALUES(3,4,210,159); +INSERT INTO xyoff VALUES(4,1,208,415); +INSERT INTO xyoff VALUES(4,1,326,665); +INSERT INTO xyoff VALUES(4,1,612,133); +INSERT INTO xyoff VALUES(4,1,537,513); +INSERT INTO xyoff VALUES(4,1,638,438); +INSERT INTO xyoff VALUES(4,1,808,269); +INSERT INTO xyoff VALUES(4,1,552,121); +INSERT INTO xyoff VALUES(4,1,100,189); +INSERT INTO xyoff VALUES(4,1,643,664); +INSERT INTO xyoff VALUES(4,1,726,378); +INSERT INTO xyoff VALUES(4,2,478,409); +INSERT INTO xyoff VALUES(4,2,497,507); +INSERT INTO xyoff VALUES(4,2,233,148); +INSERT INTO xyoff VALUES(4,2,587,237); +INSERT INTO xyoff VALUES(4,2,604,166); +INSERT INTO xyoff VALUES(4,2,165,455); +INSERT INTO xyoff VALUES(4,2,320,258); +INSERT INTO xyoff VALUES(4,2,353,496); +INSERT INTO xyoff VALUES(4,2,347,495); +INSERT INTO xyoff VALUES(4,2,166,622); +INSERT INTO xyoff VALUES(4,3,461,332); +INSERT INTO xyoff VALUES(4,3,685,278); +INSERT INTO xyoff VALUES(4,3,427,594); +INSERT INTO xyoff VALUES(4,3,467,346); +INSERT INTO xyoff VALUES(4,3,125,548); +INSERT INTO xyoff VALUES(4,3,597,680); +INSERT INTO xyoff VALUES(4,3,820,445); +INSERT INTO xyoff VALUES(4,3,144,330); +INSERT INTO xyoff VALUES(4,3,557,434); +INSERT INTO xyoff VALUES(4,3,254,315); +INSERT INTO xyoff VALUES(4,4,157,339); +INSERT INTO xyoff VALUES(4,4,249,220); +INSERT INTO xyoff VALUES(4,4,391,323); +INSERT INTO xyoff VALUES(4,4,589,429); +INSERT INTO xyoff VALUES(4,4,859,592); +INSERT INTO xyoff VALUES(4,4,337,680); +INSERT INTO xyoff VALUES(4,4,410,288); +INSERT INTO xyoff VALUES(4,4,636,596); +INSERT INTO xyoff VALUES(4,4,734,433); +INSERT INTO xyoff VALUES(4,4,559,549); +INSERT INTO xyoff VALUES(5,1,549,607); +INSERT INTO xyoff VALUES(5,1,584,498); +INSERT INTO xyoff VALUES(5,1,699,116); +INSERT INTO xyoff VALUES(5,1,525,524); +INSERT INTO xyoff VALUES(5,1,304,667); +INSERT INTO xyoff VALUES(5,1,302,232); +INSERT INTO xyoff VALUES(5,1,403,149); +INSERT INTO xyoff VALUES(5,1,824,403); +INSERT INTO xyoff VALUES(5,1,697,203); +INSERT INTO xyoff VALUES(5,1,293,689); +INSERT INTO xyoff VALUES(5,2,199,275); +INSERT INTO xyoff VALUES(5,2,395,393); +INSERT INTO xyoff VALUES(5,2,657,642); +INSERT INTO xyoff VALUES(5,2,200,655); +INSERT INTO xyoff VALUES(5,2,882,234); +INSERT INTO xyoff VALUES(5,2,483,565); +INSERT INTO xyoff VALUES(5,2,755,640); +INSERT INTO xyoff VALUES(5,2,810,305); +INSERT INTO xyoff VALUES(5,2,731,655); +INSERT INTO xyoff VALUES(5,2,466,690); +INSERT INTO xyoff VALUES(5,3,563,584); +INSERT INTO xyoff VALUES(5,3,491,117); +INSERT INTO xyoff VALUES(5,3,779,292); +INSERT INTO xyoff VALUES(5,3,375,637); +INSERT INTO xyoff VALUES(5,3,253,553); +INSERT INTO xyoff VALUES(5,3,797,514); +INSERT INTO xyoff VALUES(5,3,229,480); +INSERT INTO xyoff VALUES(5,3,257,194); +INSERT INTO xyoff VALUES(5,3,449,555); +INSERT INTO xyoff VALUES(5,3,849,630); +INSERT INTO xyoff VALUES(5,4,329,286); +INSERT INTO xyoff VALUES(5,4,640,197); +INSERT INTO xyoff VALUES(5,4,104,150); +INSERT INTO xyoff VALUES(5,4,438,272); +INSERT INTO xyoff VALUES(5,4,773,226); +INSERT INTO xyoff VALUES(5,4,441,650); +INSERT INTO xyoff VALUES(5,4,242,340); +INSERT INTO xyoff VALUES(5,4,301,435); +INSERT INTO xyoff VALUES(5,4,171,397); +INSERT INTO xyoff VALUES(5,4,541,619); +INSERT INTO xyoff VALUES(6,1,651,301); +INSERT INTO xyoff VALUES(6,1,637,137); +INSERT INTO xyoff VALUES(6,1,765,643); +INSERT INTO xyoff VALUES(6,1,173,296); +INSERT INTO xyoff VALUES(6,1,263,192); +INSERT INTO xyoff VALUES(6,1,791,302); +INSERT INTO xyoff VALUES(6,1,860,601); +INSERT INTO xyoff VALUES(6,1,780,445); +INSERT INTO xyoff VALUES(6,1,462,214); +INSERT INTO xyoff VALUES(6,1,802,207); +INSERT INTO xyoff VALUES(6,2,811,685); +INSERT INTO xyoff VALUES(6,2,533,531); +INSERT INTO xyoff VALUES(6,2,390,614); +INSERT INTO xyoff VALUES(6,2,260,580); +INSERT INTO xyoff VALUES(6,2,116,377); +INSERT INTO xyoff VALUES(6,2,860,458); +INSERT INTO xyoff VALUES(6,2,438,590); +INSERT INTO xyoff VALUES(6,2,604,562); +INSERT INTO xyoff VALUES(6,2,241,242); +INSERT INTO xyoff VALUES(6,2,667,298); +INSERT INTO xyoff VALUES(6,3,787,698); +INSERT INTO xyoff VALUES(6,3,868,521); +INSERT INTO xyoff VALUES(6,3,412,587); +INSERT INTO xyoff VALUES(6,3,640,131); +INSERT INTO xyoff VALUES(6,3,748,410); +INSERT INTO xyoff VALUES(6,3,257,244); +INSERT INTO xyoff VALUES(6,3,411,195); +INSERT INTO xyoff VALUES(6,3,464,356); +INSERT INTO xyoff VALUES(6,3,157,339); +INSERT INTO xyoff VALUES(6,3,434,505); +INSERT INTO xyoff VALUES(6,4,480,671); +INSERT INTO xyoff VALUES(6,4,519,228); +INSERT INTO xyoff VALUES(6,4,404,513); +INSERT INTO xyoff VALUES(6,4,120,538); +INSERT INTO xyoff VALUES(6,4,403,663); +INSERT INTO xyoff VALUES(6,4,477,677); +INSERT INTO xyoff VALUES(6,4,690,154); +INSERT INTO xyoff VALUES(6,4,606,498); +INSERT INTO xyoff VALUES(6,4,430,665); +INSERT INTO xyoff VALUES(6,4,499,273); +INSERT INTO xyoff VALUES(7,1,118,526); +INSERT INTO xyoff VALUES(7,1,817,522); +INSERT INTO xyoff VALUES(7,1,388,638); +INSERT INTO xyoff VALUES(7,1,181,265); +INSERT INTO xyoff VALUES(7,1,442,332); +INSERT INTO xyoff VALUES(7,1,475,282); +INSERT INTO xyoff VALUES(7,1,722,633); +INSERT INTO xyoff VALUES(7,1,104,394); +INSERT INTO xyoff VALUES(7,1,631,262); +INSERT INTO xyoff VALUES(7,1,372,392); +INSERT INTO xyoff VALUES(7,2,600,413); +INSERT INTO xyoff VALUES(7,2,386,223); +INSERT INTO xyoff VALUES(7,2,839,174); +INSERT INTO xyoff VALUES(7,2,293,410); +INSERT INTO xyoff VALUES(7,2,281,391); +INSERT INTO xyoff VALUES(7,2,859,387); +INSERT INTO xyoff VALUES(7,2,478,347); +INSERT INTO xyoff VALUES(7,2,646,690); +INSERT INTO xyoff VALUES(7,2,713,234); +INSERT INTO xyoff VALUES(7,2,199,588); +INSERT INTO xyoff VALUES(7,3,389,256); +INSERT INTO xyoff VALUES(7,3,349,542); +INSERT INTO xyoff VALUES(7,3,363,345); +INSERT INTO xyoff VALUES(7,3,751,302); +INSERT INTO xyoff VALUES(7,3,423,386); +INSERT INTO xyoff VALUES(7,3,267,444); +INSERT INTO xyoff VALUES(7,3,243,182); +INSERT INTO xyoff VALUES(7,3,453,658); +INSERT INTO xyoff VALUES(7,3,126,345); +INSERT INTO xyoff VALUES(7,3,120,472); +INSERT INTO xyoff VALUES(7,4,359,654); +INSERT INTO xyoff VALUES(7,4,339,516); +INSERT INTO xyoff VALUES(7,4,710,452); +INSERT INTO xyoff VALUES(7,4,810,560); +INSERT INTO xyoff VALUES(7,4,644,692); +INSERT INTO xyoff VALUES(7,4,826,327); +INSERT INTO xyoff VALUES(7,4,465,462); +INSERT INTO xyoff VALUES(7,4,310,456); +INSERT INTO xyoff VALUES(7,4,577,613); +INSERT INTO xyoff VALUES(7,4,502,555); +INSERT INTO xyoff VALUES(8,1,601,620); +INSERT INTO xyoff VALUES(8,1,372,683); +INSERT INTO xyoff VALUES(8,1,758,399); +INSERT INTO xyoff VALUES(8,1,485,552); +INSERT INTO xyoff VALUES(8,1,159,563); +INSERT INTO xyoff VALUES(8,1,536,303); +INSERT INTO xyoff VALUES(8,1,122,263); +INSERT INTO xyoff VALUES(8,1,836,435); +INSERT INTO xyoff VALUES(8,1,544,146); +INSERT INTO xyoff VALUES(8,1,270,277); +INSERT INTO xyoff VALUES(8,2,849,281); +INSERT INTO xyoff VALUES(8,2,563,242); +INSERT INTO xyoff VALUES(8,2,704,463); +INSERT INTO xyoff VALUES(8,2,102,165); +INSERT INTO xyoff VALUES(8,2,797,524); +INSERT INTO xyoff VALUES(8,2,612,426); +INSERT INTO xyoff VALUES(8,2,345,372); +INSERT INTO xyoff VALUES(8,2,820,376); +INSERT INTO xyoff VALUES(8,2,789,156); +INSERT INTO xyoff VALUES(8,2,321,466); +INSERT INTO xyoff VALUES(8,3,150,332); +INSERT INTO xyoff VALUES(8,3,136,152); +INSERT INTO xyoff VALUES(8,3,468,528); +INSERT INTO xyoff VALUES(8,3,409,192); +INSERT INTO xyoff VALUES(8,3,820,216); +INSERT INTO xyoff VALUES(8,3,847,249); +INSERT INTO xyoff VALUES(8,3,801,267); +INSERT INTO xyoff VALUES(8,3,181,670); +INSERT INTO xyoff VALUES(8,3,398,563); +INSERT INTO xyoff VALUES(8,3,439,576); +INSERT INTO xyoff VALUES(8,4,123,309); +INSERT INTO xyoff VALUES(8,4,190,496); +INSERT INTO xyoff VALUES(8,4,571,531); +INSERT INTO xyoff VALUES(8,4,290,255); +INSERT INTO xyoff VALUES(8,4,244,412); +INSERT INTO xyoff VALUES(8,4,264,596); +INSERT INTO xyoff VALUES(8,4,253,420); +INSERT INTO xyoff VALUES(8,4,847,536); +INSERT INTO xyoff VALUES(8,4,120,288); +INSERT INTO xyoff VALUES(8,4,331,639); + +/* Create the geopoly object from test data above */ +CREATE VIRTUAL TABLE geo1 USING geopoly(type,clr); +INSERT INTO geo1(_shape,type,clr) + SELECT geopoly_xform(jshape,A,B,-B,A,xoff,yoff), basis.name, xform.clr + FROM basis, xform, xyoff + WHERE xyoff.id1=basis.rowid AND xyoff.id2=xform.rowid; + + +/* Query polygon */ +CREATE TEMP TABLE querypoly(poly JSON, clr TEXT); +INSERT INTO querypoly(clr, poly) VALUES + ('orange', '[[300,300],[400,350],[500,250],[480,500],[400,480],[300,550],[280,450],[320,400],[280,350],[300,300]]'); + +/* Generate the HTML */ +.print '' +.print '

Everything

' +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',clr) + ) + FROM geo1; +SELECT geopoly_svg(poly, + printf('style="fill:%s;fill-opacity:0.5;"',clr) + ) + FROM querypoly; +.print '' +.print '

Query

' +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) + ) + FROM geo1, querypoly + WHERE geopoly_overlap(_shape, poly); +SELECT geopoly_svg(poly, + printf('style="fill:%s;fill-opacity:0.5;"',clr) + ) + FROM querypoly; +.print '' +.print '' diff --git a/manifest b/manifest index 4b67358753..bdb5f15c7b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Untested\sincremental\scheck-in.\s\sAdd\sthe\sgeopoly_xform()\sfunction.\s\sComplete\nbasic\slogic\sfor\sthe\sgeopoly\svirtual\stable. -D 2018-05-28T13:23:23.983 +C The\sgeopoly\svirtual\stable\sseems\sto\sbe\sworking.\s\sBut\sonly\sthinly\stested\sso\sfar. +D 2018-05-28T23:59:03.555 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 51407f0e371dcb9e65d368bd4f1a08fc17ef8361ff11aac9356f0f63693b38dd @@ -355,8 +355,8 @@ 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 8c175a1c1e9c8659533a28c9aabf5ec1315e598b56129707ffe87567fcc475b8 -F ext/rtree/rtree.c 2fd3c149c6fc4d3fdf602dc610b34ad9abdf75cca26d0c362f903aa02ea2ef47 +F ext/rtree/geopoly.c 95626633e615db611c6a61a7cc2c060d7dedea8338a92a4345e4ecce045fe0e8 +F ext/rtree/rtree.c f3c2f1b5eea75b98d4d3dcdec2ebf2a69c036b53f2f3d196e61bf5016298255f F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349 F ext/rtree/rtree2.test 5f25b01acd03470067a2d52783b2eb0a50bf836803d4342d20ca39e541220fe2 @@ -382,6 +382,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 ce5473774986a7fde188de9cbfc554f9c0f07109c61a5169019bd0c514776c11 F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a F ext/session/session1.test 4532116484f525110eb4cfff7030c59354c0cde9def4d109466b0df2b35ad5cc F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0 @@ -1730,7 +1731,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 2c2a202c14fa8803fb1e4b7356cbc9cd49e65a27e19bf6e3fd0e9dff9d5c67f9 -R f4a9697324257dda7a5826181dabdab6 +P ed06cc32568a3abaa0535b379e0ee3b04ffb7582dcda6405670620d1fbe8996c +R 81c5a462839f4fc8f38c54f9f8566edf U drh -Z 2d47301bf215e61d246a3f2a2f3aad00 +Z 985d2eedc536b0a7cccf298a1cefc057 diff --git a/manifest.uuid b/manifest.uuid index 4ffe498f38..260a10c2c6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ed06cc32568a3abaa0535b379e0ee3b04ffb7582dcda6405670620d1fbe8996c \ No newline at end of file +4288f1ad5966701eac4cfe3061e8ce98e34e0d6c112307668729642a06458d5f \ No newline at end of file From b7d376ee13878810122c0fcf0948bd468b527dec Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 29 May 2018 17:17:22 +0000 Subject: [PATCH 08/33] Fix a problem in the geopoly json parser associated with spaces before a coordinate number. FossilOrigin-Name: 9d8d3af89ab241fd6c68e043e559359c85653aa0e31270b658ff01867ae929c4 --- ext/rtree/geopoly.c | 2 +- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 9e8de3cfee..5ae2b8f22d 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -146,8 +146,8 @@ static char geopolySkipSpace(GeoParse *p){ ** return non-zero on success and zero if the next token is not a number. */ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){ - const unsigned char *z = p->z; char c = geopolySkipSpace(p); + const unsigned char *z = p->z; int j; int seenDP = 0; int seenE = 0; diff --git a/manifest b/manifest index bdb5f15c7b..3d0a40be76 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\sgeopoly\svirtual\stable\sseems\sto\sbe\sworking.\s\sBut\sonly\sthinly\stested\sso\sfar. -D 2018-05-28T23:59:03.555 +C Fix\sa\sproblem\sin\sthe\sgeopoly\sjson\sparser\sassociated\swith\sspaces\sbefore\sa\ncoordinate\snumber. +D 2018-05-29T17:17:22.931 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 95626633e615db611c6a61a7cc2c060d7dedea8338a92a4345e4ecce045fe0e8 +F ext/rtree/geopoly.c 524f336f28d2f2c3c5abf2238c07964e4ddebce441ca79489d08f7f2fae3b27e F ext/rtree/rtree.c f3c2f1b5eea75b98d4d3dcdec2ebf2a69c036b53f2f3d196e61bf5016298255f F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349 @@ -1731,7 +1731,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 ed06cc32568a3abaa0535b379e0ee3b04ffb7582dcda6405670620d1fbe8996c -R 81c5a462839f4fc8f38c54f9f8566edf +P 4288f1ad5966701eac4cfe3061e8ce98e34e0d6c112307668729642a06458d5f +R 10d3e455a51f13d4bc5211661301b72f U drh -Z 985d2eedc536b0a7cccf298a1cefc057 +Z 37cefd68e4dc10f83a5c791f1094a8b3 diff --git a/manifest.uuid b/manifest.uuid index 260a10c2c6..6580f9fd41 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4288f1ad5966701eac4cfe3061e8ce98e34e0d6c112307668729642a06458d5f \ No newline at end of file +9d8d3af89ab241fd6c68e043e559359c85653aa0e31270b658ff01867ae929c4 \ No newline at end of file From c4ceea72b7cac366a8d9b605e7e112b1b9025713 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 21 Aug 2018 12:16:33 +0000 Subject: [PATCH 09/33] Fix various harmless warnings generated by static analysis tools. FossilOrigin-Name: a04a0ea9e30e0ef12bafa0b90b7d1b7764865768bb4a738b0c73a7a3ef9416db --- ext/misc/completion.c | 3 +-- manifest | 22 +++++++++++----------- manifest.uuid | 2 +- src/pragma.c | 1 - src/upsert.c | 4 +++- src/vdbeaux.c | 2 +- src/whereexpr.c | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ext/misc/completion.c b/ext/misc/completion.c index 89c4f5d5db..4a4b918a37 100644 --- a/ext/misc/completion.c +++ b/ext/misc/completion.c @@ -365,7 +365,7 @@ static int completionFilter( pCur->zPrefix = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg])); if( pCur->zPrefix==0 ) return SQLITE_NOMEM; } - iArg++; + iArg = 1; } if( idxNum & 2 ){ pCur->nLine = sqlite3_value_bytes(argv[iArg]); @@ -373,7 +373,6 @@ static int completionFilter( pCur->zLine = sqlite3_mprintf("%s", sqlite3_value_text(argv[iArg])); if( pCur->zLine==0 ) return SQLITE_NOMEM; } - iArg++; } if( pCur->zLine!=0 && pCur->zPrefix==0 ){ int i = pCur->nLine; diff --git a/manifest b/manifest index 233b7d9449..5aa0122864 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sharmless\scompiler\swarnings\sonly\sseen\swith\sSTAT4\senabled. -D 2018-08-17T21:14:28.190 +C Fix\svarious\sharmless\swarnings\sgenerated\sby\sstatic\sanalysis\stools. +D 2018-08-21T12:16:33.162 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6 @@ -276,7 +276,7 @@ F ext/misc/appendvfs.c 3777f22ec1057dc4e5fd89f2fbddcc7a29fbeef1ad038c736c54411bb F ext/misc/btreeinfo.c 78c8c57d325185ccc04b7679e5b020e34a4d9c87453e6b7ac943d0a26cee3256 F ext/misc/carray.c ed96c218ea940b85c9a274c4d9c59fe9491c299147a38a8bba537687bd6c6005 F ext/misc/closure.c fe928228e8dfb2f00227311c203ccba9c2e5561f4f6de6da87e5b4a30cd8af15 -F ext/misc/completion.c e75b8886a2531f9a7ec02dab5f179bb37e6bd46b5da7665a6cbf2dfbe2daa483 +F ext/misc/completion.c fc811dda86d899c15848079c32cad40c181da1dd7a1a4f8d768a2c6ce07a1904 F ext/misc/compress.c dd4f8a6d0baccff3c694757db5b430f3bbd821d8686d1fc24df55cf9f035b189 F ext/misc/csv.c 65297bcce8d5acd5aadef42acbe739aef5a2ef5e74c7b73361ca19f3e21de657 F ext/misc/dbdump.c 12389a10c410fadf1e68eeb382def92d5a7fa9ce7cce4fb86a736fa2bac1000a @@ -491,7 +491,7 @@ F src/parse.y 704c94624d41d7d46a5467574130e55aa8029a563f4df538f0121475eae46e34 F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170 F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880 -F src/pragma.c 873b767f233932e97cbffd094aa61928be90aca03f946a94bb29ce5695e4885b +F src/pragma.c 79abc65c08d2754048efee3ba99fe91863dfeab0ba699a4439fa5053ec87cf36 F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324 F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0 F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365 @@ -565,7 +565,7 @@ F src/tokenize.c 01e96d1b639c3eb0b9ef90616e766d453935c554f1f7aa86b6db937b79554b9 F src/treeview.c e7a7f90552bb418533cdd0309b5eb71d4effa50165b880fc8c2001e613577e5f F src/trigger.c 4ace6d1d5ba9a89822deb287317f33c810440526eafe185c2d8a48c31df1e995 F src/update.c 345ce35eb1332eb4829857aa8b1f65a614b07dae91d0346c0dc2baacafbcc51b -F src/upsert.c 47edd408cc73f8d3c00a140550d1ad180b407c146285947969dd09874802bf88 +F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157 F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855 @@ -573,7 +573,7 @@ F src/vdbe.c b11baa48b293dc48fbd51c6a9029f88bdf4cd117c01225b2a2b5e90e5928a8a3 F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907 F src/vdbeInt.h 8ea493d994c6697cf7bccc60583a80a0222560490410f60f1113e90d36643ce0 F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611 -F src/vdbeaux.c f03d4a1961ec282abaec5dbf7e5576ddb1eb01e6157335a232d8d9e57fd5eca1 +F src/vdbeaux.c b64c699261611e3921de8bdf5a69d5559f0d1443dab8c4ba8e81a64d9219ac6a F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 F src/vdbemem.c 0dc99941388a867a4dc77a8bed5dfc6024ee9c3ef147a09de844a6629086ec0c F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f @@ -586,7 +586,7 @@ F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4 F src/where.c 155809967fbab889374dedf970ea6561b8fb519fcb165d6ba00776552ecc5cde F src/whereInt.h b90ef9b9707ef750eab2a7a080c48fb4900315033274689def32d0cf5a81ebe4 F src/wherecode.c 2b6cd1b27736cc803060289e04ecf9849976106f4077aa67d1a2c0e3ec420159 -F src/whereexpr.c 5a57a974aeadef4443b39bd44594fdf0c884b62a4c72286de880999018df8317 +F src/whereexpr.c 94f181d1bc6139973c3677e35b0f1ebfb2b82254620002abb9cb8eb02a58c0b8 F src/window.c 4b503da928dace3e845b891381a4d98eeb8c5744313ae3643df8d8d21fdcca65 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -1755,7 +1755,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 456842924bb33c0af8af29402f06e5f25b6791f698a0d12a080258b20b0cfb61 -R be5dc18fc300ed89457d8bc932b7b151 -U mistachkin -Z be93350402c55bcc80fcf7d3af56f20b +P 6f5e84bafcaf425cb664c7db8179c9c09a13c96aaf057551c04a919ca554d057 +R 9df5e3240f54dd72e65d190d80e2d8fd +U drh +Z 5fa5d5ac4c1aa0b705908d236232bb3b diff --git a/manifest.uuid b/manifest.uuid index 714f7a83e6..d5361a492b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6f5e84bafcaf425cb664c7db8179c9c09a13c96aaf057551c04a919ca554d057 \ No newline at end of file +a04a0ea9e30e0ef12bafa0b90b7d1b7764865768bb4a738b0c73a7a3ef9416db \ No newline at end of file diff --git a/src/pragma.c b/src/pragma.c index 48878a3f55..9381724b17 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -2222,7 +2222,6 @@ static int pragmaVtabConnect( } if( i==0 ){ sqlite3_str_appendf(&acc, "(\"%s\"", pPragma->zName); - cSep = ','; i++; } j = 0; diff --git a/src/upsert.c b/src/upsert.c index 31a905dd6c..850ae863b9 100644 --- a/src/upsert.c +++ b/src/upsert.c @@ -204,10 +204,12 @@ void sqlite3UpsertDoUpdate( Vdbe *v = pParse->pVdbe; sqlite3 *db = pParse->db; SrcList *pSrc; /* FROM clause for the UPDATE */ - int iDataCur = pUpsert->iDataCur; + int iDataCur; assert( v!=0 ); + assert( pUpsert!=0 ); VdbeNoopComment((v, "Begin DO UPDATE of UPSERT")); + iDataCur = pUpsert->iDataCur; if( pIdx && iCur!=iDataCur ){ if( HasRowid(pTab) ){ int regRowid = sqlite3GetTempReg(pParse); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 68784d5fa9..f4708d6c34 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -316,7 +316,7 @@ int sqlite3VdbeExplainParent(Parse *pParse){ void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ if( pParse->explain==2 ){ char *zMsg; - Vdbe *v = pParse->pVdbe; + Vdbe *v; va_list ap; int iThis; va_start(ap, zFmt); diff --git a/src/whereexpr.c b/src/whereexpr.c index a72c94f2db..b39b1453ca 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -820,7 +820,7 @@ static void exprAnalyzeOrTerm( idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC); testcase( idxNew==0 ); exprAnalyze(pSrc, pWC, idxNew); - pTerm = &pWC->a[idxTerm]; + /* pTerm = &pWC->a[idxTerm]; // would be needed if pTerm where used again */ markTermAsChild(pWC, idxNew, idxTerm); }else{ sqlite3ExprListDelete(db, pList); From f396ecadcdf3a4ea645258c99858e142a4fbef9c Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 21 Aug 2018 12:46:34 +0000 Subject: [PATCH 10/33] Further attempts to reduce the number of false-positives genenerated by static analysis tools. FossilOrigin-Name: 38f9ce6503c4dd05ccdd73463b1784a6df7ed6e5018c29c5874a3681ca34ba54 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/vdbesort.c | 7 ++++++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 5aa0122864..04d8e34e32 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\svarious\sharmless\swarnings\sgenerated\sby\sstatic\sanalysis\stools. -D 2018-08-21T12:16:33.162 +C Further\sattempts\sto\sreduce\sthe\snumber\sof\sfalse-positives\sgenenerated\sby\nstatic\sanalysis\stools. +D 2018-08-21T12:46:34.393 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6 @@ -576,7 +576,7 @@ F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611 F src/vdbeaux.c b64c699261611e3921de8bdf5a69d5559f0d1443dab8c4ba8e81a64d9219ac6a F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 F src/vdbemem.c 0dc99941388a867a4dc77a8bed5dfc6024ee9c3ef147a09de844a6629086ec0c -F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f +F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392 F src/vtab.c 678992ac8ec677a3f9b08126aaf891441083805e3b42574e3654d44538381c14 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 @@ -1755,7 +1755,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 6f5e84bafcaf425cb664c7db8179c9c09a13c96aaf057551c04a919ca554d057 -R 9df5e3240f54dd72e65d190d80e2d8fd +P a04a0ea9e30e0ef12bafa0b90b7d1b7764865768bb4a738b0c73a7a3ef9416db +R d85758f026f92625818d6378a1dcce5e U drh -Z 5fa5d5ac4c1aa0b705908d236232bb3b +Z 83b440066eedd3b049df3a10587affba diff --git a/manifest.uuid b/manifest.uuid index d5361a492b..aa020da9e4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a04a0ea9e30e0ef12bafa0b90b7d1b7764865768bb4a738b0c73a7a3ef9416db \ No newline at end of file +38f9ce6503c4dd05ccdd73463b1784a6df7ed6e5018c29c5874a3681ca34ba54 \ No newline at end of file diff --git a/src/vdbesort.c b/src/vdbesort.c index ef5715d249..b30bc4e082 100644 --- a/src/vdbesort.c +++ b/src/vdbesort.c @@ -2107,7 +2107,11 @@ static int vdbeMergeEngineInit( ){ int rc = SQLITE_OK; /* Return code */ int i; /* For looping over PmaReader objects */ - int nTree = pMerger->nTree; + int nTree; /* Number of subtrees to merge */ + + /* Failure to allocate the merge would have been detected prior to + ** invoking this routine */ + assert( pMerger!=0 ); /* eMode is always INCRINIT_NORMAL in single-threaded mode */ assert( SQLITE_MAX_WORKER_THREADS>0 || eMode==INCRINIT_NORMAL ); @@ -2116,6 +2120,7 @@ static int vdbeMergeEngineInit( assert( pMerger->pTask==0 ); pMerger->pTask = pTask; + nTree = pMerger->nTree; for(i=0; i0 && eMode==INCRINIT_ROOT ){ /* PmaReaders should be normally initialized in order, as if they are From 79e9d347642e4d81c96e7d069313701fd941f53a Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 21 Aug 2018 17:03:25 +0000 Subject: [PATCH 11/33] Fix a test case that was failing for SQLITE_ENABLE_STAT4 builds. FossilOrigin-Name: 1e29fd430dead641c5d92943ce81cf51b3df2f45c5a011bb2eed592efd62e056 --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/view.test | 5 ++++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 04d8e34e32..6d3aa15013 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Further\sattempts\sto\sreduce\sthe\snumber\sof\sfalse-positives\sgenenerated\sby\nstatic\sanalysis\stools. -D 2018-08-21T12:46:34.393 +C Fix\sa\stest\scase\sthat\swas\sfailing\sfor\sSQLITE_ENABLE_STAT4\sbuilds. +D 2018-08-21T17:03:26.000 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6 @@ -1544,7 +1544,7 @@ F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2 F test/vacuummem.test 7b42abb3208bd82dd23a7536588396f295a314f2 F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62 F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661 -F test/view.test 42b97dcd3d7c2f5f9439e41b0983e0c6a5718d8b874e9d5e82d3cd25a50ffcf7 +F test/view.test 226fb71e37be61854f3a01929ae0a7e14584d6aef5c459bb0a22318f0b6dd210 F test/vtab1.test 8f91b9538d1404c3932293a588c4344218a0c94792d4289bb55e41020e7b3fff F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c84082 F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e @@ -1755,7 +1755,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 a04a0ea9e30e0ef12bafa0b90b7d1b7764865768bb4a738b0c73a7a3ef9416db -R d85758f026f92625818d6378a1dcce5e -U drh -Z 83b440066eedd3b049df3a10587affba +P 38f9ce6503c4dd05ccdd73463b1784a6df7ed6e5018c29c5874a3681ca34ba54 +R e19baf9da067d129328dfc451589a7f0 +U dan +Z 71298651aa8751c5de875b463750a2a6 diff --git a/manifest.uuid b/manifest.uuid index aa020da9e4..8dc2017f9a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -38f9ce6503c4dd05ccdd73463b1784a6df7ed6e5018c29c5874a3681ca34ba54 \ No newline at end of file +1e29fd430dead641c5d92943ce81cf51b3df2f45c5a011bb2eed592efd62e056 \ No newline at end of file diff --git a/test/view.test b/test/view.test index 857d077345..54e6f916c1 100644 --- a/test/view.test +++ b/test/view.test @@ -691,10 +691,13 @@ do_test view-25.1 { db eval {DROP VIEW x1;} set log } {} + +set res [list {SQLITE_DELETE sqlite_stat1 {} main {} {}}] +ifcapable stat4 { lappend res {SQLITE_DELETE sqlite_stat4 {} main {} {}} } do_test view-25.2 { set log "" db eval {DROP TABLE t25;} set log -} {{SQLITE_DELETE sqlite_stat1 {} main {} {}}} +} $res finish_test From ba3a4072b406b5ec3810db8e6621e6cb301d70d9 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 23 Aug 2018 18:56:33 +0000 Subject: [PATCH 12/33] Automatically detect when compiling for AArch64 on windows and set SQLITE_BYTEORDER to little-endian to avoid compile-time testing. FossilOrigin-Name: ef6729be85ed106212ed23a024d83b85b709207cf287436c0603a21c659f36ad --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqliteInt.h | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 6d3aa15013..de40c9d862 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stest\scase\sthat\swas\sfailing\sfor\sSQLITE_ENABLE_STAT4\sbuilds. -D 2018-08-21T17:03:26.000 +C Automatically\sdetect\swhen\scompiling\sfor\sAArch64\son\swindows\sand\sset\nSQLITE_BYTEORDER\sto\slittle-endian\sto\savoid\scompile-time\stesting. +D 2018-08-23T18:56:33.848 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6 @@ -503,7 +503,7 @@ F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1 F src/sqlite.h.in 82b5768e36ce796ecf93c73bd88bad99def831ce7d470138e213ac693bf4ceab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7 -F src/sqliteInt.h a5d212bb7ae5cfc0540af6fb09eee2092a45fe083fac4191ee64ff70e7d4d78a +F src/sqliteInt.h 49620c948a0022c065a9948c7f9feba56d5206da8050c83ad365fb36896a4ac7 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1755,7 +1755,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 38f9ce6503c4dd05ccdd73463b1784a6df7ed6e5018c29c5874a3681ca34ba54 -R e19baf9da067d129328dfc451589a7f0 -U dan -Z 71298651aa8751c5de875b463750a2a6 +P 1e29fd430dead641c5d92943ce81cf51b3df2f45c5a011bb2eed592efd62e056 +R 0974697392d1ab411d928a32ee000d51 +U drh +Z 8a92905a25efce04adc91a14634c4b23 diff --git a/manifest.uuid b/manifest.uuid index 8dc2017f9a..96562ab211 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1e29fd430dead641c5d92943ce81cf51b3df2f45c5a011bb2eed592efd62e056 \ No newline at end of file +ef6729be85ed106212ed23a024d83b85b709207cf287436c0603a21c659f36ad \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 6304680ab3..44f90c6683 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -832,7 +832,7 @@ typedef INT16_TYPE LogEst; # if defined(i386) || defined(__i386__) || defined(_M_IX86) || \ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \ - defined(__arm__) + defined(__arm__) || defined(_M_ARM64) # define SQLITE_BYTEORDER 1234 # elif defined(sparc) || defined(__ppc__) # define SQLITE_BYTEORDER 4321 From 88edc6c72a99dfe387918887b5fc38f1615969c0 Mon Sep 17 00:00:00 2001 From: mistachkin Date: Fri, 24 Aug 2018 19:04:08 +0000 Subject: [PATCH 13/33] Set SQLITE_PTRSIZE to 4 when compiling with xlc on 32-bit AIX. FossilOrigin-Name: d158e5b12eec5b81d54c8f5902a972795423947a21d0212b6cceb2810aa6cc5c --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/sqliteInt.h | 3 ++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index de40c9d862..31a0cb26a2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Automatically\sdetect\swhen\scompiling\sfor\sAArch64\son\swindows\sand\sset\nSQLITE_BYTEORDER\sto\slittle-endian\sto\savoid\scompile-time\stesting. -D 2018-08-23T18:56:33.848 +C Set\sSQLITE_PTRSIZE\sto\s4\swhen\scompiling\swith\sxlc\son\s32-bit\sAIX. +D 2018-08-24T19:04:08.056 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6 @@ -503,7 +503,7 @@ F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1 F src/sqlite.h.in 82b5768e36ce796ecf93c73bd88bad99def831ce7d470138e213ac693bf4ceab F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7 -F src/sqliteInt.h 49620c948a0022c065a9948c7f9feba56d5206da8050c83ad365fb36896a4ac7 +F src/sqliteInt.h 2a670143a4f6b7d85958bac125e4d9d8ad14f016a3582e9d7c6907d9d50b75a0 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1755,7 +1755,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 1e29fd430dead641c5d92943ce81cf51b3df2f45c5a011bb2eed592efd62e056 -R 0974697392d1ab411d928a32ee000d51 -U drh -Z 8a92905a25efce04adc91a14634c4b23 +P ef6729be85ed106212ed23a024d83b85b709207cf287436c0603a21c659f36ad +R 0f2d8093aae9a7e4f75df1b87b4bd0e1 +U mistachkin +Z 5d877bbacdeea49203afbcd3a16fe3ab diff --git a/manifest.uuid b/manifest.uuid index 96562ab211..d8f7e24ad9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ef6729be85ed106212ed23a024d83b85b709207cf287436c0603a21c659f36ad \ No newline at end of file +d158e5b12eec5b81d54c8f5902a972795423947a21d0212b6cceb2810aa6cc5c \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 44f90c6683..875f8fa692 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -791,7 +791,8 @@ typedef INT16_TYPE LogEst; # if defined(__SIZEOF_POINTER__) # define SQLITE_PTRSIZE __SIZEOF_POINTER__ # elif defined(i386) || defined(__i386__) || defined(_M_IX86) || \ - defined(_M_ARM) || defined(__arm__) || defined(__x86) + defined(_M_ARM) || defined(__arm__) || defined(__x86) || \ + (defined(__TOS_AIX__) && !defined(__64BIT__)) # define SQLITE_PTRSIZE 4 # else # define SQLITE_PTRSIZE 8 From 95327f539baa622a54efa6e9bd67e8cc319d2fe7 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 25 Aug 2018 18:57:12 +0000 Subject: [PATCH 14/33] Fix a harmless compiler warning. FossilOrigin-Name: d49be9838d237b57ba1f12ed00e2d3411314ee1b9c30ef7bbaf65aca20d0870e --- ext/rtree/geopoly.c | 2 +- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 5ae2b8f22d..229c399c7b 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -698,7 +698,7 @@ static void geopolyAddSegments( ){ unsigned int i; GeoCoord *x; - for(i=0; inVertex-1; i++){ + for(i=0; i<(unsigned)pPoly->nVertex-1; i++){ x = pPoly->a + (i*2); geopolyAddOneSegment(p, x[0], x[1], x[2], x[3], side, i); } diff --git a/manifest b/manifest index 69ed94f90d..a150ebe81f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\senhancements\sfrom\strunk. -D 2018-08-23T14:54:45.921 +C Fix\sa\sharmless\scompiler\swarning. +D 2018-08-25T18:57:12.922 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 524f336f28d2f2c3c5abf2238c07964e4ddebce441ca79489d08f7f2fae3b27e +F ext/rtree/geopoly.c 9d4f90cdb08bc46de463c5ee1ab7cf114f33f7d512165a9b60eb710a5801777a F ext/rtree/rtree.c f3c2f1b5eea75b98d4d3dcdec2ebf2a69c036b53f2f3d196e61bf5016298255f F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349 @@ -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 9d8d3af89ab241fd6c68e043e559359c85653aa0e31270b658ff01867ae929c4 6f5e84bafcaf425cb664c7db8179c9c09a13c96aaf057551c04a919ca554d057 -R d84f06ed0f94ca1373159bebe9094ab5 +P c446c8841192054c97ba5003fb6185b135a687b36c10fe0986e627282955520a +R a41568f93760504ebb09f57d0f907e04 U drh -Z 725be34ef0270e7909902e889a1c91fa +Z e5256e66a995508165b2fa785b46beee diff --git a/manifest.uuid b/manifest.uuid index 6a9daefc09..b99708861f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c446c8841192054c97ba5003fb6185b135a687b36c10fe0986e627282955520a \ No newline at end of file +d49be9838d237b57ba1f12ed00e2d3411314ee1b9c30ef7bbaf65aca20d0870e \ No newline at end of file From 27d62540e529de7e2ea39d1f64c824e428280e33 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 25 Aug 2018 19:51:49 +0000 Subject: [PATCH 15/33] Provide the two-argument geopoly_within(P1,P2) routine that determines if polygon P2 is contained within polygon P1. Make this function available to the query planner for optimized rtree lookups. Update the visual01.txt script to verify that the new functionality actually works. FossilOrigin-Name: 6eb5d09b7f9d9bf8edbf993dccc2e2f702b95ba96cf68445609feb0ccc3ac0f7 --- ext/rtree/geopoly.c | 56 +++++++++++++++++++++++++------- ext/rtree/visual01.txt | 74 +++++++++++++++++++++++++++++++++++++++++- manifest | 14 ++++---- manifest.uuid | 2 +- 4 files changed, 125 insertions(+), 21 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 229c399c7b..1ebca66259 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -579,34 +579,45 @@ static int pointBeneathLine( return 0; } +/* Forward declaration */ +static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2); + /* -** SQL function: geopoly_within(P,X,Y) +** SQL function: geopoly_within(P,X,Y) -- 3-argument form ** ** Return +2 if point X,Y is within polygon P. ** Return +1 if point X,Y is on the polygon boundary. ** Return 0 if point X,Y is outside the polygon +** +** SQL function: geopoly_within(P1,P2) -- 2-argument form +** +** Return +2 if P1 and P2 are the same polygon +** Return +1 if P2 is contained within P1 +** Return 0 if any part of P2 is on the outside of P1 +** */ static void geopolyWithinFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ - GeoPoly *p = geopolyFuncParam(context, argv[0], 0); - double x0 = sqlite3_value_double(argv[1]); - double y0 = sqlite3_value_double(argv[2]); - if( p ){ + GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0); + if( p1==0 ) return; + if( argc==3 ){ + double x0 = sqlite3_value_double(argv[1]); + double y0 = sqlite3_value_double(argv[2]); int v = 0; int cnt = 0; int ii; - for(ii=0; iinVertex-1; ii++){ - v = pointBeneathLine(x0,y0,p->a[ii*2],p->a[ii*2+1], - p->a[ii*2+2],p->a[ii*2+3]); + for(ii=0; iinVertex-1; ii++){ + v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1], + p1->a[ii*2+2],p1->a[ii*2+3]); if( v==2 ) break; cnt += v; } if( v!=2 ){ - v = pointBeneathLine(x0,y0,p->a[ii*2],p->a[ii*2+1], - p->a[0],p->a[1]); + v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1], + p1->a[0],p1->a[1]); } if( v==2 ){ sqlite3_result_int(context, 1); @@ -615,8 +626,20 @@ static void geopolyWithinFunc( }else{ sqlite3_result_int(context, 2); } - sqlite3_free(p); - } + }else{ + assert( argc==2 ); + GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0); + if( p2 ){ + int x = geopolyOverlap(p1, p2); + if( x<0 ){ + sqlite3_result_error_nomem(context); + }else{ + sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0); + } + sqlite3_free(p2); + } + } + sqlite3_free(p1); } /* Objects used by the overlap algorihm. */ @@ -1219,6 +1242,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ if( iRowidTerm>=0 ){ pIdxInfo->idxNum = 1; + pIdxInfo->idxStr = "rowid"; pIdxInfo->aConstraintUsage[iRowidTerm].argvIndex = 1; pIdxInfo->aConstraintUsage[iRowidTerm].omit = 1; pIdxInfo->estimatedCost = 30.0; @@ -1228,6 +1252,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ } if( iFuncTerm>=0 ){ pIdxInfo->idxNum = 2; + pIdxInfo->idxStr = "rtree"; pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1; pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0; pIdxInfo->estimatedCost = 300.0; @@ -1235,6 +1260,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ return SQLITE_OK; } pIdxInfo->idxNum = 3; + pIdxInfo->idxStr = "fullscan"; pIdxInfo->estimatedCost = 3000000.0; pIdxInfo->estimatedRows = 100000; return SQLITE_OK; @@ -1432,6 +1458,11 @@ static int geopolyFindFunction( *ppArg = 0; return SQLITE_INDEX_CONSTRAINT_FUNCTION; } + if( nArg==2 && sqlite3_stricmp(zName, "geopoly_within")==0 ){ + *pxFunc = geopolyWithinFunc; + *ppArg = 0; + return SQLITE_INDEX_CONSTRAINT_FUNCTION; + } return 0; } @@ -1473,6 +1504,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){ { geopolyBlobFunc, 1, "geopoly_blob" }, { geopolyJsonFunc, 1, "geopoly_json" }, { geopolySvgFunc, -1, "geopoly_svg" }, + { geopolyWithinFunc, 2, "geopoly_within" }, { geopolyWithinFunc, 3, "geopoly_within" }, { geopolyOverlapFunc, 2, "geopoly_overlap" }, { geopolyDebugFunc, 1, "geopoly_debug" }, diff --git a/ext/rtree/visual01.txt b/ext/rtree/visual01.txt index bb3e4af5b5..9aafb14dc3 100644 --- a/ext/rtree/visual01.txt +++ b/ext/rtree/visual01.txt @@ -374,7 +374,16 @@ SELECT geopoly_svg(poly, ) FROM querypoly; .print '' -.print '

Query

' + +.print '

Overlap Query

' +.print '
'
+EXPLAIN QUERY PLAN
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       )
+  FROM geo1, querypoly
+ WHERE geopoly_overlap(_shape, poly);
+.print '
' .print '' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) @@ -386,4 +395,67 @@ SELECT geopoly_svg(poly, ) FROM querypoly; .print '' + +.print '

Within Query

' +.print '
'
+EXPLAIN QUERY PLAN
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       )
+  FROM geo1, querypoly
+ WHERE geopoly_within(_shape, poly);
+.print '
' +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) + ) + FROM geo1, querypoly + WHERE geopoly_within(_shape, poly); +SELECT geopoly_svg(poly, + printf('style="fill:%s;fill-opacity:0.5;"',clr) + ) + FROM querypoly; +.print '' + +.print '

Not Overlap Query

' +.print '
'
+EXPLAIN QUERY PLAN
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       )
+  FROM geo1, querypoly
+ WHERE NOT geopoly_overlap(_shape, poly);
+.print '
' +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) + ) + FROM geo1, querypoly + WHERE NOT geopoly_overlap(_shape, poly); +SELECT geopoly_svg(poly, + printf('style="fill:%s;fill-opacity:0.5;"',clr) + ) + FROM querypoly; +.print '' + +.print '

Not Within Query

' +.print '
'
+EXPLAIN QUERY PLAN
+SELECT geopoly_svg(_shape,
+         printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
+       )
+  FROM geo1, querypoly
+ WHERE NOT geopoly_within(_shape, poly);
+.print '
' +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) + ) + FROM geo1, querypoly + WHERE NOT geopoly_within(_shape, poly); +SELECT geopoly_svg(poly, + printf('style="fill:%s;fill-opacity:0.5;"',clr) + ) + FROM querypoly; +.print '' .print '' diff --git a/manifest b/manifest index a150ebe81f..4be8e181d6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sharmless\scompiler\swarning. -D 2018-08-25T18:57:12.922 +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 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 9d4f90cdb08bc46de463c5ee1ab7cf114f33f7d512165a9b60eb710a5801777a +F ext/rtree/geopoly.c b495718226257fe7a69df3367ae9a440a81f99e63013177cb327fbc8a12a1d92 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 ce5473774986a7fde188de9cbfc554f9c0f07109c61a5169019bd0c514776c11 +F ext/rtree/visual01.txt c5cceddea30ab74099365a54ee8850f085d01503050353240eda48b6062ad3f4 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 c446c8841192054c97ba5003fb6185b135a687b36c10fe0986e627282955520a -R a41568f93760504ebb09f57d0f907e04 +P d49be9838d237b57ba1f12ed00e2d3411314ee1b9c30ef7bbaf65aca20d0870e +R d6a6a8b236c31c3e94eaf646cbba5241 U drh -Z e5256e66a995508165b2fa785b46beee +Z 150d6fa9f487a014f94bf1a66214204f diff --git a/manifest.uuid b/manifest.uuid index b99708861f..c25d834242 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d49be9838d237b57ba1f12ed00e2d3411314ee1b9c30ef7bbaf65aca20d0870e \ No newline at end of file +6eb5d09b7f9d9bf8edbf993dccc2e2f702b95ba96cf68445609feb0ccc3ac0f7 \ No newline at end of file From e6474b77b849843e45e9f235486ca7d63a2ccae5 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 25 Aug 2018 23:03:27 +0000 Subject: [PATCH 16/33] Enhance the geopoly virtual table so that it does a better job of optimizing geopoly_within() queries. FossilOrigin-Name: 1f717385340f295064a7649cfc36ad048573cbacb6faa20f5c6067328c40c745 --- ext/rtree/geopoly.c | 76 +++++++++++++++++++++++++++++------------- ext/rtree/visual01.txt | 56 +++++++++++++++++++++++++++++++ manifest | 14 ++++---- manifest.uuid | 2 +- 4 files changed, 116 insertions(+), 32 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 1ebca66259..8b4246858e 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -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; iinConstraint; 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; } diff --git a/ext/rtree/visual01.txt b/ext/rtree/visual01.txt index 9aafb14dc3..f9692714a6 100644 --- a/ext/rtree/visual01.txt +++ b/ext/rtree/visual01.txt @@ -396,6 +396,34 @@ SELECT geopoly_svg(poly, FROM querypoly; .print '' +.print '

Bounding-Box Overlap Query

' +.print '
'
+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 '
' +.print '' +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 '' + .print '

Within Query

' .print '
'
 EXPLAIN QUERY PLAN
@@ -417,6 +445,34 @@ SELECT geopoly_svg(poly,
   FROM querypoly;
 .print ''
 
+.print '

Bounding-Box WITHIN Query

' +.print '
'
+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 '
' +.print '' +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 '' + .print '

Not Overlap Query

' .print '
'
 EXPLAIN QUERY PLAN
diff --git a/manifest b/manifest
index 4be8e181d6..ac0fba2074 100644
--- 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
diff --git a/manifest.uuid b/manifest.uuid
index c25d834242..79c7afc57f 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-6eb5d09b7f9d9bf8edbf993dccc2e2f702b95ba96cf68445609feb0ccc3ac0f7
\ No newline at end of file
+1f717385340f295064a7649cfc36ad048573cbacb6faa20f5c6067328c40c745
\ No newline at end of file

From b2a18c95f0f1ed2805c7b17b0055db33a138df7a Mon Sep 17 00:00:00 2001
From: drh 
Date: Mon, 27 Aug 2018 15:55:37 +0000
Subject: [PATCH 17/33] Split the three-argument version of geopoly_within()
 off into a separate function named geopoly_contains_point().

FossilOrigin-Name: 5a0e1541037b5bbc1b4bf26a7da304c9b32ea72960aca8b9309cf2180757c8a4
---
 ext/rtree/geopoly.c | 108 +++++++++++++++++++++++---------------------
 manifest            |  12 ++---
 manifest.uuid       |   2 +-
 3 files changed, 64 insertions(+), 58 deletions(-)

diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c
index 8b4246858e..3af3d32612 100644
--- a/ext/rtree/geopoly.c
+++ b/ext/rtree/geopoly.c
@@ -579,17 +579,50 @@ static int pointBeneathLine(
   return 0;
 }
 
-/* Forward declaration */
-static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2);
-
 /*
-** SQL function:    geopoly_within(P,X,Y)  -- 3-argument form
+** SQL function:    geopoly_contains_point(P,X,Y)
 **
 ** Return +2 if point X,Y is within polygon P.
 ** Return +1 if point X,Y is on the polygon boundary.
 ** Return 0 if point X,Y is outside the polygon
-**
-** SQL function:    geopoly_within(P1,P2)  -- 2-argument form
+*/
+static void geopolyContainsPointFunc(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
+  double x0 = sqlite3_value_double(argv[1]);
+  double y0 = sqlite3_value_double(argv[2]);
+  int v = 0;
+  int cnt = 0;
+  int ii;
+  if( p1==0 ) return;
+  for(ii=0; iinVertex-1; ii++){
+    v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
+                               p1->a[ii*2+2],p1->a[ii*2+3]);
+    if( v==2 ) break;
+    cnt += v;
+  }
+  if( v!=2 ){
+    v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
+                               p1->a[0],p1->a[1]);
+  }
+  if( v==2 ){
+    sqlite3_result_int(context, 1);
+  }else if( ((v+cnt)&1)==0 ){
+    sqlite3_result_int(context, 0);
+  }else{
+    sqlite3_result_int(context, 2);
+  }
+  sqlite3_free(p1);
+}
+
+/* Forward declaration */
+static int geopolyOverlap(GeoPoly *p1, GeoPoly *p2);
+
+/*
+** SQL function:    geopoly_within(P1,P2)
 **
 ** Return +2 if P1 and P2 are the same polygon
 ** Return +1 if P2 is contained within P1
@@ -602,44 +635,17 @@ static void geopolyWithinFunc(
   sqlite3_value **argv
 ){
   GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
-  if( p1==0 ) return;
-  if( argc==3 ){
-    double x0 = sqlite3_value_double(argv[1]);
-    double y0 = sqlite3_value_double(argv[2]);
-    int v = 0;
-    int cnt = 0;
-    int ii;
-    for(ii=0; iinVertex-1; ii++){
-      v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
-                                 p1->a[ii*2+2],p1->a[ii*2+3]);
-      if( v==2 ) break;
-      cnt += v;
-    }
-    if( v!=2 ){
-      v = pointBeneathLine(x0,y0,p1->a[ii*2],p1->a[ii*2+1],
-                                 p1->a[0],p1->a[1]);
-    }
-    if( v==2 ){
-      sqlite3_result_int(context, 1);
-    }else if( ((v+cnt)&1)==0 ){
-      sqlite3_result_int(context, 0);
+  GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
+  if( p1 && p2 ){
+    int x = geopolyOverlap(p1, p2);
+    if( x<0 ){
+      sqlite3_result_error_nomem(context);
     }else{
-      sqlite3_result_int(context, 2);
-    }
-  }else{
-    assert( argc==2 );
-    GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
-    if( p2 ){
-      int x = geopolyOverlap(p1, p2);
-      if( x<0 ){
-        sqlite3_result_error_nomem(context);
-      }else{
-        sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0);
-      }
-      sqlite3_free(p2);
+      sqlite3_result_int(context, x==2 ? 1 : x==4 ? 2 : 0);
     }
   }
   sqlite3_free(p1);
+  sqlite3_free(p2);
 }
 
 /* Objects used by the overlap algorihm. */
@@ -1486,7 +1492,7 @@ static int geopolyFindFunction(
     *ppArg = 0;
     return SQLITE_INDEX_CONSTRAINT_FUNCTION;
   }
-  if( nArg==2 && sqlite3_stricmp(zName, "geopoly_within")==0 ){
+  if( sqlite3_stricmp(zName, "geopoly_within")==0 ){
     *pxFunc = geopolyWithinFunc;
     *ppArg = 0;
     return SQLITE_INDEX_CONSTRAINT_FUNCTION+1;
@@ -1528,16 +1534,16 @@ static int sqlite3_geopoly_init(sqlite3 *db){
     int nArg;
     const char *zName;
   } aFunc[] = {
-     { geopolyAreaFunc,          1,    "geopoly_area"     },
-     { geopolyBlobFunc,          1,    "geopoly_blob"     },
-     { geopolyJsonFunc,          1,    "geopoly_json"     },
-     { geopolySvgFunc,          -1,    "geopoly_svg"      },
-     { geopolyWithinFunc,        2,    "geopoly_within"   },
-     { geopolyWithinFunc,        3,    "geopoly_within"   },
-     { geopolyOverlapFunc,       2,    "geopoly_overlap"  },
-     { geopolyDebugFunc,         1,    "geopoly_debug"    },
-     { geopolyBBoxFunc,          1,    "geopoly_bbox"     },
-     { geopolyXformFunc,         7,    "geopoly_xform"    },
+     { geopolyAreaFunc,          1,    "geopoly_area"             },
+     { geopolyBlobFunc,          1,    "geopoly_blob"             },
+     { geopolyJsonFunc,          1,    "geopoly_json"             },
+     { geopolySvgFunc,          -1,    "geopoly_svg"              },
+     { geopolyWithinFunc,        2,    "geopoly_within"           },
+     { geopolyContainsPointFunc, 3,    "geopoly_contains_point"   },
+     { geopolyOverlapFunc,       2,    "geopoly_overlap"          },
+     { geopolyDebugFunc,         1,    "geopoly_debug"            },
+     { geopolyBBoxFunc,          1,    "geopoly_bbox"             },
+     { geopolyXformFunc,         7,    "geopoly_xform"            },
   };
   int i;
   for(i=0; i
Date: Mon, 27 Aug 2018 17:05:59 +0000
Subject: [PATCH 18/33] Minor changes to the visual01.txt test script.

FossilOrigin-Name: 4bc28eed32154be0e62fe69acd30f828c2e6f59c6579618ecad8ecf632a90517
---
 ext/rtree/visual01.txt | 32 ++++++++++++++++----------------
 manifest               | 12 ++++++------
 manifest.uuid          |  2 +-
 3 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/ext/rtree/visual01.txt b/ext/rtree/visual01.txt
index f9692714a6..b248b76bc8 100644
--- a/ext/rtree/visual01.txt
+++ b/ext/rtree/visual01.txt
@@ -377,6 +377,10 @@ SELECT geopoly_svg(poly,
 
 .print '

Overlap Query

' .print '
'
+.print 'SELECT *'
+.print '  FROM geo1, querypoly'
+.print ' WHERE geopoly_overlap(_shape, poly);'
+.print 
 EXPLAIN QUERY PLAN
 SELECT geopoly_svg(_shape,
          printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
@@ -397,14 +401,6 @@ SELECT geopoly_svg(poly,
 .print ''
 
 .print '

Bounding-Box Overlap Query

' -.print '
'
-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 '
' .print '' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) @@ -426,6 +422,10 @@ SELECT geopoly_svg(geopoly_bbox(poly), .print '

Within Query

' .print '
'
+.print 'SELECT *'
+.print '  FROM geo1, querypoly'
+.print ' WHERE geopoly_within(_shape, poly);'
+.print 
 EXPLAIN QUERY PLAN
 SELECT geopoly_svg(_shape,
          printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
@@ -446,14 +446,6 @@ SELECT geopoly_svg(poly,
 .print ''
 
 .print '

Bounding-Box WITHIN Query

' -.print '
'
-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 '
' .print '' SELECT geopoly_svg(_shape, printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) @@ -475,6 +467,10 @@ SELECT geopoly_svg(geopoly_bbox(poly), .print '

Not Overlap Query

' .print '
'
+.print 'SELECT *'
+.print '  FROM geo1, querypoly'
+.print ' WHERE NOT geopoly_overlap(_shape, poly);'
+.print 
 EXPLAIN QUERY PLAN
 SELECT geopoly_svg(_shape,
          printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
@@ -496,6 +492,10 @@ SELECT geopoly_svg(poly,
 
 .print '

Not Within Query

' .print '
'
+.print 'SELECT *'
+.print '  FROM geo1, querypoly'
+.print ' WHERE NOT geopoly_within(_shape, poly);'
+.print 
 EXPLAIN QUERY PLAN
 SELECT geopoly_svg(_shape,
          printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
diff --git a/manifest b/manifest
index 539d326ba8..5d9705d73b 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Split\sthe\sthree-argument\sversion\sof\sgeopoly_within()\soff\sinto\sa\sseparate\nfunction\snamed\sgeopoly_contains_point().
-D 2018-08-27T15:55:37.720
+C Minor\schanges\sto\sthe\svisual01.txt\stest\sscript.
+D 2018-08-27T17:05:59.920
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f
@@ -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 9852cd026953dd0e6fcfae49f72f51b3b9a42f11f2f38720e9f6d4993d862802
+F ext/rtree/visual01.txt a3bc394ac37a031d8eda690fa35a6532717df2ae54cd066e1b8f45566b0a8650
 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 1f717385340f295064a7649cfc36ad048573cbacb6faa20f5c6067328c40c745
-R c8bba0eba3c40fb02a7a476491c628b8
+P 5a0e1541037b5bbc1b4bf26a7da304c9b32ea72960aca8b9309cf2180757c8a4
+R 57d482752e51750ee238bfa9c4f73bf0
 U drh
-Z dc507345f435c2e520c7c866391dda2f
+Z 5dd365657ebaf30e9435a4a7515828ca
diff --git a/manifest.uuid b/manifest.uuid
index c75656c40b..4a106de8af 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-5a0e1541037b5bbc1b4bf26a7da304c9b32ea72960aca8b9309cf2180757c8a4
\ No newline at end of file
+4bc28eed32154be0e62fe69acd30f828c2e6f59c6579618ecad8ecf632a90517
\ No newline at end of file

From f5778751f7fd15962d469775a8e15ec09a6ec5d0 Mon Sep 17 00:00:00 2001
From: dan 
Date: Tue, 28 Aug 2018 11:23:52 +0000
Subject: [PATCH 19/33] Fix a problem causing spurious SQLITE_CORRUPT errors
 when using the snapshot API to read from old database snapshots.

FossilOrigin-Name: 535155be584ad8c1836e6b1c62de836d9872056d39608c995221c928cb5b365d
---
 manifest            | 16 +++++-----
 manifest.uuid       |  2 +-
 src/wal.c           |  1 +
 test/snapshot4.test | 75 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 85 insertions(+), 9 deletions(-)
 create mode 100644 test/snapshot4.test

diff --git a/manifest b/manifest
index a045ef12ab..6c13150b7e 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\ssupport\sfor\sthe\sGeopoly\sextension\sto\sthe\sR-Tree\sextension.\s\sThis\salso\ninvolves\sadding\sthe\sSQLITE_INDEX_CONSTRAINT_FUNCTION\scapability\sto\sthe\s\nxFindFunction\smethod\sof\sthe\ssqlite3_module\sobject,\sand\sto\sthe\nsqlite3_index_info.aConstraint.op\sfield\sin\sthe\sxBestIndex\simplementation\sof\nvirtual\stables.
-D 2018-08-27T17:13:12.965
+C Fix\sa\sproblem\scausing\sspurious\sSQLITE_CORRUPT\serrors\swhen\susing\sthe\ssnapshot\nAPI\sto\sread\sfrom\sold\sdatabase\ssnapshots.
+D 2018-08-28T11:23:52.641
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f
@@ -582,7 +582,7 @@ F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7
 F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
 F src/vtab.c 678992ac8ec677a3f9b08126aaf891441083805e3b42574e3654d44538381c14
 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
-F src/wal.c e4bcbd90072e9626126d6f3b8411159a0b984c1b9628d15237776578d5eda12d
+F src/wal.c 46bfc9427d527099c17ce00a343a1c3fb8b050b00ddaf90a94398cda44070bf8
 F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
 F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4
 F src/where.c 155809967fbab889374dedf970ea6561b8fb519fcb165d6ba00776552ecc5cde
@@ -1274,6 +1274,7 @@ F test/skipscan6.test 0b4cd1b4ac9f84d91454df513c99a4932fa07e8f27b8049bea605068b3
 F test/snapshot.test fef12fc5c16ff21c4748509401cfba7d9a3d91156f1bfe23fb881d3bfc65ddfe
 F test/snapshot2.test 925e42427e923262db63c9d7155183f889e3e99feaedec4075f659e51608344f
 F test/snapshot3.test 9719443594a04778861bd20d12596c5f880af177d6cd62f111da3198cafc6096
+F test/snapshot4.test 0f7e6bd6f1370d112ee820c541d0dd0e7b8ab4ea77429e65106d81c9ad2185a6
 F test/snapshot_fault.test 52c5e97ebd218846a8ae2da4d147d3e77d71f963
 F test/snapshot_up.test b778a04561a67b8bfde828f473a8d31dbde23e3f648e36237e0369421e08f23c
 F test/soak.test 18944cf21b94a7fe0df02016a6ee1e9632bc4e8d095a0cb49d95e15d5cca2d5c
@@ -1757,8 +1758,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 d158e5b12eec5b81d54c8f5902a972795423947a21d0212b6cceb2810aa6cc5c 4bc28eed32154be0e62fe69acd30f828c2e6f59c6579618ecad8ecf632a90517
-R 8e52d60c2558b132e89c46c2b2e927ee
-T +closed 4bc28eed32154be0e62fe69acd30f828c2e6f59c6579618ecad8ecf632a90517
-U drh
-Z 29251fdcd22ade960e4bf01a9382ce41
+P 666133e32ca8e95807f8437dc8401bc93e2e6508ab8e6ae1e6031b7cee1584ae
+R 64c8500a3b3b1576c0a05df68a2057d2
+U dan
+Z 4febad62a4c0de1b34fab12b530aa165
diff --git a/manifest.uuid b/manifest.uuid
index 450c37349d..fd0023fa92 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-666133e32ca8e95807f8437dc8401bc93e2e6508ab8e6ae1e6031b7cee1584ae
\ No newline at end of file
+535155be584ad8c1836e6b1c62de836d9872056d39608c995221c928cb5b365d
\ No newline at end of file
diff --git a/src/wal.c b/src/wal.c
index e8714403d8..194d6da1d0 100644
--- a/src/wal.c
+++ b/src/wal.c
@@ -2798,6 +2798,7 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
 
         /* Release the shared CKPT lock obtained above. */
         walUnlockShared(pWal, WAL_CKPT_LOCK);
+        pWal->minFrame = 1;
       }
 
 
diff --git a/test/snapshot4.test b/test/snapshot4.test
new file mode 100644
index 0000000000..90a8d254e7
--- /dev/null
+++ b/test/snapshot4.test
@@ -0,0 +1,75 @@
+# 2018 August 28
+#
+# 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 the sqlite3_snapshot_xxx() APIs.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+ifcapable !snapshot {finish_test; return}
+set testprefix snapshot4
+
+# This test does not work with the inmemory_journal permutation. The reason
+# is that each connection opened as part of this permutation executes
+# "PRAGMA journal_mode=memory", which fails if the database is in wal mode
+# and there are one or more existing connections.
+if {[permutation]=="inmemory_journal"} {
+  finish_test
+  return
+}
+
+sqlite3 db2 test.db
+
+do_execsql_test 1.0 {
+  PRAGMA cache_size = 10;
+  CREATE TABLE t1(a, b);
+  INSERT INTO t1 VALUES(1, randomblob(400));
+  PRAGMA journal_mode = wal;
+  WITH s(i) AS (
+    SELECT 2 UNION ALL SELECT i+1 FROM s WHERE i<100
+  ) 
+  INSERT INTO t1 SELECT i, randomblob(400) FROM s;
+} {wal}
+
+do_test 1.1 {
+  execsql {
+    BEGIN;
+      SELECT count(*) FROM t1;
+  }
+} {100}
+
+do_test 1.2 {
+  db2 eval { 
+    SELECT count(*) FROM t1;
+    CREATE TABLE t2(x); 
+  }
+} {100}
+
+do_test 1.3 {
+  set ::snap [sqlite3_snapshot_get_blob db main]
+  db2 eval { PRAGMA wal_checkpoint }
+} {0 54 52}
+
+do_test 1.4 {
+  execsql {
+    COMMIT;
+    SELECT * FROM sqlite_master;
+    BEGIN;
+  }
+  sqlite3_snapshot_open_blob db main $::snap
+  execsql {
+    SELECT count(*) FROM t1
+  } 
+} {100}
+
+
+finish_test
+

From 79931a1517c7d38684a8de7c1021bce41458723a Mon Sep 17 00:00:00 2001
From: drh 
Date: Tue, 28 Aug 2018 15:51:10 +0000
Subject: [PATCH 20/33] Fix new issues in the geopoly module discovered by TH3.

FossilOrigin-Name: 22fff9afc2fb20906173f258aa8feae9b52acc69a0ca7baf4e914d29c4279a23
---
 ext/rtree/geopoly.c | 27 ++++++++++++++++++---------
 manifest            | 14 +++++++-------
 manifest.uuid       |  2 +-
 3 files changed, 26 insertions(+), 17 deletions(-)

diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c
index 3af3d32612..c2ecb62a63 100644
--- a/ext/rtree/geopoly.c
+++ b/ext/rtree/geopoly.c
@@ -187,9 +187,10 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
 }
 
 /*
-** If the input is a well-formed JSON array of coordinates, where each
-** coordinate is itself a two-value array, then convert the JSON into
-** a GeoPoly object and return a pointer to that object.
+** If the input is a well-formed JSON array of coordinates with at least
+** four coordinates and where each coordinate is itself a two-value array,
+** then convert the JSON into a GeoPoly object and return a pointer to
+** that object.
 **
 ** If any error occurs, return NULL.
 */
@@ -221,7 +222,7 @@ static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){
         c = geopolySkipSpace(&s);
         s.z++;
         if( c==',' ) continue;
-        if( c==']' ) break;
+        if( c==']' && ii>=2 ) break;
         s.nErr++;
         rc = SQLITE_ERROR;
         goto parse_json_err;
@@ -232,7 +233,10 @@ static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){
       }
       break;
     }
-    if( geopolySkipSpace(&s)==']' && s.nVertex>=4 ){
+    if( geopolySkipSpace(&s)==']'
+     && s.nVertex>=4
+     && (s.z++, geopolySkipSpace(&s)==0)
+    ){
       int nByte;
       GeoPoly *pOut;
       int x = (s.nVertex-1)*2;
@@ -305,7 +309,7 @@ static GeoPoly *geopolyFuncParam(
   }else if( sqlite3_value_type(pVal)==SQLITE_TEXT ){
     return geopolyParseJson(sqlite3_value_text(pVal), pRc);
   }else{
-    *pRc = SQLITE_ERROR;
+    if( pRc ) *pRc = SQLITE_ERROR;
     if( pCtx!=0 ) sqlite3_result_error(pCtx, "not a valid polygon", -1);
     return 0;
   }
@@ -1173,7 +1177,7 @@ static int geopolyFilter(
       assert( argc==1 );
       geopolyBBox(0, argv[0], bbox, &rc);
       if( rc ){
-        return rc;
+        goto geopoly_filter_end;
       }
       pCsr->aConstraint = p = sqlite3_malloc(sizeof(RtreeConstraint)*4);
       pCsr->nConstraint = 4;
@@ -1222,7 +1226,10 @@ static int geopolyFilter(
     if( rc==SQLITE_OK ){
       RtreeSearchPoint *pNew;
       pNew = rtreeSearchPointNew(pCsr, RTREE_ZERO, (u8)(pRtree->iDepth+1));
-      if( pNew==0 ) return SQLITE_NOMEM;
+      if( pNew==0 ){
+        rc = SQLITE_NOMEM;
+        goto geopoly_filter_end;
+      }
       pNew->id = 1;
       pNew->iCell = 0;
       pNew->eWithin = PARTLY_WITHIN;
@@ -1234,6 +1241,7 @@ static int geopolyFilter(
     }
   }
 
+geopoly_filter_end:
   nodeRelease(pRtree, pRoot);
   rtreeRelease(pRtree);
   return rc;
@@ -1402,7 +1410,7 @@ static int geopolyUpdate(
         pVtab->zErrMsg =
           sqlite3_mprintf("_shape does not contain a valid polygon");
       }
-      return rc;
+      goto geopoly_update_end;
     }
     coordChange = 1;
 
@@ -1472,6 +1480,7 @@ static int geopolyUpdate(
     }
   }
 
+geopoly_update_end:
   rtreeRelease(pRtree);
   return rc;
 }
diff --git a/manifest b/manifest
index 6c13150b7e..55ecf735f3 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\sproblem\scausing\sspurious\sSQLITE_CORRUPT\serrors\swhen\susing\sthe\ssnapshot\nAPI\sto\sread\sfrom\sold\sdatabase\ssnapshots.
-D 2018-08-28T11:23:52.641
+C Fix\snew\sissues\sin\sthe\sgeopoly\smodule\sdiscovered\sby\sTH3.
+D 2018-08-28T15:51:10.106
 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 01343c633cf59893abc0797571dbfe50d116a6474743941ba46b09ad085df271
+F ext/rtree/geopoly.c 00e0cc341affcf65afd3449ce71ec45de106463e9d98b3248509e2c9499e50c8
 F ext/rtree/rtree.c f3c2f1b5eea75b98d4d3dcdec2ebf2a69c036b53f2f3d196e61bf5016298255f
 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349
@@ -1758,7 +1758,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 666133e32ca8e95807f8437dc8401bc93e2e6508ab8e6ae1e6031b7cee1584ae
-R 64c8500a3b3b1576c0a05df68a2057d2
-U dan
-Z 4febad62a4c0de1b34fab12b530aa165
+P 535155be584ad8c1836e6b1c62de836d9872056d39608c995221c928cb5b365d
+R 89e303590eb89c7b3ebe8848db3ad489
+U drh
+Z 6ec3cd71799cdaf9a300185233e89b80
diff --git a/manifest.uuid b/manifest.uuid
index fd0023fa92..ecce3f9f6a 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-535155be584ad8c1836e6b1c62de836d9872056d39608c995221c928cb5b365d
\ No newline at end of file
+22fff9afc2fb20906173f258aa8feae9b52acc69a0ca7baf4e914d29c4279a23
\ No newline at end of file

From 58726ca4b949c210fdbfbeb26fd449aacee4432a Mon Sep 17 00:00:00 2001
From: drh 
Date: Tue, 28 Aug 2018 19:23:41 +0000
Subject: [PATCH 21/33] Stricter enforcement of the JSON and GeoJSON standards
 in the Geopoly extension.

FossilOrigin-Name: c0bf3ff3af4d34ef7801c16e39128e894b00699313f4915f57aa73b57642f7fd
---
 ext/rtree/geopoly.c | 27 ++++++++++++++++-----------
 manifest            | 12 ++++++------
 manifest.uuid       |  2 +-
 3 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c
index c2ecb62a63..88cad4a172 100644
--- a/ext/rtree/geopoly.c
+++ b/ext/rtree/geopoly.c
@@ -148,15 +148,14 @@ static char geopolySkipSpace(GeoParse *p){
 static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
   char c = geopolySkipSpace(p);
   const unsigned char *z = p->z;
-  int j;
+  int j = 0;
   int seenDP = 0;
   int seenE = 0;
-  assert( '-' < '0' );
-  if( c<='0' ){
-    j = c=='-';
-    if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0;
+  if( c=='-' ){
+    j = 1;
+    c = z[j];
   }
-  j = 1;
+  if( c=='0' && z[j+1]>='0' && z[j+1]<='9' ) return 0;
   for(;; j++){
     c = z[j];
     if( c>='0' && c<='9' ) continue;
@@ -235,13 +234,15 @@ static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){
     }
     if( geopolySkipSpace(&s)==']'
      && s.nVertex>=4
+     && s.a[0]==s.a[s.nVertex*2-2]
+     && s.a[1]==s.a[s.nVertex*2-1]
      && (s.z++, geopolySkipSpace(&s)==0)
     ){
       int nByte;
       GeoPoly *pOut;
-      int x = (s.nVertex-1)*2;
-      if( s.a[x]==s.a[0] && s.a[x+1]==s.a[1] ) s.nVertex--;
-      nByte = sizeof(GeoPoly) * (s.nVertex-1)*2*sizeof(GeoCoord);
+      int x = 1;
+      s.nVertex--;  /* Remove the redundant vertex at the end */
+      nByte = sizeof(GeoPoly) * s.nVertex*2*sizeof(GeoCoord);
       pOut = sqlite3_malloc64( nByte );
       x = 1;
       if( pOut==0 ) goto parse_json_err;
@@ -307,10 +308,14 @@ static GeoPoly *geopolyFuncParam(
     if( pRc ) *pRc = SQLITE_OK;
     return p;
   }else if( sqlite3_value_type(pVal)==SQLITE_TEXT ){
-    return geopolyParseJson(sqlite3_value_text(pVal), pRc);
+    const unsigned char *zJson = sqlite3_value_text(pVal);
+    if( zJson==0 ){
+      if( pRc ) *pRc = SQLITE_NOMEM;
+      return 0;
+    }
+    return geopolyParseJson(zJson, pRc);
   }else{
     if( pRc ) *pRc = SQLITE_ERROR;
-    if( pCtx!=0 ) sqlite3_result_error(pCtx, "not a valid polygon", -1);
     return 0;
   }
 }
diff --git a/manifest b/manifest
index 55ecf735f3..ea4b6c857b 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\snew\sissues\sin\sthe\sgeopoly\smodule\sdiscovered\sby\sTH3.
-D 2018-08-28T15:51:10.106
+C Stricter\senforcement\sof\sthe\sJSON\sand\sGeoJSON\sstandards\sin\sthe\sGeopoly\sextension.
+D 2018-08-28T19:23:41.917
 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 00e0cc341affcf65afd3449ce71ec45de106463e9d98b3248509e2c9499e50c8
+F ext/rtree/geopoly.c 3b27e2e493d15697b39f5c2e722f86b5c2913fa662152e34614df9cf8bc2e112
 F ext/rtree/rtree.c f3c2f1b5eea75b98d4d3dcdec2ebf2a69c036b53f2f3d196e61bf5016298255f
 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412
 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349
@@ -1758,7 +1758,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 535155be584ad8c1836e6b1c62de836d9872056d39608c995221c928cb5b365d
-R 89e303590eb89c7b3ebe8848db3ad489
+P 22fff9afc2fb20906173f258aa8feae9b52acc69a0ca7baf4e914d29c4279a23
+R 9b08441f72c4a920b4c5ba9dc3c04bb3
 U drh
-Z 6ec3cd71799cdaf9a300185233e89b80
+Z d1b541ea432c030d051deb7fc1efc1dc
diff --git a/manifest.uuid b/manifest.uuid
index ecce3f9f6a..38c7ccf3be 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-22fff9afc2fb20906173f258aa8feae9b52acc69a0ca7baf4e914d29c4279a23
\ No newline at end of file
+c0bf3ff3af4d34ef7801c16e39128e894b00699313f4915f57aa73b57642f7fd
\ No newline at end of file

From 8ab114c6a914ad4bb5e0ae44338144184787beed Mon Sep 17 00:00:00 2001
From: drh 
Date: Tue, 28 Aug 2018 21:12:02 +0000
Subject: [PATCH 22/33] Disable the server1.test script on old PPC Macs due to
 problems in the pthreads implementation on those archaic machines.

FossilOrigin-Name: 43efdd8c7e468405c9d4956a8caa66548059499289cbcc091628de7b055268cd
---
 manifest          | 12 ++++++------
 manifest.uuid     |  2 +-
 test/server1.test |  9 +++++++++
 3 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/manifest b/manifest
index ea4b6c857b..87b80a42e6 100644
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Stricter\senforcement\sof\sthe\sJSON\sand\sGeoJSON\sstandards\sin\sthe\sGeopoly\sextension.
-D 2018-08-28T19:23:41.917
+C Disable\sthe\sserver1.test\sscript\son\sold\sPPC\sMacs\sdue\sto\sproblems\sin\sthe\npthreads\simplementation\son\sthose\sarchaic\smachines.
+D 2018-08-28T21:12:02.935
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f
@@ -1238,7 +1238,7 @@ F test/selectD.test fc20452847a01775710090383cfb4423275d2f745fed61f34fbf37573ac0
 F test/selectE.test a8730ca330fcf40ace158f134f4fe0eb00c7edbf
 F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3
 F test/selectG.test 089f7d3d7e6db91566f00b036cb353107a2cca6220eb1cb264085a836dae8840
-F test/server1.test 46803bd3fe8b99b30dbc5ff38ffc756f5c13a118
+F test/server1.test c2b00864514a68a0e6fd518659dc95d0050307a357a08969872bef027d785dc4
 F test/session.test 78fa2365e93d3663a6e933f86e7afc395adf18be
 F test/sessionfuzz-data1.db 1f8d5def831f19b1c74571037f0d53a588ea49a6c4ca2a028fc0c27ef896dbcb
 F test/sessionfuzz.c b0fcdcf757451957e17396a3af5171f1fdf9b2babc81da9fa35675df46c4729a
@@ -1758,7 +1758,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 22fff9afc2fb20906173f258aa8feae9b52acc69a0ca7baf4e914d29c4279a23
-R 9b08441f72c4a920b4c5ba9dc3c04bb3
+P c0bf3ff3af4d34ef7801c16e39128e894b00699313f4915f57aa73b57642f7fd
+R 95abfcfab7ce38adddfe464609758ff7
 U drh
-Z d1b541ea432c030d051deb7fc1efc1dc
+Z c51195c228691c481dc919d190eb15c7
diff --git a/manifest.uuid b/manifest.uuid
index 38c7ccf3be..e7f7dc28b8 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-c0bf3ff3af4d34ef7801c16e39128e894b00699313f4915f57aa73b57642f7fd
\ No newline at end of file
+43efdd8c7e468405c9d4956a8caa66548059499289cbcc091628de7b055268cd
\ No newline at end of file
diff --git a/test/server1.test b/test/server1.test
index 90673ef000..c809217094 100644
--- a/test/server1.test
+++ b/test/server1.test
@@ -26,6 +26,15 @@ if {[llength [info command client_step]]==0 || [sqlite3 -has-codec]} {
   return
 }
 
+# This test does not work on older PPC Macs due to problems in the
+# pthreads library.  So skip it.
+#
+if {$tcl_platform(machine)=="Power Macintosh" && 
+    $tcl_platform(byteOrder)=="bigEndian"} {
+  finish_test
+  return
+}
+
 # The sample server implementation does not work right when memory
 # management is enabled.
 #

From c0d2117f1ceeb4cfe5e406831722523d696274f5 Mon Sep 17 00:00:00 2001
From: drh 
Date: Wed, 29 Aug 2018 15:50:47 +0000
Subject: [PATCH 23/33] Add the geopoly_group_bbox() aggregate function to the
 Geopoly module.

FossilOrigin-Name: 2d4debccbc027405a33aeb10f9d65f6fe4bfb5eb1be5a4d8b82158caba04643f
---
 ext/rtree/geopoly.c    | 95 ++++++++++++++++++++++++++++++++++++++----
 ext/rtree/visual01.txt | 22 ++++++++++
 manifest               | 14 +++----
 manifest.uuid          |  2 +-
 4 files changed, 117 insertions(+), 16 deletions(-)

diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c
index 88cad4a172..70beffd7d1 100644
--- a/ext/rtree/geopoly.c
+++ b/ext/rtree/geopoly.c
@@ -477,9 +477,14 @@ static void geopolyAreaFunc(
 }
 
 /*
-** Compute a bound-box on a polygon.  Return a new GeoPoly object
-** that describes the bounding box.  Or, if aCoord is not a NULL pointer
-** fill it in with the bounding box instead.
+** If pPoly is a polygon, compute its bounding box. Then:
+**
+**    (1) if aCoord!=0 store the bounding box in aCoord, returning NULL
+**    (2) otherwise, compute a GeoPoly for the bounding box and return the
+**        new GeoPoly
+**
+** If pPoly is NULL but aCoord is not NULL, then compute a new GeoPoly from
+** the bounding box in aCoord and return a pointer to that GeoPoly.
 */
 static GeoPoly *geopolyBBox(
   sqlite3_context *context,   /* For recording the error */
@@ -487,11 +492,21 @@ static GeoPoly *geopolyBBox(
   RtreeCoord *aCoord,         /* Results here */
   int *pRc                    /* Error code here */
 ){
-  GeoPoly *p = geopolyFuncParam(context, pPoly, pRc);
   GeoPoly *pOut = 0;
+  GeoPoly *p;
+  float mnX, mxX, mnY, mxY;
+  if( pPoly==0 && aCoord!=0 ){
+    p = 0;
+    mnX = aCoord[0].f;
+    mxX = aCoord[1].f;
+    mnY = aCoord[2].f;
+    mxY = aCoord[3].f;
+    goto geopolyBboxFill;
+  }else{
+    p = geopolyFuncParam(context, pPoly, pRc);
+  }
   if( p ){
     int ii;
-    float mnX, mxX, mnY, mxY;
     mnX = mxX = p->a[0];
     mnY = mxY = p->a[1];
     for(ii=1; iinVertex; ii++){
@@ -504,6 +519,7 @@ static GeoPoly *geopolyBBox(
     }
     if( pRc ) *pRc = SQLITE_OK;
     if( aCoord==0 ){
+      geopolyBboxFill:
       pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6);
       if( pOut==0 ){
         sqlite3_free(p);
@@ -512,6 +528,8 @@ static GeoPoly *geopolyBBox(
         return 0;
       }
       pOut->nVertex = 4;
+      ii = 1;
+      pOut->hdr[0] = *(unsigned char*)ⅈ
       pOut->hdr[1] = 0;
       pOut->hdr[2] = 0;
       pOut->hdr[3] = 4;
@@ -550,6 +568,58 @@ static void geopolyBBoxFunc(
   }
 }
 
+/*
+** State vector for the geopoly_group_bbox() aggregate function.
+*/
+typedef struct GeoBBox GeoBBox;
+struct GeoBBox {
+  int isInit;
+  RtreeCoord a[4];
+};
+
+
+/*
+** Implementation of the geopoly_group_bbox(X) aggregate SQL function.
+*/
+static void geopolyBBoxStep(
+  sqlite3_context *context,
+  int argc,
+  sqlite3_value **argv
+){
+  RtreeCoord a[4];
+  int rc = SQLITE_OK;
+  (void)geopolyBBox(context, argv[0], a, &rc);
+  if( rc==SQLITE_OK ){
+    GeoBBox *pBBox;
+    pBBox = (GeoBBox*)sqlite3_aggregate_context(context, sizeof(*pBBox));
+    if( pBBox==0 ) return;
+    if( pBBox->isInit==0 ){
+      pBBox->isInit = 1;
+      memcpy(pBBox->a, a, sizeof(RtreeCoord)*4);
+    }else{
+      if( a[0].f < pBBox->a[0].f ) pBBox->a[0] = a[0];
+      if( a[1].f > pBBox->a[1].f ) pBBox->a[1] = a[1];
+      if( a[2].f < pBBox->a[2].f ) pBBox->a[2] = a[2];
+      if( a[3].f > pBBox->a[3].f ) pBBox->a[3] = a[3];
+    }
+  }
+}
+static void geopolyBBoxFinal(
+  sqlite3_context *context
+){
+  GeoPoly *p;
+  GeoBBox *pBBox;
+  pBBox = (GeoBBox*)sqlite3_aggregate_context(context, 0);
+  if( pBBox==0 ) return;
+  p = geopolyBBox(context, 0, pBBox->a, 0);
+  if( p ){
+    sqlite3_result_blob(context, p->hdr, 
+       4+8*p->nVertex, SQLITE_TRANSIENT);
+    sqlite3_free(p);
+  }
+}
+
+
 /*
 ** Determine if point (x0,y0) is beneath line segment (x1,y1)->(x2,y2).
 ** Returns:
@@ -1057,7 +1127,7 @@ static int geopolyInit(
     pRtree->nAux++;
     sqlite3_str_appendf(pSql, ",%s", argv[ii]);
   }
-  sqlite3_str_appendf(pSql, ",_bbox HIDDEN);");
+  sqlite3_str_appendf(pSql, ");");
   zSql = sqlite3_str_finish(pSql);
   if( !zSql ){
     rc = SQLITE_NOMEM;
@@ -1345,8 +1415,6 @@ static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
       }
     }
     sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pReadAux, i+2));
-  }else{
-    /* Must be the _bbox column */
   }
   return SQLITE_OK;
 }
@@ -1559,12 +1627,23 @@ static int sqlite3_geopoly_init(sqlite3 *db){
      { geopolyBBoxFunc,          1,    "geopoly_bbox"             },
      { geopolyXformFunc,         7,    "geopoly_xform"            },
   };
+  static const struct {
+    void (*xStep)(sqlite3_context*,int,sqlite3_value**);
+    void (*xFinal)(sqlite3_context*);
+    const char *zName;
+  } aAgg[] = {
+     { geopolyBBoxStep, geopolyBBoxFinal, "geopoly_group_bbox"    },
+  };
   int i;
   for(i=0; i'
 
+.print '

Overlap Query And Result Bounding Box

' +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) + ) + FROM geo1, querypoly + WHERE geopoly_overlap(_shape, poly); +SELECT geopoly_svg(geopoly_bbox(poly), + 'style="fill:none;stroke:black;stroke-width:3"' + ) + FROM querypoly; +SELECT geopoly_svg(poly, + printf('style="fill:%s;fill-opacity:0.5;"',clr) + ) + FROM querypoly; +SELECT geopoly_svg(geopoly_group_bbox(_shape), + 'style="fill:none;stroke:red;stroke-width:3"' + ) + FROM geo1, querypoly + WHERE geopoly_overlap(_shape, poly); +.print '' + .print '

Bounding-Box Overlap Query

' .print '' SELECT geopoly_svg(_shape, diff --git a/manifest b/manifest index 87b80a42e6..c52c96c754 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Disable\sthe\sserver1.test\sscript\son\sold\sPPC\sMacs\sdue\sto\sproblems\sin\sthe\npthreads\simplementation\son\sthose\sarchaic\smachines. -D 2018-08-28T21:12:02.935 +C Add\sthe\sgeopoly_group_bbox()\saggregate\sfunction\sto\sthe\sGeopoly\smodule. +D 2018-08-29T15:50:47.314 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 3b27e2e493d15697b39f5c2e722f86b5c2913fa662152e34614df9cf8bc2e112 +F ext/rtree/geopoly.c 0f1fda44b4515d2ab388f997593ac5030ff2023c6ae36fef3ca01b5bf7769e90 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 a3bc394ac37a031d8eda690fa35a6532717df2ae54cd066e1b8f45566b0a8650 +F ext/rtree/visual01.txt 6f2fdbde3a163034a47f007c43c7b5d52952a99d8258d6aafc3d87879e904e4a F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a F ext/session/session1.test 4532116484f525110eb4cfff7030c59354c0cde9def4d109466b0df2b35ad5cc F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0 @@ -1758,7 +1758,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 c0bf3ff3af4d34ef7801c16e39128e894b00699313f4915f57aa73b57642f7fd -R 95abfcfab7ce38adddfe464609758ff7 +P 43efdd8c7e468405c9d4956a8caa66548059499289cbcc091628de7b055268cd +R 67d74f447410c9c096d1d977e8daccbd U drh -Z c51195c228691c481dc919d190eb15c7 +Z b43229d61c5d2506dfee2bf7cbf08d25 diff --git a/manifest.uuid b/manifest.uuid index e7f7dc28b8..4cfef93773 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -43efdd8c7e468405c9d4956a8caa66548059499289cbcc091628de7b055268cd \ No newline at end of file +2d4debccbc027405a33aeb10f9d65f6fe4bfb5eb1be5a4d8b82158caba04643f \ No newline at end of file From 72f56ef95dbed75685221e0018c63e90798a9fd8 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 29 Aug 2018 18:47:22 +0000 Subject: [PATCH 24/33] Free up the MEM_Frame bit in Mem.flags object. Store VdbeFrame objects as MEM_Blob with a special Mem.xDel pointer instead. FossilOrigin-Name: 62db5fd47660bbc4fcf2c6d4a6c5a3077f12c6442a128d22b66b789a0409ef32 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/vdbe.c | 14 ++++++++++---- src/vdbeInt.h | 21 +++++++++++++++++---- src/vdbeaux.c | 34 ++++++++++++++++++++++++++++++++-- src/vdbemem.c | 6 +----- 6 files changed, 70 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index c52c96c754..f073df776b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sgeopoly_group_bbox()\saggregate\sfunction\sto\sthe\sGeopoly\smodule. -D 2018-08-29T15:50:47.314 +C Free\sup\sthe\sMEM_Frame\sbit\sin\sMem.flags\sobject.\s\sStore\sVdbeFrame\sobjects\nas\sMEM_Blob\swith\sa\sspecial\sMem.xDel\spointer\sinstead. +D 2018-08-29T18:47:22.883 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f @@ -571,13 +571,13 @@ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157 F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855 -F src/vdbe.c b11baa48b293dc48fbd51c6a9029f88bdf4cd117c01225b2a2b5e90e5928a8a3 +F src/vdbe.c a44a1cd246f808d36ee0ce7dc031d9624a50242db96ac57f65ad93aea65ceaac F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907 -F src/vdbeInt.h 8ea493d994c6697cf7bccc60583a80a0222560490410f60f1113e90d36643ce0 +F src/vdbeInt.h a660268d9e60dcd60abe8768c1582dd35f3d174ad12f742aee8c805af72dac03 F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611 -F src/vdbeaux.c b64c699261611e3921de8bdf5a69d5559f0d1443dab8c4ba8e81a64d9219ac6a +F src/vdbeaux.c 20da0273e9bdb3f49dafa71123d7bdd63b2656134ecd73123562c028847d0e07 F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 -F src/vdbemem.c 0dc99941388a867a4dc77a8bed5dfc6024ee9c3ef147a09de844a6629086ec0c +F src/vdbemem.c 9a9aa4262f2c5620a552ad83902379d9b1dbb792eb4c1e8758ffffa7ab8a2e64 F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392 F src/vtab.c 678992ac8ec677a3f9b08126aaf891441083805e3b42574e3654d44538381c14 @@ -1758,7 +1758,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 43efdd8c7e468405c9d4956a8caa66548059499289cbcc091628de7b055268cd -R 67d74f447410c9c096d1d977e8daccbd +P 2d4debccbc027405a33aeb10f9d65f6fe4bfb5eb1be5a4d8b82158caba04643f +R bd76e3ebc281873295239e9b6605a092 U drh -Z b43229d61c5d2506dfee2bf7cbf08d25 +Z 6a1519aefdfc6d3a0da507442f0a767b diff --git a/manifest.uuid b/manifest.uuid index 4cfef93773..78a4375395 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2d4debccbc027405a33aeb10f9d65f6fe4bfb5eb1be5a4d8b82158caba04643f \ No newline at end of file +62db5fd47660bbc4fcf2c6d4a6c5a3077f12c6442a128d22b66b789a0409ef32 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 9e5f9705bc..888bb4444a 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -6050,7 +6050,7 @@ case OP_Program: { /* jump */ ** of the current program, and the memory required at runtime to execute ** the trigger program. If this trigger has been fired before, then pRt ** is already allocated. Otherwise, it must be initialized. */ - if( (pRt->flags&MEM_Frame)==0 ){ + if( (pRt->flags&MEM_Blob)==0 ){ /* SubProgram.nMem is set to the number of memory cells used by the ** program stored in SubProgram.aOp. As well as these, one memory ** cell is required for each cursor used by the program. Set local @@ -6068,8 +6068,10 @@ case OP_Program: { /* jump */ goto no_mem; } sqlite3VdbeMemRelease(pRt); - pRt->flags = MEM_Frame; - pRt->u.pFrame = pFrame; + pRt->flags = MEM_Blob|MEM_Dyn; + pRt->z = (char*)pFrame; + pRt->n = nByte; + pRt->xDel = sqlite3VdbeFrameMemDel; pFrame->v = p; pFrame->nChildMem = nMem; @@ -6085,6 +6087,9 @@ case OP_Program: { /* jump */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS pFrame->anExec = p->anExec; #endif +#ifdef SQLITE_DEBUG + pFrame->iFrameMagic = SQLITE_FRAME_MAGIC; +#endif pEnd = &VdbeFrameMem(pFrame)[pFrame->nChildMem]; for(pMem=VdbeFrameMem(pFrame); pMem!=pEnd; pMem++){ @@ -6092,7 +6097,8 @@ case OP_Program: { /* jump */ pMem->db = db; } }else{ - pFrame = pRt->u.pFrame; + pFrame = (VdbeFrame*)pRt->z; + assert( pRt->xDel==sqlite3VdbeFrameMemDel ); assert( pProgram->nMem+pProgram->nCsr==pFrame->nChildMem || (pProgram->nCsr==0 && pProgram->nMem+1==pFrame->nChildMem) ); assert( pProgram->nCsr==pFrame->nChildCsr ); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index a15b29a033..fe0875876f 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -169,6 +169,9 @@ struct VdbeFrame { void *token; /* Copy of SubProgram.token */ i64 lastRowid; /* Last insert rowid (sqlite3.lastRowid) */ AuxData *pAuxData; /* Linked list of auxdata allocations */ +#if SQLITE_DEBUG + u32 iFrameMagic; /* magic number for sanity checking */ +#endif int nCursor; /* Number of entries in apCsr */ int pc; /* Program Counter in parent (calling) frame */ int nOp; /* Size of aOp array */ @@ -179,6 +182,13 @@ struct VdbeFrame { int nDbChange; /* Value of db->nChange */ }; +/* Magic number for sanity checking on VdbeFrame objects */ +#define SQLITE_FRAME_MAGIC 0x879fb71e + +/* +** Return a pointer to the array of registers allocated for use +** by a VdbeFrame. +*/ #define VdbeFrameMem(p) ((Mem *)&((u8 *)p)[ROUND8(sizeof(VdbeFrame))]) /* @@ -194,7 +204,6 @@ struct sqlite3_value { const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ - VdbeFrame *pFrame; /* Used when flags==MEM_Frame */ } u; u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ @@ -239,7 +248,7 @@ struct sqlite3_value { #define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_AffMask 0x001f /* Mask of affinity bits */ #define MEM_RowSet 0x0020 /* Value is a RowSet object */ -#define MEM_Frame 0x0040 /* Value is a VdbeFrame object */ +/* Available 0x0040 */ #define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ #define MEM_TypeMask 0xc1ff /* Mask of type bits */ @@ -266,7 +275,7 @@ struct sqlite3_value { ** that needs to be deallocated to avoid a leak. */ #define VdbeMemDynamic(X) \ - (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet|MEM_Frame))!=0) + (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet))!=0) /* ** Clear any existing type flags from a Mem and replace them with f @@ -500,7 +509,11 @@ const char *sqlite3OpcodeName(int); int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); int sqlite3VdbeMemClearAndResize(Mem *pMem, int n); int sqlite3VdbeCloseStatement(Vdbe *, int); -void sqlite3VdbeFrameDelete(VdbeFrame*); +#ifdef SQLITE_DEBUG +int sqlite3VdbeFrameIsValid(VdbeFrame*); +#endif +void sqlite3VdbeFrameMemDel(void*); /* Destructor on Mem */ +void sqlite3VdbeFrameDelete(VdbeFrame*); /* Actually deletes the Frame */ int sqlite3VdbeFrameRestore(VdbeFrame *); #ifdef SQLITE_ENABLE_PREUPDATE_HOOK void sqlite3VdbePreUpdateHook(Vdbe*,VdbeCursor*,int,const char*,Table*,i64,int); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index f4708d6c34..ce763e9168 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1661,9 +1661,9 @@ static void releaseMemArray(Mem *p, int N){ */ testcase( p->flags & MEM_Agg ); testcase( p->flags & MEM_Dyn ); - testcase( p->flags & MEM_Frame ); + testcase( p->xDel==sqlite3VdbeFrameMemDel ); testcase( p->flags & MEM_RowSet ); - if( p->flags&(MEM_Agg|MEM_Dyn|MEM_Frame|MEM_RowSet) ){ + if( p->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet) ){ sqlite3VdbeMemRelease(p); }else if( p->szMalloc ){ sqlite3DbFreeNN(db, p->zMalloc); @@ -1675,6 +1675,35 @@ static void releaseMemArray(Mem *p, int N){ } } +#ifdef SQLITE_DEBUG +/* +** Verify that pFrame is a valid VdbeFrame pointer. Return true if it is +** and false if something is wrong. +** +** This routine is intended for use inside of assert() statements only. +*/ +int sqlite3VdbeFrameIsValid(VdbeFrame *pFrame){ + if( pFrame->iFrameMagic!=SQLITE_FRAME_MAGIC ) return 0; + return 1; +} +#endif + + +/* +** This is a destructor on a Mem object (which is really an sqlite3_value) +** that deletes the Frame object that is attached to it as a blob. +** +** This routine does not delete the Frame right away. It merely adds the +** frame to a list of frames to be deleted when the Vdbe halts. +*/ +void sqlite3VdbeFrameMemDel(void *pArg){ + VdbeFrame *pFrame = (VdbeFrame*)pArg; + assert( sqlite3VdbeFrameIsValid(pFrame) ); + pFrame->pParent = pFrame->v->pDelFrame; + pFrame->v->pDelFrame = pFrame; +} + + /* ** Delete a VdbeFrame object and its contents. VdbeFrame objects are ** allocated by the OP_Program opcode in sqlite3VdbeExec(). @@ -1683,6 +1712,7 @@ void sqlite3VdbeFrameDelete(VdbeFrame *p){ int i; Mem *aMem = VdbeFrameMem(p); VdbeCursor **apCsr = (VdbeCursor **)&aMem[p->nChildMem]; + assert( sqlite3VdbeFrameIsValid(p) ); for(i=0; inChildCsr; i++){ sqlite3VdbeFreeCursor(p->v, apCsr[i]); } diff --git a/src/vdbemem.c b/src/vdbemem.c index fc73212f06..ba3f13157a 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -43,7 +43,7 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){ if( p->flags & MEM_Null ){ /* Cannot be both MEM_Null and some other type */ assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob - |MEM_RowSet|MEM_Frame|MEM_Agg))==0 ); + |MEM_RowSet|MEM_Agg))==0 ); /* If MEM_Null is set, then either the value is a pure NULL (the usual ** case) or it is a pointer set using sqlite3_bind_pointer() or @@ -467,10 +467,6 @@ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){ p->xDel((void *)p->z); }else if( p->flags&MEM_RowSet ){ sqlite3RowSetClear(p->u.pRowSet); - }else if( p->flags&MEM_Frame ){ - VdbeFrame *pFrame = p->u.pFrame; - pFrame->pParent = pFrame->v->pDelFrame; - pFrame->v->pDelFrame = pFrame; } p->flags = MEM_Null; } From 9d67afc421b726ec02fb422deadee31247f6aac3 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 29 Aug 2018 20:24:03 +0000 Subject: [PATCH 25/33] Also free up the MEM_RowSet bit in the Mem.flags field and have RowSet objects be destroyed using Mem.xDel. This change results in faster code. FossilOrigin-Name: f48e9feb3fca514e4e586932e6d19a5e34a384204effeba553006dcddf5f13d2 --- manifest | 22 ++++++++-------- manifest.uuid | 2 +- src/rowset.c | 52 ++++++++++++++++++++----------------- src/sqliteInt.h | 5 ++-- src/vdbe.c | 26 +++++++++---------- src/vdbeInt.h | 10 +++++--- src/vdbeaux.c | 4 +-- src/vdbemem.c | 68 +++++++++++++++++++++++++++---------------------- 8 files changed, 101 insertions(+), 88 deletions(-) diff --git a/manifest b/manifest index f073df776b..0f6348fb6f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Free\sup\sthe\sMEM_Frame\sbit\sin\sMem.flags\sobject.\s\sStore\sVdbeFrame\sobjects\nas\sMEM_Blob\swith\sa\sspecial\sMem.xDel\spointer\sinstead. -D 2018-08-29T18:47:22.883 +C Also\sfree\sup\sthe\sMEM_RowSet\sbit\sin\sthe\sMem.flags\sfield\sand\shave\sRowSet\sobjects\nbe\sdestroyed\susing\sMem.xDel.\s\sThis\schange\sresults\sin\sfaster\scode. +D 2018-08-29T20:24:03.572 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f @@ -499,13 +499,13 @@ F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0 F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea -F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac +F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c ae7396a314cc1bb1d767947cd57094e3a9ffcbb155ebc1b1c391e028c44a9a04 F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f F src/sqlite.h.in 5a2d431493020c2c9f2f37c9119d6439444e3c44a714566a5192b6911ac917e6 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7 -F src/sqliteInt.h 2a670143a4f6b7d85958bac125e4d9d8ad14f016a3582e9d7c6907d9d50b75a0 +F src/sqliteInt.h 26e48f0c823844fcce67bd2a11ad1ad3468aaed32fd8864bc69c4147cb608728 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -571,13 +571,13 @@ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157 F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855 -F src/vdbe.c a44a1cd246f808d36ee0ce7dc031d9624a50242db96ac57f65ad93aea65ceaac +F src/vdbe.c 74671dff9ba856c5464557a8dbf2ba940fc4fa67efbceb32e262eedac31d86ca F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907 -F src/vdbeInt.h a660268d9e60dcd60abe8768c1582dd35f3d174ad12f742aee8c805af72dac03 +F src/vdbeInt.h f1f35f70460698d8f5a2bdef1001114babf318e2983a067804e2ae077d8e9827 F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611 -F src/vdbeaux.c 20da0273e9bdb3f49dafa71123d7bdd63b2656134ecd73123562c028847d0e07 +F src/vdbeaux.c 1ee77344fe9fd6ac11fae6f0150f81e0eadf349a9957340089cf82284e6b379a F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 -F src/vdbemem.c 9a9aa4262f2c5620a552ad83902379d9b1dbb792eb4c1e8758ffffa7ab8a2e64 +F src/vdbemem.c 81329ab760e4ec0162119d9cd10193e0303c45c5935bb20c7ae9139d44dd6641 F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392 F src/vtab.c 678992ac8ec677a3f9b08126aaf891441083805e3b42574e3654d44538381c14 @@ -1758,7 +1758,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 2d4debccbc027405a33aeb10f9d65f6fe4bfb5eb1be5a4d8b82158caba04643f -R bd76e3ebc281873295239e9b6605a092 +P 62db5fd47660bbc4fcf2c6d4a6c5a3077f12c6442a128d22b66b789a0409ef32 +R b874f6bc6fe7e6d492c17f3293f43632 U drh -Z 6a1519aefdfc6d3a0da507442f0a767b +Z e2bd09cc55c8cf3a3298f3d931f8e0b9 diff --git a/manifest.uuid b/manifest.uuid index 78a4375395..688e6449a1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -62db5fd47660bbc4fcf2c6d4a6c5a3077f12c6442a128d22b66b789a0409ef32 \ No newline at end of file +f48e9feb3fca514e4e586932e6d19a5e34a384204effeba553006dcddf5f13d2 \ No newline at end of file diff --git a/src/rowset.c b/src/rowset.c index aa81607b9f..703cf499bc 100644 --- a/src/rowset.c +++ b/src/rowset.c @@ -124,30 +124,23 @@ struct RowSet { #define ROWSET_NEXT 0x02 /* True if sqlite3RowSetNext() has been called */ /* -** Turn bulk memory into a RowSet object. N bytes of memory -** are available at pSpace. The db pointer is used as a memory context -** for any subsequent allocations that need to occur. -** Return a pointer to the new RowSet object. -** -** It must be the case that N is sufficient to make a Rowset. If not -** an assertion fault occurs. -** -** If N is larger than the minimum, use the surplus as an initial -** allocation of entries available to be filled. +** Allocate a RowSet object. Return NULL if a memory allocation +** error occurs. */ -RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){ - RowSet *p; - assert( N >= ROUND8(sizeof(*p)) ); - p = pSpace; - p->pChunk = 0; - p->db = db; - p->pEntry = 0; - p->pLast = 0; - p->pForest = 0; - p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); - p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); - p->rsFlags = ROWSET_SORTED; - p->iBatch = 0; +RowSet *sqlite3RowSetInit(sqlite3 *db){ + RowSet *p = sqlite3DbMallocRawNN(db, sizeof(*p)); + if( p ){ + int N = sqlite3DbMallocSize(db, p); + p->pChunk = 0; + p->db = db; + p->pEntry = 0; + p->pLast = 0; + p->pForest = 0; + p->pFresh = (struct RowSetEntry*)(ROUND8(sizeof(*p)) + (char*)p); + p->nFresh = (u16)((N - ROUND8(sizeof(*p)))/sizeof(struct RowSetEntry)); + p->rsFlags = ROWSET_SORTED; + p->iBatch = 0; + } return p; } @@ -156,7 +149,8 @@ RowSet *sqlite3RowSetInit(sqlite3 *db, void *pSpace, unsigned int N){ ** the RowSet has allocated over its lifetime. This routine is ** the destructor for the RowSet. */ -void sqlite3RowSetClear(RowSet *p){ +void sqlite3RowSetClear(void *pArg){ + RowSet *p = (RowSet*)pArg; struct RowSetChunk *pChunk, *pNextChunk; for(pChunk=p->pChunk; pChunk; pChunk = pNextChunk){ pNextChunk = pChunk->pNextChunk; @@ -170,6 +164,16 @@ void sqlite3RowSetClear(RowSet *p){ p->rsFlags = ROWSET_SORTED; } +/* +** Deallocate all chunks from a RowSet. This frees all memory that +** the RowSet has allocated over its lifetime. This routine is +** the destructor for the RowSet. +*/ +void sqlite3RowSetDelete(void *pArg){ + sqlite3RowSetClear(pArg); + sqlite3DbFree(((RowSet*)pArg)->db, pArg); +} + /* ** Allocate a new RowSetEntry object that is associated with the ** given RowSet. Return a pointer to the new and completely uninitialized diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 875f8fa692..78707ee371 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3825,8 +3825,9 @@ u32 sqlite3BitvecSize(Bitvec*); int sqlite3BitvecBuiltinTest(int,int*); #endif -RowSet *sqlite3RowSetInit(sqlite3*, void*, unsigned int); -void sqlite3RowSetClear(RowSet*); +RowSet *sqlite3RowSetInit(sqlite3*); +void sqlite3RowSetDelete(void*); +void sqlite3RowSetClear(void*); void sqlite3RowSetInsert(RowSet*, i64); int sqlite3RowSetTest(RowSet*, int iBatch, i64); int sqlite3RowSetNext(RowSet*, i64*); diff --git a/src/vdbe.c b/src/vdbe.c index 888bb4444a..7db4d83ccb 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -502,7 +502,7 @@ static void memTracePrint(Mem *p){ }else if( p->flags & MEM_Real ){ printf(" r:%g", p->u.r); #endif - }else if( p->flags & MEM_RowSet ){ + }else if( sqlite3VdbeMemIsRowSet(p) ){ printf(" (rowset)"); }else{ char zBuf[200]; @@ -5903,11 +5903,11 @@ case OP_RowSetAdd: { /* in1, in2 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; assert( (pIn2->flags & MEM_Int)!=0 ); - if( (pIn1->flags & MEM_RowSet)==0 ){ - sqlite3VdbeMemSetRowSet(pIn1); - if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem; + if( (pIn1->flags & MEM_Blob)==0 ){ + if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem; } - sqlite3RowSetInsert(pIn1->u.pRowSet, pIn2->u.i); + assert( sqlite3VdbeMemIsRowSet(pIn1) ); + sqlite3RowSetInsert((RowSet*)pIn1->z, pIn2->u.i); break; } @@ -5923,8 +5923,9 @@ case OP_RowSetRead: { /* jump, in1, out3 */ i64 val; pIn1 = &aMem[pOp->p1]; - if( (pIn1->flags & MEM_RowSet)==0 - || sqlite3RowSetNext(pIn1->u.pRowSet, &val)==0 + assert( (pIn1->flags & MEM_Blob)==0 || sqlite3VdbeMemIsRowSet(pIn1) ); + if( (pIn1->flags & MEM_Blob)==0 + || sqlite3RowSetNext((RowSet*)pIn1->z, &val)==0 ){ /* The boolean index is empty */ sqlite3VdbeMemSetNull(pIn1); @@ -5973,20 +5974,19 @@ case OP_RowSetTest: { /* jump, in1, in3 */ /* If there is anything other than a rowset object in memory cell P1, ** delete it now and initialize P1 with an empty rowset */ - if( (pIn1->flags & MEM_RowSet)==0 ){ - sqlite3VdbeMemSetRowSet(pIn1); - if( (pIn1->flags & MEM_RowSet)==0 ) goto no_mem; + if( (pIn1->flags & MEM_Blob)==0 ){ + if( sqlite3VdbeMemSetRowSet(pIn1) ) goto no_mem; } - + assert( sqlite3VdbeMemIsRowSet(pIn1) ); assert( pOp->p4type==P4_INT32 ); assert( iSet==-1 || iSet>=0 ); if( iSet ){ - exists = sqlite3RowSetTest(pIn1->u.pRowSet, iSet, pIn3->u.i); + exists = sqlite3RowSetTest((RowSet*)pIn1->z, iSet, pIn3->u.i); VdbeBranchTaken(exists!=0,2); if( exists ) goto jump_to_p2; } if( iSet>=0 ){ - sqlite3RowSetInsert(pIn1->u.pRowSet, pIn3->u.i); + sqlite3RowSetInsert((RowSet*)pIn1->z, pIn3->u.i); } break; } diff --git a/src/vdbeInt.h b/src/vdbeInt.h index fe0875876f..107e5cab44 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -203,7 +203,6 @@ struct sqlite3_value { int nZero; /* Extra zero bytes when MEM_Zero and MEM_Blob set */ const char *zPType; /* Pointer type when MEM_Term|MEM_Subtype|MEM_Null */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ - RowSet *pRowSet; /* Used only when flags==MEM_RowSet */ } u; u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ @@ -247,7 +246,7 @@ struct sqlite3_value { #define MEM_Real 0x0008 /* Value is a real number */ #define MEM_Blob 0x0010 /* Value is a BLOB */ #define MEM_AffMask 0x001f /* Mask of affinity bits */ -#define MEM_RowSet 0x0020 /* Value is a RowSet object */ +/* Available 0x0020 */ /* Available 0x0040 */ #define MEM_Undefined 0x0080 /* Value is undefined */ #define MEM_Cleared 0x0100 /* NULL set by OP_Null, not from data */ @@ -275,7 +274,7 @@ struct sqlite3_value { ** that needs to be deallocated to avoid a leak. */ #define VdbeMemDynamic(X) \ - (((X)->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet))!=0) + (((X)->flags&(MEM_Agg|MEM_Dyn))!=0) /* ** Clear any existing type flags from a Mem and replace them with f @@ -488,7 +487,10 @@ void sqlite3VdbeMemSetPointer(Mem*, void*, const char*, void(*)(void*)); void sqlite3VdbeMemInit(Mem*,sqlite3*,u16); void sqlite3VdbeMemSetNull(Mem*); void sqlite3VdbeMemSetZeroBlob(Mem*,int); -void sqlite3VdbeMemSetRowSet(Mem*); +#ifdef SQLITE_DEBUG +int sqlite3VdbeMemIsRowSet(const Mem*); +#endif +int sqlite3VdbeMemSetRowSet(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemStringify(Mem*, u8, u8); i64 sqlite3VdbeIntValue(Mem*); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index ce763e9168..3592e5ed48 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1663,7 +1663,7 @@ static void releaseMemArray(Mem *p, int N){ testcase( p->flags & MEM_Dyn ); testcase( p->xDel==sqlite3VdbeFrameMemDel ); testcase( p->flags & MEM_RowSet ); - if( p->flags&(MEM_Agg|MEM_Dyn|MEM_RowSet) ){ + if( p->flags&(MEM_Agg|MEM_Dyn) ){ sqlite3VdbeMemRelease(p); }else if( p->szMalloc ){ sqlite3DbFreeNN(db, p->zMalloc); @@ -3991,7 +3991,7 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ f1 = pMem1->flags; f2 = pMem2->flags; combined_flags = f1|f2; - assert( (combined_flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem1) && !sqlite3VdbeMemIsRowSet(pMem2) ); /* If one value is NULL, it is less than the other. If both values ** are NULL, return 0. diff --git a/src/vdbemem.c b/src/vdbemem.c index ba3f13157a..d204dc8d27 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -42,8 +42,7 @@ int sqlite3VdbeCheckMemInvariants(Mem *p){ if( p->flags & MEM_Null ){ /* Cannot be both MEM_Null and some other type */ - assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob - |MEM_RowSet|MEM_Agg))==0 ); + assert( (p->flags & (MEM_Int|MEM_Real|MEM_Str|MEM_Blob|MEM_Agg))==0 ); /* If MEM_Null is set, then either the value is a pure NULL (the usual ** case) or it is a pointer set using sqlite3_bind_pointer() or @@ -156,7 +155,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ #ifndef SQLITE_OMIT_UTF16 int rc; #endif - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE || desiredEnc==SQLITE_UTF16BE ); if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ @@ -189,7 +188,7 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ */ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){ assert( sqlite3VdbeCheckMemInvariants(pMem) ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); testcase( pMem->db==0 ); /* If the bPreserve flag is set to true, then the memory cell must already @@ -277,7 +276,7 @@ static SQLITE_NOINLINE int vdbeMemAddTerminator(Mem *pMem){ */ int sqlite3VdbeMemMakeWriteable(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); if( (pMem->flags & (MEM_Str|MEM_Blob))!=0 ){ if( ExpandBlob(pMem) ) return SQLITE_NOMEM; if( pMem->szMalloc==0 || pMem->z!=pMem->zMalloc ){ @@ -302,7 +301,7 @@ int sqlite3VdbeMemExpandBlob(Mem *pMem){ int nByte; assert( pMem->flags & MEM_Zero ); assert( pMem->flags&MEM_Blob ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); /* Set nByte to the number of bytes required to store the expanded blob. */ @@ -357,7 +356,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){ assert( !(fg&MEM_Zero) ); assert( !(fg&(MEM_Str|MEM_Blob)) ); assert( fg&(MEM_Int|MEM_Real) ); - assert( (pMem->flags&MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -462,11 +461,8 @@ static SQLITE_NOINLINE void vdbeMemClearExternAndSetNull(Mem *p){ testcase( p->flags & MEM_Dyn ); } if( p->flags&MEM_Dyn ){ - assert( (p->flags&MEM_RowSet)==0 ); assert( p->xDel!=SQLITE_DYNAMIC && p->xDel!=0 ); p->xDel((void *)p->z); - }else if( p->flags&MEM_RowSet ){ - sqlite3RowSetClear(p->u.pRowSet); } p->flags = MEM_Null; } @@ -614,7 +610,7 @@ int sqlite3VdbeBooleanValue(Mem *pMem, int ifNull){ void sqlite3VdbeIntegerAffinity(Mem *pMem){ i64 ix; assert( pMem->flags & MEM_Real ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); @@ -641,7 +637,7 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){ */ int sqlite3VdbeMemIntegerify(Mem *pMem){ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); assert( EIGHT_BYTE_ALIGNMENT(pMem) ); pMem->u.i = sqlite3VdbeIntValue(pMem); @@ -859,26 +855,36 @@ void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ } #endif +#ifdef SQLITE_DEBUG +/* +** Return true if the Mem holds a RowSet object. This routine is intended +** for use inside of assert() statements. +*/ +int sqlite3VdbeMemIsRowSet(const Mem *pMem){ + return (pMem->flags&(MEM_Blob|MEM_Dyn))==(MEM_Blob|MEM_Dyn) + && pMem->xDel==sqlite3RowSetDelete; +} +#endif + /* ** Delete any previous value and set the value of pMem to be an ** empty boolean index. +** +** Return SQLITE_OK on success and SQLITE_NOMEM if a memory allocation +** error occurs. */ -void sqlite3VdbeMemSetRowSet(Mem *pMem){ +int sqlite3VdbeMemSetRowSet(Mem *pMem){ sqlite3 *db = pMem->db; + RowSet *p; assert( db!=0 ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); sqlite3VdbeMemRelease(pMem); - pMem->zMalloc = sqlite3DbMallocRawNN(db, 64); - if( db->mallocFailed ){ - pMem->flags = MEM_Null; - pMem->szMalloc = 0; - }else{ - assert( pMem->zMalloc ); - pMem->szMalloc = sqlite3DbMallocSize(db, pMem->zMalloc); - pMem->u.pRowSet = sqlite3RowSetInit(db, pMem->zMalloc, pMem->szMalloc); - assert( pMem->u.pRowSet!=0 ); - pMem->flags = MEM_RowSet; - } + p = sqlite3RowSetInit(db); + if( p==0 ) return SQLITE_NOMEM; + pMem->z = (char*)p; + pMem->flags = MEM_Blob|MEM_Dyn; + pMem->xDel = sqlite3RowSetDelete; + return SQLITE_OK; } /* @@ -946,7 +952,7 @@ static SQLITE_NOINLINE void vdbeClrCopy(Mem *pTo, const Mem *pFrom, int eType){ sqlite3VdbeMemShallowCopy(pTo, pFrom, eType); } void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ - assert( (pFrom->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pFrom) ); assert( pTo->db==pFrom->db ); if( VdbeMemDynamic(pTo) ){ vdbeClrCopy(pTo,pFrom,srcType); return; } memcpy(pTo, pFrom, MEMCELLSIZE); @@ -964,7 +970,7 @@ void sqlite3VdbeMemShallowCopy(Mem *pTo, const Mem *pFrom, int srcType){ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ int rc = SQLITE_OK; - assert( (pFrom->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pFrom) ); if( VdbeMemDynamic(pTo) ) vdbeMemClearExternAndSetNull(pTo); memcpy(pTo, pFrom, MEMCELLSIZE); pTo->flags &= ~MEM_Dyn; @@ -1022,7 +1028,7 @@ int sqlite3VdbeMemSetStr( u16 flags = 0; /* New value for pMem->flags */ assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); /* If z is a NULL pointer, set pMem to contain an SQL NULL. */ if( !z ){ @@ -1144,7 +1150,7 @@ int sqlite3VdbeMemFromBtree( /* Note: the calls to BtreeKeyFetch() and DataFetch() below assert() ** that both the BtShared and database handle mutexes are held. */ - assert( (pMem->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pMem) ); zData = (char *)sqlite3BtreePayloadFetch(pCur, &available); assert( zData!=0 ); @@ -1168,7 +1174,7 @@ static SQLITE_NOINLINE const void *valueToText(sqlite3_value* pVal, u8 enc){ assert( pVal!=0 ); assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); - assert( (pVal->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pVal) ); assert( (pVal->flags & (MEM_Null))==0 ); if( pVal->flags & (MEM_Blob|MEM_Str) ){ if( ExpandBlob(pVal) ) return 0; @@ -1211,7 +1217,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ if( !pVal ) return 0; assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); - assert( (pVal->flags & MEM_RowSet)==0 ); + assert( !sqlite3VdbeMemIsRowSet(pVal) ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ assert( sqlite3VdbeMemConsistentDualRep(pVal) ); return pVal->z; From 17f19eadb82a2463c68f852ef7cb591cf61605a9 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 29 Aug 2018 20:52:40 +0000 Subject: [PATCH 26/33] Fixes to the UPDATE logic in Geopoly. FossilOrigin-Name: 7c3cee0a2a5ccacff27400c38bd708f7b9b968eb013a8fa685d876dfe85e12a6 --- ext/rtree/geopoly.c | 18 +++++++++++++----- ext/rtree/rtree.c | 7 ++++++- ext/rtree/visual01.txt | 36 ++++++++++++++++++++++++++++++++++++ manifest | 16 ++++++++-------- manifest.uuid | 2 +- 5 files changed, 64 insertions(+), 15 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 70beffd7d1..39629aee70 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -1122,7 +1122,8 @@ static int geopolyInit( */ pSql = sqlite3_str_new(db); sqlite3_str_appendf(pSql, "CREATE TABLE x(_shape"); - pRtree->nAux = 1; /* Add one for _shape */ + pRtree->nAux = 1; /* Add one for _shape */ + pRtree->nAuxNotNull = 1; /* The _shape column is always not-null */ for(ii=3; iinAux++; sqlite3_str_appendf(pSql, ",%s", argv[ii]); @@ -1396,6 +1397,7 @@ static int geopolyColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){ if( rc ) return rc; if( p==0 ) return SQLITE_OK; + if( i==0 && sqlite3_vtab_nochange(ctx) ) return SQLITE_OK; if( i<=pRtree->nAux ){ if( !pCsr->bAuxValid ){ if( pCsr->pReadAux==0 ){ @@ -1465,7 +1467,6 @@ static int geopolyUpdate( rtreeReference(pRtree); assert(nData>=1); - rc = SQLITE_ERROR; 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; @@ -1489,7 +1490,7 @@ static int geopolyUpdate( /* If a rowid value was supplied, check if it is already present in ** the table. If so, the constraint has failed. */ - if( newRowidValid ){ + if( newRowidValid && (!oldRowidValid || oldRowid!=newRowid) ){ int steprc; sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); steprc = sqlite3_step(pRtree->pReadRowid); @@ -1543,8 +1544,15 @@ static int geopolyUpdate( int jj; int nChange = 0; sqlite3_bind_int64(pUp, 1, cell.iRowid); - for(jj=0; jjnAux; jj++){ - if( !sqlite3_value_nochange(aData[jj+2]) ) nChange++; + assert( pRtree->nAux>=1 ); + if( sqlite3_value_nochange(aData[2]) ){ + sqlite3_bind_null(pUp, 2); + }else{ + sqlite3_bind_value(pUp, 2, aData[2]); + nChange = 1; + } + for(jj=1; jjnAux; jj++){ + nChange++; sqlite3_bind_value(pUp, jj+2, aData[jj+2]); } if( nChange ){ diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index 091c0bc6b4..06efdc71f4 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -127,6 +127,7 @@ struct Rtree { u8 nBytesPerCell; /* Bytes consumed per cell */ u8 inWrTrans; /* True if inside write transaction */ u8 nAux; /* # of auxiliary columns in %_rowid */ + u8 nAuxNotNull; /* Number of initial not-null aux columns */ int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ @@ -3453,7 +3454,11 @@ static int rtreeSqlInit( sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix); for(ii=0; iinAux; ii++){ if( ii ) sqlite3_str_append(p, ",", 1); - sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2); + if( iinAuxNotNull ){ + sqlite3_str_appendf(p,"a%d=coalesce(?%d,a%d)",ii,ii+2,ii); + }else{ + sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2); + } } sqlite3_str_appendf(p, " WHERE rowid=?1"); zSql = sqlite3_str_finish(p); diff --git a/ext/rtree/visual01.txt b/ext/rtree/visual01.txt index fc1b26a749..b1c808c665 100644 --- a/ext/rtree/visual01.txt +++ b/ext/rtree/visual01.txt @@ -536,4 +536,40 @@ SELECT geopoly_svg(poly, ) FROM querypoly; .print '' + +.print '

Color-Change For Overlapping Elements

' +BEGIN; +UPDATE geo1 + SET clr=CASE WHEN rowid IN (SELECT geo1.rowid FROM geo1, querypoly + WHERE geopoly_overlap(_shape,poly)) + THEN 'red' ELSE 'blue' END; +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) + ) + FROM geo1; +SELECT geopoly_svg(poly,'style="fill:none;stroke:black;stroke-width:2"') + FROM querypoly; +ROLLBACK; +.print '' + +.print '

Color-Change And Move Overlapping Elements

' +BEGIN; +UPDATE geo1 + SET clr=CASE WHEN rowid IN (SELECT geo1.rowid FROM geo1, querypoly + WHERE geopoly_overlap(_shape,poly)) + THEN 'red' ELSE 'blue' END; +UPDATE geo1 + SET _shape=geopoly_xform(_shape,1,0,0,1,300,0) + WHERE geopoly_overlap(_shape,(SELECT poly FROM querypoly)); +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) + ) + FROM geo1; +SELECT geopoly_svg(poly,'style="fill:none;stroke:black;stroke-width:2"') + FROM querypoly; +ROLLBACK; +.print '' + .print '' diff --git a/manifest b/manifest index 0f6348fb6f..c9093d9428 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Also\sfree\sup\sthe\sMEM_RowSet\sbit\sin\sthe\sMem.flags\sfield\sand\shave\sRowSet\sobjects\nbe\sdestroyed\susing\sMem.xDel.\s\sThis\schange\sresults\sin\sfaster\scode. -D 2018-08-29T20:24:03.572 +C Fixes\sto\sthe\sUPDATE\slogic\sin\sGeopoly. +D 2018-08-29T20:52:40.880 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f @@ -359,8 +359,8 @@ 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 0f1fda44b4515d2ab388f997593ac5030ff2023c6ae36fef3ca01b5bf7769e90 -F ext/rtree/rtree.c f3c2f1b5eea75b98d4d3dcdec2ebf2a69c036b53f2f3d196e61bf5016298255f +F ext/rtree/geopoly.c 8ed95c3233ea38b6688cda8c07685cb6bf6e6e0b14208bad343c12c9f8252d3f +F ext/rtree/rtree.c ce94cbb319423fd739702582dde47371aec8ad85207d517c41bdbf75a7ffd737 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349 F ext/rtree/rtree2.test 5f25b01acd03470067a2d52783b2eb0a50bf836803d4342d20ca39e541220fe2 @@ -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 6f2fdbde3a163034a47f007c43c7b5d52952a99d8258d6aafc3d87879e904e4a +F ext/rtree/visual01.txt e47922ab37af9589cd03aca33876fcc8eefef7c9a624e1960d14bdd2572e8d9e F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a F ext/session/session1.test 4532116484f525110eb4cfff7030c59354c0cde9def4d109466b0df2b35ad5cc F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0 @@ -1758,7 +1758,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 62db5fd47660bbc4fcf2c6d4a6c5a3077f12c6442a128d22b66b789a0409ef32 -R b874f6bc6fe7e6d492c17f3293f43632 +P f48e9feb3fca514e4e586932e6d19a5e34a384204effeba553006dcddf5f13d2 +R c11872ace9ae24cb28c40999f97e723f U drh -Z e2bd09cc55c8cf3a3298f3d931f8e0b9 +Z 581e01d30ec7f16b604718e3d6a88b37 diff --git a/manifest.uuid b/manifest.uuid index 688e6449a1..b6bf5f9d22 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f48e9feb3fca514e4e586932e6d19a5e34a384204effeba553006dcddf5f13d2 \ No newline at end of file +7c3cee0a2a5ccacff27400c38bd708f7b9b968eb013a8fa685d876dfe85e12a6 \ No newline at end of file From 9c1d7c6d4ce60c73e29daed1c005bb589f0cd74a Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 29 Aug 2018 21:01:22 +0000 Subject: [PATCH 27/33] Additional test cases for geopoly. FossilOrigin-Name: 19b5eb45e090c4b7169a52d881495ee2eafc59f80e3db2288fc1814ba76134ac --- ext/rtree/visual01.txt | 16 +++++++++++++++- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/ext/rtree/visual01.txt b/ext/rtree/visual01.txt index b1c808c665..90ae92403d 100644 --- a/ext/rtree/visual01.txt +++ b/ext/rtree/visual01.txt @@ -558,7 +558,7 @@ BEGIN; UPDATE geo1 SET clr=CASE WHEN rowid IN (SELECT geo1.rowid FROM geo1, querypoly WHERE geopoly_overlap(_shape,poly)) - THEN 'red' ELSE 'blue' END; + THEN 'red' ELSE '#76ccff' END; UPDATE geo1 SET _shape=geopoly_xform(_shape,1,0,0,1,300,0) WHERE geopoly_overlap(_shape,(SELECT poly FROM querypoly)); @@ -569,6 +569,20 @@ SELECT geopoly_svg(_shape, FROM geo1; SELECT geopoly_svg(poly,'style="fill:none;stroke:black;stroke-width:2"') FROM querypoly; +--ROLLBACK; +.print '' + + +.print '

Overlap With Translated Query Polygon

' +UPDATE querypoly SET poly=geopoly_xform(poly,1,0,0,1,300,0); +.print '' +SELECT geopoly_svg(_shape, + printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr) + ) + FROM geo1 + WHERE geopoly_overlap(_shape,(SELECT poly FROM querypoly)); +SELECT geopoly_svg(poly,'style="fill:none;stroke:black;stroke-width:2"') + FROM querypoly; ROLLBACK; .print '' diff --git a/manifest b/manifest index c9093d9428..19aea93dfd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fixes\sto\sthe\sUPDATE\slogic\sin\sGeopoly. -D 2018-08-29T20:52:40.880 +C Additional\stest\scases\sfor\sgeopoly. +D 2018-08-29T21:01:22.572 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f @@ -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 e47922ab37af9589cd03aca33876fcc8eefef7c9a624e1960d14bdd2572e8d9e +F ext/rtree/visual01.txt 17c3afefc208c375607aa82242e97fa79c316e539bcd0b7b3e59344c69445d05 F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a F ext/session/session1.test 4532116484f525110eb4cfff7030c59354c0cde9def4d109466b0df2b35ad5cc F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0 @@ -1758,7 +1758,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 f48e9feb3fca514e4e586932e6d19a5e34a384204effeba553006dcddf5f13d2 -R c11872ace9ae24cb28c40999f97e723f +P 7c3cee0a2a5ccacff27400c38bd708f7b9b968eb013a8fa685d876dfe85e12a6 +R 771e2fad0c71e34b021e9df816201c53 U drh -Z 581e01d30ec7f16b604718e3d6a88b37 +Z fceaa831790380442f9478793a598598 diff --git a/manifest.uuid b/manifest.uuid index b6bf5f9d22..e33dd2740f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7c3cee0a2a5ccacff27400c38bd708f7b9b968eb013a8fa685d876dfe85e12a6 \ No newline at end of file +19b5eb45e090c4b7169a52d881495ee2eafc59f80e3db2288fc1814ba76134ac \ No newline at end of file From e35fc302c3da49ac52edcda89a604a99ef898039 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 30 Aug 2018 01:52:10 +0000 Subject: [PATCH 28/33] Improved JSON parser caching. FossilOrigin-Name: 58078c0d2647a194279fa80e032670441b296ffc3acee692901faa5beca460b7 --- ext/misc/json1.c | 74 ++++++++++++++++++++++++++++++++---------------- manifest | 12 ++++---- manifest.uuid | 2 +- 3 files changed, 56 insertions(+), 32 deletions(-) diff --git a/ext/misc/json1.c b/ext/misc/json1.c index f1b633d2c6..51a519cf01 100644 --- a/ext/misc/json1.c +++ b/ext/misc/json1.c @@ -172,6 +172,7 @@ struct JsonParse { u8 nErr; /* Number of errors seen */ u16 iDepth; /* Nesting depth */ int nJson; /* Length of the zJson string in bytes */ + u32 iHold; /* Replace cache line with the lowest iHold value */ }; /* @@ -976,7 +977,8 @@ static int jsonParseFindParents(JsonParse *pParse){ /* ** Magic number used for the JSON parse cache in sqlite3_get_auxdata() */ -#define JSON_CACHE_ID (-429938) +#define JSON_CACHE_ID (-429938) /* First cache entry */ +#define JSON_CACHE_SZ 4 /* Max number of cache entries */ /* ** Obtain a complete parse of the JSON found in the first argument @@ -988,16 +990,42 @@ static int jsonParseFindParents(JsonParse *pParse){ */ static JsonParse *jsonParseCached( sqlite3_context *pCtx, - sqlite3_value **argv + sqlite3_value **argv, + sqlite3_context *pErrCtx ){ const char *zJson = (const char*)sqlite3_value_text(argv[0]); int nJson = sqlite3_value_bytes(argv[0]); JsonParse *p; + JsonParse *pMatch = 0; + int iKey; + int iMinKey = 0; + u32 iMinHold = 0xffffffff; + u32 iMaxHold = 0; if( zJson==0 ) return 0; - p = (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID); - if( p && p->nJson==nJson && memcmp(p->zJson,zJson,nJson)==0 ){ - p->nErr = 0; - return p; /* The cached entry matches, so return it */ + for(iKey=0; iKeynJson==nJson + && memcmp(p->zJson,zJson,nJson)==0 + ){ + p->nErr = 0; + pMatch = p; + }else if( p->iHoldiHold; + iMinKey = iKey; + } + if( p->iHold>iMaxHold ){ + iMaxHold = p->iHold; + } + } + if( pMatch ){ + pMatch->nErr = 0; + pMatch->iHold = iMaxHold+1; + return pMatch; } p = sqlite3_malloc( sizeof(*p) + nJson + 1 ); if( p==0 ){ @@ -1007,13 +1035,15 @@ static JsonParse *jsonParseCached( memset(p, 0, sizeof(*p)); p->zJson = (char*)&p[1]; memcpy((char*)p->zJson, zJson, nJson+1); - if( jsonParse(p, pCtx, p->zJson) ){ + if( jsonParse(p, pErrCtx, p->zJson) ){ sqlite3_free(p); return 0; } p->nJson = nJson; - sqlite3_set_auxdata(pCtx, JSON_CACHE_ID, p, (void(*)(void*))jsonParseFree); - return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID); + p->iHold = iMaxHold+1; + sqlite3_set_auxdata(pCtx, JSON_CACHE_ID+iMinKey, p, + (void(*)(void*))jsonParseFree); + return (JsonParse*)sqlite3_get_auxdata(pCtx, JSON_CACHE_ID+iMinKey); } /* @@ -1386,7 +1416,7 @@ static void jsonArrayLengthFunc( u32 i; JsonNode *pNode; - p = jsonParseCached(ctx, argv); + p = jsonParseCached(ctx, argv, ctx); if( p==0 ) return; assert( p->nNode ); if( argc==2 ){ @@ -1427,7 +1457,7 @@ static void jsonExtractFunc( int i; if( argc<2 ) return; - p = jsonParseCached(ctx, argv); + p = jsonParseCached(ctx, argv, ctx); if( p==0 ) return; jsonInit(&jx, ctx); jsonAppendChar(&jx, '['); @@ -1734,22 +1764,21 @@ static void jsonTypeFunc( int argc, sqlite3_value **argv ){ - JsonParse x; /* The parse */ + JsonParse *p; /* The parse */ const char *zPath; JsonNode *pNode; - if( jsonParse(&x, ctx, (const char*)sqlite3_value_text(argv[0])) ) return; - assert( x.nNode ); + p = jsonParseCached(ctx, argv, ctx); + if( p==0 ) return; if( argc==2 ){ zPath = (const char*)sqlite3_value_text(argv[1]); - pNode = jsonLookup(&x, zPath, 0, ctx); + pNode = jsonLookup(p, zPath, 0, ctx); }else{ - pNode = x.aNode; + pNode = p->aNode; } if( pNode ){ sqlite3_result_text(ctx, jsonType[pNode->eType], -1, SQLITE_STATIC); } - jsonParseReset(&x); } /* @@ -1763,15 +1792,10 @@ static void jsonValidFunc( int argc, sqlite3_value **argv ){ - JsonParse x; /* The parse */ - int rc = 0; - + JsonParse *p; /* The parse */ UNUSED_PARAM(argc); - if( jsonParse(&x, 0, (const char*)sqlite3_value_text(argv[0]))==0 ){ - rc = 1; - } - jsonParseReset(&x); - sqlite3_result_int(ctx, rc); + p = jsonParseCached(ctx, argv, 0); + sqlite3_result_int(ctx, p!=0); } diff --git a/manifest b/manifest index 19aea93dfd..ca27635ca6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Additional\stest\scases\sfor\sgeopoly. -D 2018-08-29T21:01:22.572 +C Improved\sJSON\sparser\scaching. +D 2018-08-30T01:52:10.764 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f @@ -284,7 +284,7 @@ F ext/misc/eval.c 6ea9b22a5fa0dd973b67ca4e53555be177bc0b7b263aadf1024429457c82c0 F ext/misc/fileio.c 48c7751c78fc4cdd29d8c862fd2f3f98bbfefa2a3cf1ca1496df4bf02eb8cded F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25 F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c -F ext/misc/json1.c 696c596de45d991e6c4617b5a3cb4cc60d231aa4be10edea7d27a4008df2f545 +F ext/misc/json1.c 34a31eac76aeec269657f6f84a72533600d511005efa5dd97034909a2a0fbc9a F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567 F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29 F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342 @@ -1758,7 +1758,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 7c3cee0a2a5ccacff27400c38bd708f7b9b968eb013a8fa685d876dfe85e12a6 -R 771e2fad0c71e34b021e9df816201c53 +P 19b5eb45e090c4b7169a52d881495ee2eafc59f80e3db2288fc1814ba76134ac +R 6879c3448f3a21f21360b0e010f06ec5 U drh -Z fceaa831790380442f9478793a598598 +Z c5fe49b6610cf864d1fad4e0e99d3945 diff --git a/manifest.uuid b/manifest.uuid index e33dd2740f..554957456a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -19b5eb45e090c4b7169a52d881495ee2eafc59f80e3db2288fc1814ba76134ac \ No newline at end of file +58078c0d2647a194279fa80e032670441b296ffc3acee692901faa5beca460b7 \ No newline at end of file From ed9272159e12bd86d98bef5e8664a9920801f4fa Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 30 Aug 2018 18:53:09 +0000 Subject: [PATCH 29/33] Give the debugging routine print_pager_stats() external linkage in order to suppress harmless compiler and TSAN warnings. FossilOrigin-Name: ff4dc08298ab3988e69fe60802657791f65d2af15f4b1cbd1d02649bc597d0d6 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/pager.c | 13 +++++-------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index ca27635ca6..8d06fd07f5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improved\sJSON\sparser\scaching. -D 2018-08-30T01:52:10.764 +C Give\sthe\sdebugging\sroutine\sprint_pager_stats()\sexternal\slinkage\sin\sorder\sto\nsuppress\sharmless\scompiler\sand\sTSAN\swarnings. +D 2018-08-30T18:53:09.671 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f @@ -487,7 +487,7 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 F src/os_unix.c d6ee0c3b3f221dd5f3cec95f0400a581c516d04ea16a2916bba17c55127d8e06 F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a -F src/pager.c 705de01dff9c3df9739c37a6d3b58cd2b1734fdabcef829b16cdc7721a9eeaa4 +F src/pager.c a0d8f686ef64549ad5b356fd30429bd9ee7a06dd42b4d6faa096352ff26b1c5b F src/pager.h ecc554a55bc55d1c4ba5e17137b72e238e00bd81e72ff2662d8b9c8c10ae3963 F src/parse.y 704c94624d41d7d46a5467574130e55aa8029a563f4df538f0121475eae46e34 F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd @@ -1758,7 +1758,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 19b5eb45e090c4b7169a52d881495ee2eafc59f80e3db2288fc1814ba76134ac -R 6879c3448f3a21f21360b0e010f06ec5 +P 58078c0d2647a194279fa80e032670441b296ffc3acee692901faa5beca460b7 +R a4b705470a4ec2c924173c8c942f70f9 U drh -Z c5fe49b6610cf864d1fad4e0e99d3945 +Z 1e426c4805f3914010cc98a58db34e64 diff --git a/manifest.uuid b/manifest.uuid index 554957456a..0e3a958bc6 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -58078c0d2647a194279fa80e032670441b296ffc3acee692901faa5beca460b7 \ No newline at end of file +ff4dc08298ab3988e69fe60802657791f65d2af15f4b1cbd1d02649bc597d0d6 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index a7d076ab0b..92d32fd275 100644 --- a/src/pager.c +++ b/src/pager.c @@ -997,8 +997,12 @@ static int assert_pager_state(Pager *p){ ** to "print *pPager" in gdb: ** ** (gdb) printf "%s", print_pager_state(pPager) +** +** This routine has external linkage in order to suppress compiler warnings +** about an unused function. It is enclosed within SQLITE_DEBUG and so does +** not appear in normal builds. */ -static char *print_pager_state(Pager *p){ +char *print_pager_state(Pager *p){ static char zRet[1024]; sqlite3_snprintf(1024, zRet, @@ -7278,13 +7282,6 @@ int sqlite3PagerLockingMode(Pager *pPager, int eMode){ int sqlite3PagerSetJournalMode(Pager *pPager, int eMode){ u8 eOld = pPager->journalMode; /* Prior journalmode */ -#ifdef SQLITE_DEBUG - /* The print_pager_state() routine is intended to be used by the debugger - ** only. We invoke it once here to suppress a compiler warning. */ - print_pager_state(pPager); -#endif - - /* The eMode parameter is always valid */ assert( eMode==PAGER_JOURNALMODE_DELETE || eMode==PAGER_JOURNALMODE_TRUNCATE From 876c7ea3fa7507018df842eeb6870c1b4f5d8f38 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 30 Aug 2018 20:28:18 +0000 Subject: [PATCH 30/33] Try to identify the places in WAL code where thread-safety depends on the underlying architecture supporting atomic load and store of aligned 32-bit values. FossilOrigin-Name: 47d44be4a68d377d0049a12b2587dbbcc0870b469473e1098f7c0358fe8c7532 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/wal.c | 20 ++++++++++++++++---- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 8d06fd07f5..941aad31d5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Give\sthe\sdebugging\sroutine\sprint_pager_stats()\sexternal\slinkage\sin\sorder\sto\nsuppress\sharmless\scompiler\sand\sTSAN\swarnings. -D 2018-08-30T18:53:09.671 +C Try\sto\sidentify\sthe\splaces\sin\sWAL\scode\swhere\sthread-safety\sdepends\son\sthe\nunderlying\sarchitecture\ssupporting\satomic\sload\sand\sstore\sof\saligned\s32-bit\nvalues. +D 2018-08-30T20:28:18.073 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f @@ -582,7 +582,7 @@ F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7 F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392 F src/vtab.c 678992ac8ec677a3f9b08126aaf891441083805e3b42574e3654d44538381c14 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 -F src/wal.c 46bfc9427d527099c17ce00a343a1c3fb8b050b00ddaf90a94398cda44070bf8 +F src/wal.c f58ff398f7dba6d6129f27b9a52fc00b46a36d0fea5368706b6d088dde801313 F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4 F src/where.c 155809967fbab889374dedf970ea6561b8fb519fcb165d6ba00776552ecc5cde @@ -1758,7 +1758,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 58078c0d2647a194279fa80e032670441b296ffc3acee692901faa5beca460b7 -R a4b705470a4ec2c924173c8c942f70f9 +P ff4dc08298ab3988e69fe60802657791f65d2af15f4b1cbd1d02649bc597d0d6 +R 8b1c21076160b5400497f5a8fe9f34ce U drh -Z 1e426c4805f3914010cc98a58db34e64 +Z 66336bd926abce6891acc1782fdb9867 diff --git a/manifest.uuid b/manifest.uuid index 0e3a958bc6..7e0941b00f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ff4dc08298ab3988e69fe60802657791f65d2af15f4b1cbd1d02649bc597d0d6 \ No newline at end of file +47d44be4a68d377d0049a12b2587dbbcc0870b469473e1098f7c0358fe8c7532 \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index 194d6da1d0..326e25d339 100644 --- a/src/wal.c +++ b/src/wal.c @@ -258,6 +258,18 @@ int sqlite3WalTrace = 0; # define WALTRACE(X) #endif +/* +** WAL mode depends on atomic aligned 32-bit loads and stores in a few +** places. The following macros try to make this explicit. +*/ +#if GCC_VESRION>=5004000 +# define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED) +# define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED) +#else +# define AtomicLoad(PTR) (*(PTR)) +# define AtomicStore(PTR,VAL) (*(PTR) = (VAL)) +#endif + /* ** The maximum (and only) versions of the wal and wal-index formats ** that may be interpreted by this version of SQLite. @@ -2555,7 +2567,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ } #endif for(i=1; iaReadMark[i]; + u32 thisMark = AtomicLoad(pInfo->aReadMark+i); if( mxReadMark<=thisMark && thisMark<=mxFrame ){ assert( thisMark!=READMARK_NOT_USED ); mxReadMark = thisMark; @@ -2568,7 +2580,7 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ for(i=1; iaReadMark[i] = mxFrame; + mxReadMark = AtomicStore(pInfo->aReadMark+i,mxFrame); mxI = i; walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1); break; @@ -2620,9 +2632,9 @@ static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){ ** we can guarantee that the checkpointer that set nBackfill could not ** see any pages past pWal->hdr.mxFrame, this problem does not come up. */ - pWal->minFrame = pInfo->nBackfill+1; + pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1; walShmBarrier(pWal); - if( pInfo->aReadMark[mxI]!=mxReadMark + if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){ walUnlockShared(pWal, WAL_READ_LOCK(mxI)); From 8d4b7a3fa85592a0e39ada5bf56d4cc0abd4d80c Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 31 Aug 2018 19:00:16 +0000 Subject: [PATCH 31/33] If a call to sqlite3_snapshot_open() fails because the requested snapshot no longer exists, return SQLITE_ERROR_SNAPSHOT instead of SQLITE_BUSY_SNAPSHOT. FossilOrigin-Name: e07923128bb164efbafde29d49175b61f2ef44b2dfac5ae4ed61937945dfcf4c --- manifest | 26 +++++++++++++------------- manifest.uuid | 2 +- src/main.c | 1 + src/sqlite.h.in | 5 +++-- src/wal.c | 6 +++--- test/snapshot.test | 6 +++--- test/snapshot2.test | 6 +++--- test/snapshot3.test | 2 +- test/snapshot_up.test | 8 ++++---- 9 files changed, 32 insertions(+), 30 deletions(-) diff --git a/manifest b/manifest index 941aad31d5..21e91551c3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Try\sto\sidentify\sthe\splaces\sin\sWAL\scode\swhere\sthread-safety\sdepends\son\sthe\nunderlying\sarchitecture\ssupporting\satomic\sload\sand\sstore\sof\saligned\s32-bit\nvalues. -D 2018-08-30T20:28:18.073 +C If\sa\scall\sto\ssqlite3_snapshot_open()\sfails\sbecause\sthe\srequested\ssnapshot\sno\nlonger\sexists,\sreturn\sSQLITE_ERROR_SNAPSHOT\sinstead\sof\sSQLITE_BUSY_SNAPSHOT. +D 2018-08-31T19:00:16.739 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f @@ -464,7 +464,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c c723716f0de7aa0a679300f7d3541c89645f4a9882161cecdb3093fc07f8cc4b F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e F src/loadext.c 6aae5739198d96c51ae6eb97c4a5b1744c22ed7a5a565a5399a717780d48a36b -F src/main.c 187011ff7a091ff4b8bea9481a42789c0fa094715b4e5d89352fb63377673490 +F src/main.c 1f54ee71990bfbf4cdc2dc79bdc33e7c4f54eef6922447b4c910f9b5885a4478 F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@ -502,7 +502,7 @@ F src/resolve.c 797088662ed61102485e3070ba3b3f7828bd5ef6a588223ba6865d77d52f6cea F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c ae7396a314cc1bb1d767947cd57094e3a9ffcbb155ebc1b1c391e028c44a9a04 F src/shell.c.in 6e0aad854be738a5d0368940459399be211e9ac43aebe92bb9ed46cfe38d0e1f -F src/sqlite.h.in 5a2d431493020c2c9f2f37c9119d6439444e3c44a714566a5192b6911ac917e6 +F src/sqlite.h.in cdf2a539cd0570322a94bcb97c01c56feb1be0657ec7cfb8273c89d19fff87a9 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 9887b27e69c01e79c2cbe74ef73bf01af5b5703d6a7f0a4371e386d7249cb1c7 F src/sqliteInt.h 26e48f0c823844fcce67bd2a11ad1ad3468aaed32fd8864bc69c4147cb608728 @@ -582,7 +582,7 @@ F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7 F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392 F src/vtab.c 678992ac8ec677a3f9b08126aaf891441083805e3b42574e3654d44538381c14 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 -F src/wal.c f58ff398f7dba6d6129f27b9a52fc00b46a36d0fea5368706b6d088dde801313 +F src/wal.c df50883d93689d009be5ad9bdc4e53a4ee45fcc291087ec9272569d00b360791 F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/walker.c ba7225773931760cf60bf22f34d0cce2588df7ce5ce0f215a52eb88234b55ac4 F src/where.c 155809967fbab889374dedf970ea6561b8fb519fcb165d6ba00776552ecc5cde @@ -1271,12 +1271,12 @@ F test/skipscan2.test ef143c6e4a5ba4f19c1d1e3f517811f7942bdf2142736cc568feb34e0b F test/skipscan3.test ec5bab3f81c7038b43450e7b3062e04a198bdbb5 F test/skipscan5.test 67817a4b6857c47e0e33ba3e506da6f23ef68de2 F test/skipscan6.test 0b4cd1b4ac9f84d91454df513c99a4932fa07e8f27b8049bea605068b3e34ac7 -F test/snapshot.test fef12fc5c16ff21c4748509401cfba7d9a3d91156f1bfe23fb881d3bfc65ddfe -F test/snapshot2.test 925e42427e923262db63c9d7155183f889e3e99feaedec4075f659e51608344f -F test/snapshot3.test 9719443594a04778861bd20d12596c5f880af177d6cd62f111da3198cafc6096 +F test/snapshot.test a504f2e7009f512ef66c719f0ea1c55a556bdaf1e1312c80a04d46fc1a3e9632 +F test/snapshot2.test 4fc84a0121e882d6980333bf14dfc1143dfb94f5afbb909c084977a945b45beb +F test/snapshot3.test d6ec952e437e5c06a293d0f5ec1be1b45771d46d93bccfb3818ca2617dcb11e7 F test/snapshot4.test 0f7e6bd6f1370d112ee820c541d0dd0e7b8ab4ea77429e65106d81c9ad2185a6 F test/snapshot_fault.test 52c5e97ebd218846a8ae2da4d147d3e77d71f963 -F test/snapshot_up.test b778a04561a67b8bfde828f473a8d31dbde23e3f648e36237e0369421e08f23c +F test/snapshot_up.test 93fec2d847ec12e3bae0f6486da2abc965a606e099e4e870454045f5f56f71ba F test/soak.test 18944cf21b94a7fe0df02016a6ee1e9632bc4e8d095a0cb49d95e15d5cca2d5c F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087 F test/sort.test c2adc635c2564241fefec0b3a68391ef6868fd3b @@ -1758,7 +1758,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 ff4dc08298ab3988e69fe60802657791f65d2af15f4b1cbd1d02649bc597d0d6 -R 8b1c21076160b5400497f5a8fe9f34ce -U drh -Z 66336bd926abce6891acc1782fdb9867 +P 47d44be4a68d377d0049a12b2587dbbcc0870b469473e1098f7c0358fe8c7532 +R 8019365693265d8430d24b1290c280cd +U dan +Z bf99ed6d8dec4f787bbe304a5e0c353c diff --git a/manifest.uuid b/manifest.uuid index 7e0941b00f..8c5645c4e7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -47d44be4a68d377d0049a12b2587dbbcc0870b469473e1098f7c0358fe8c7532 \ No newline at end of file +e07923128bb164efbafde29d49175b61f2ef44b2dfac5ae4ed61937945dfcf4c \ No newline at end of file diff --git a/src/main.c b/src/main.c index b39328d230..fb7ca37c1e 100644 --- a/src/main.c +++ b/src/main.c @@ -1329,6 +1329,7 @@ const char *sqlite3ErrName(int rc){ switch( rc ){ case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; + case SQLITE_ERROR_SNAPSHOT: zName = "SQLITE_ERROR_SNAPSHOT"; break; case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; case SQLITE_PERM: zName = "SQLITE_PERM"; break; case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 9a611fa00a..6a7c4f7e03 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -472,6 +472,7 @@ int sqlite3_exec( */ #define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8)) #define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8)) +#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8)) #define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8)) #define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8)) #define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8)) @@ -9053,11 +9054,11 @@ SQLITE_EXPERIMENTAL int sqlite3_snapshot_get( ** ** ^A call to sqlite3_snapshot_open() will fail to open if the specified ** snapshot has been overwritten by a [checkpoint]. In this case -** SQLITE_BUSY_SNAPSHOT is returned. +** SQLITE_ERROR_SNAPSHOT is returned. ** ** If there is already a read transaction open when this function is ** invoked, then the same read transaction remains open (on the same -** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_BUSY_SNAPSHOT +** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT ** is returned. If another error code - for example SQLITE_PROTOCOL or an ** SQLITE_IOERR error code - is returned, then the final state of the ** read transaction is undefined. If SQLITE_OK is returned, then the diff --git a/src/wal.c b/src/wal.c index 326e25d339..8c32f3ea10 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2795,7 +2795,7 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ /* Check that the wal file has not been wrapped. Assuming that it has ** not, also check that no checkpointer has attempted to checkpoint any ** frames beyond pSnapshot->mxFrame. If either of these conditions are - ** true, return SQLITE_BUSY_SNAPSHOT. Otherwise, overwrite pWal->hdr + ** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr ** with *pSnapshot and set *pChanged as appropriate for opening the ** snapshot. */ if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) @@ -2805,7 +2805,7 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){ memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr)); *pChanged = bChanged; }else{ - rc = SQLITE_BUSY_SNAPSHOT; + rc = SQLITE_ERROR_SNAPSHOT; } /* Release the shared CKPT lock obtained above. */ @@ -3802,7 +3802,7 @@ int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot){ if( memcmp(pNew->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt)) || pNew->mxFramenBackfillAttempted ){ - rc = SQLITE_BUSY_SNAPSHOT; + rc = SQLITE_ERROR_SNAPSHOT; walUnlockShared(pWal, WAL_CKPT_LOCK); } } diff --git a/test/snapshot.test b/test/snapshot.test index 10400523da..75a8af214a 100644 --- a/test/snapshot.test +++ b/test/snapshot.test @@ -258,7 +258,7 @@ foreach {tn tcl} { } {} #------------------------------------------------------------------------- - # Check that SQLITE_BUSY_SNAPSHOT is returned if the specified snapshot + # Check that SQLITE_ERROR_SNAPSHOT is returned if the specified snapshot # no longer exists because the wal file has been checkpointed. # # 1. Reading a snapshot from the middle of a wal file is not possible @@ -296,7 +296,7 @@ foreach {tn tcl} { BEGIN; } list [catch {snapshot_open db main $snapshot} msg] $msg - } {1 SQLITE_BUSY_SNAPSHOT} + } {1 SQLITE_ERROR_SNAPSHOT} do_test $tn.4.1.4 { snapshot_free $snapshot execsql COMMIT @@ -327,7 +327,7 @@ foreach {tn tcl} { BEGIN; } list [catch {snapshot_open db main $snapshot} msg] $msg - } {1 SQLITE_BUSY_SNAPSHOT} + } {1 SQLITE_ERROR_SNAPSHOT} do_test $tn.4.2.4 { snapshot_free $snapshot } {} diff --git a/test/snapshot2.test b/test/snapshot2.test index 3faabd7f4c..0f0e63961f 100644 --- a/test/snapshot2.test +++ b/test/snapshot2.test @@ -110,7 +110,7 @@ do_test 2.2 { execsql {SELECT * FROM sqlite_master} execsql BEGIN list [catch { sqlite3_snapshot_open_blob db main $snap } msg] $msg -} {1 SQLITE_BUSY_SNAPSHOT} +} {1 SQLITE_ERROR_SNAPSHOT} do_test 2.3 { execsql COMMIT @@ -134,7 +134,7 @@ do_test 2.5 { sqlite3_snapshot_recover db main execsql BEGIN list [catch { sqlite3_snapshot_open_blob db main $snap } msg] $msg -} {1 SQLITE_BUSY_SNAPSHOT} +} {1 SQLITE_ERROR_SNAPSHOT} #------------------------------------------------------------------------- # Check that calling sqlite3_snapshot_recover() does not confuse the @@ -234,7 +234,7 @@ do_test 5.4 { execsql { INSERT INTO t2 VALUES('jkl') } execsql BEGIN db2 list [catch { sqlite3_snapshot_open_blob db2 main $snap } msg] $msg -} {1 SQLITE_BUSY_SNAPSHOT} +} {1 SQLITE_ERROR_SNAPSHOT} finish_test diff --git a/test/snapshot3.test b/test/snapshot3.test index 266f43dfd4..8c330d7cbf 100644 --- a/test/snapshot3.test +++ b/test/snapshot3.test @@ -94,7 +94,7 @@ do_test 1.7 { do_test 1.8 { execsql BEGIN db3 list [catch { sqlite3_snapshot_open_blob db3 main $snap } msg] $msg -} {1 SQLITE_BUSY_SNAPSHOT} +} {1 SQLITE_ERROR_SNAPSHOT} finish_test diff --git a/test/snapshot_up.test b/test/snapshot_up.test index f7c2e443cf..651a92ac64 100644 --- a/test/snapshot_up.test +++ b/test/snapshot_up.test @@ -75,7 +75,7 @@ do_execsql_test 1.6 { do_test 1.7 { list [catch { sqlite3_snapshot_open db main $::snap1 } msg] $msg -} {1 SQLITE_BUSY_SNAPSHOT} +} {1 SQLITE_ERROR_SNAPSHOT} do_execsql_test 1.8 { SELECT * FROM t1 @@ -84,7 +84,7 @@ do_execsql_test 1.8 { do_test 1.9 { execsql { COMMIT ; BEGIN } list [catch { sqlite3_snapshot_open db main $::snap1 } msg] $msg -} {1 SQLITE_BUSY_SNAPSHOT} +} {1 SQLITE_ERROR_SNAPSHOT} do_test 1.10 { execsql { COMMIT } @@ -113,7 +113,7 @@ do_test 1.12 { do_test 1.13 { list [catch { sqlite3_snapshot_open db main $::snap3 } msg] $msg -} {1 SQLITE_BUSY_SNAPSHOT} +} {1 SQLITE_ERROR_SNAPSHOT} do_test 1.14 { execsql { SELECT * FROM t1 } } {4 5 6 7 8 9 10 11 12 13 14 15} @@ -127,7 +127,7 @@ do_execsql_test 1.15 { } {7 8 9 10 11 12 13 14 15} do_test 1.16 { list [catch { sqlite3_snapshot_open db main $::snap4 } msg] $msg -} {1 SQLITE_BUSY_SNAPSHOT} +} {1 SQLITE_ERROR_SNAPSHOT} do_execsql_test 1.17 { COMMIT } sqlite3_snapshot_free $::snap1 From 28d46eed3fd73ae6155a8c2da8d7b460572edfae Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 31 Aug 2018 23:22:40 +0000 Subject: [PATCH 32/33] New hyperlink on the README.md file. FossilOrigin-Name: c663961e34ec03ef76aabc9741f37d19544826e3e0b5931711313fc088e9e62c --- README.md | 5 +++-- manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8c8cc95c74..87f1f81103 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@

SQLite Source Repository

-This repository contains the complete source code for the SQLite database -engine. Some test scripts are also included. However, many other test scripts +This repository contains the complete source code for the +[SQLite database engine](https://sqlite.org/). Some test scripts +are also included. However, many other test scripts and most of the documentation are managed separately. SQLite [does not use Git](https://sqlite.org/whynotgit.html). diff --git a/manifest b/manifest index 21e91551c3..ff1a562ed1 100644 --- a/manifest +++ b/manifest @@ -1,11 +1,11 @@ -C If\sa\scall\sto\ssqlite3_snapshot_open()\sfails\sbecause\sthe\srequested\ssnapshot\sno\nlonger\sexists,\sreturn\sSQLITE_ERROR_SNAPSHOT\sinstead\sof\sSQLITE_BUSY_SNAPSHOT. -D 2018-08-31T19:00:16.739 +C New\shyperlink\son\sthe\sREADME.md\sfile. +D 2018-08-31T23:22:40.497 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc ab99b4a0aa33f1c0f39587be9df15c9db536acf7859828ff8c51e13eb5082874 -F README.md 7764d56778d567913ef11c82da9ab94aefa0826f7c243351e4e2d7adaef6f373 +F README.md 377233394b905d3b2e2b33741289e093bc93f2e7adbe00923b2c5958c9a9edee F VERSION d3e3afdec1165a5e593dcdfffd8e0f33a2b0186067eb51a073ef6c4aec34923d F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2 @@ -1758,7 +1758,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 47d44be4a68d377d0049a12b2587dbbcc0870b469473e1098f7c0358fe8c7532 -R 8019365693265d8430d24b1290c280cd -U dan -Z bf99ed6d8dec4f787bbe304a5e0c353c +P e07923128bb164efbafde29d49175b61f2ef44b2dfac5ae4ed61937945dfcf4c +R 547460f5e80d9b93c6a19fd045e588a1 +U drh +Z fb21b6ae32fc6545ce2e423fcfd763a1 diff --git a/manifest.uuid b/manifest.uuid index 8c5645c4e7..4b716587f1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e07923128bb164efbafde29d49175b61f2ef44b2dfac5ae4ed61937945dfcf4c \ No newline at end of file +c663961e34ec03ef76aabc9741f37d19544826e3e0b5931711313fc088e9e62c \ No newline at end of file From 6ae2454a67804f45fe94ef78336a3ab7d3f90884 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 1 Sep 2018 06:13:07 +0000 Subject: [PATCH 33/33] Update test script snapshot_fault.test to account for the new sqlite3_snapshot_open() error code. FossilOrigin-Name: c1aca7673ab04740bc8ad76af0a72a229c79a0cd51cf84d1c689a77424ff17c6 --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/snapshot_fault.test | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index ff1a562ed1..2978337ecd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\shyperlink\son\sthe\sREADME.md\sfile. -D 2018-08-31T23:22:40.497 +C Update\stest\sscript\ssnapshot_fault.test\sto\saccount\sfor\sthe\snew\nsqlite3_snapshot_open()\serror\scode. +D 2018-09-01T06:13:07.396 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in d06f463c5b623a61ac27f5cb8214fca9e53a6704d34d6b8f2124e2b1b293c88f @@ -1275,7 +1275,7 @@ F test/snapshot.test a504f2e7009f512ef66c719f0ea1c55a556bdaf1e1312c80a04d46fc1a3 F test/snapshot2.test 4fc84a0121e882d6980333bf14dfc1143dfb94f5afbb909c084977a945b45beb F test/snapshot3.test d6ec952e437e5c06a293d0f5ec1be1b45771d46d93bccfb3818ca2617dcb11e7 F test/snapshot4.test 0f7e6bd6f1370d112ee820c541d0dd0e7b8ab4ea77429e65106d81c9ad2185a6 -F test/snapshot_fault.test 52c5e97ebd218846a8ae2da4d147d3e77d71f963 +F test/snapshot_fault.test 508ae6f211d4991e9ff3b5080aeb0a179bf6755138aabeac4bca8083044d895a F test/snapshot_up.test 93fec2d847ec12e3bae0f6486da2abc965a606e099e4e870454045f5f56f71ba F test/soak.test 18944cf21b94a7fe0df02016a6ee1e9632bc4e8d095a0cb49d95e15d5cca2d5c F test/softheap1.test 843cd84db9891b2d01b9ab64cef3e9020f98d087 @@ -1758,7 +1758,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 e07923128bb164efbafde29d49175b61f2ef44b2dfac5ae4ed61937945dfcf4c -R 547460f5e80d9b93c6a19fd045e588a1 -U drh -Z fb21b6ae32fc6545ce2e423fcfd763a1 +P c663961e34ec03ef76aabc9741f37d19544826e3e0b5931711313fc088e9e62c +R cd8df7b46385f21282cbe8048608f95d +U dan +Z 6efe33567a6b3165892c7111d30b4286 diff --git a/manifest.uuid b/manifest.uuid index 4b716587f1..236f669f38 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c663961e34ec03ef76aabc9741f37d19544826e3e0b5931711313fc088e9e62c \ No newline at end of file +c1aca7673ab04740bc8ad76af0a72a229c79a0cd51cf84d1c689a77424ff17c6 \ No newline at end of file diff --git a/test/snapshot_fault.test b/test/snapshot_fault.test index 5c6cf40a6f..c0df4ec8e0 100644 --- a/test/snapshot_fault.test +++ b/test/snapshot_fault.test @@ -47,7 +47,7 @@ do_faultsim_test 1.0 -prep { } -test { db2 eval BEGIN if {[catch { sqlite3_snapshot_open db2 main $::snapshot } msg]} { - if {$msg != "SQLITE_BUSY_SNAPSHOT" && $msg != "SQLITE_BUSY"} { + if {$msg != "SQLITE_ERROR_SNAPSHOT" && $msg != "SQLITE_BUSY"} { error "error is $msg" } } else { @@ -98,7 +98,7 @@ do_faultsim_test 2.0 -prep { db eval BEGIN if {[catch { sqlite3_snapshot_open db main $::snapshot } msg]} { - if {$msg != "SQLITE_BUSY_SNAPSHOT" && $msg != "SQLITE_BUSY"} { + if {$msg != "SQLITE_ERROR_SNAPSHOT" && $msg != "SQLITE_BUSY"} { error "error is $msg" } } else {