1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-12-24 14:17:58 +03:00

Untested incremental check-in. Basic infrastructure for geopoly in place,

except for the MATCH operator.

FossilOrigin-Name: b27451910b6880b166d4777e05b14ab2731c3483b5ed0f42c459bbb61c6cd095
This commit is contained in:
drh
2018-05-25 22:39:29 +00:00
parent 66c43599ce
commit ecdc742790
3 changed files with 102 additions and 112 deletions

View File

@@ -193,8 +193,9 @@ static int geopolyParseNumber(GeoParse *p, GeoCoord *pVal){
**
** If any error occurs, return NULL.
*/
static GeoPoly *geopolyParseJson(const unsigned char *z){
static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){
GeoParse s;
int rc = SQLITE_OK;
memset(&s, 0, sizeof(s));
s.z = z;
if( geopolySkipSpace(&s)=='[' ){
@@ -208,6 +209,7 @@ static GeoPoly *geopolyParseJson(const unsigned char *z){
s.nAlloc = s.nAlloc*2 + 16;
aNew = sqlite3_realloc64(s.a, s.nAlloc*sizeof(GeoCoord)*2 );
if( aNew==0 ){
rc = SQLITE_NOMEM;
s.nErr++;
break;
}
@@ -221,6 +223,7 @@ static GeoPoly *geopolyParseJson(const unsigned char *z){
if( c==',' ) continue;
if( c==']' ) break;
s.nErr++;
rc = SQLITE_ERROR;
goto parse_json_err;
}
if( geopolySkipSpace(&s)==',' ){
@@ -245,12 +248,15 @@ static GeoPoly *geopolyParseJson(const unsigned char *z){
pOut->hdr[2] = (s.nVertex>>8)&0xff;
pOut->hdr[3] = s.nVertex&0xff;
sqlite3_free(s.a);
if( pRc ) *pRc = SQLITE_OK;
return pOut;
}else{
s.nErr++;
rc = SQLITE_ERROR;
}
}
parse_json_err:
if( pRc ) *pRc = rc;
sqlite3_free(s.a);
return 0;
}
@@ -261,7 +267,11 @@ parse_json_err:
** return a pointer to that object. Or if the input is not a well-formed
** polygon, put an error message in sqlite3_context and return NULL.
*/
static GeoPoly *geopolyFuncParam(sqlite3_context *pCtx, sqlite3_value *pVal){
static GeoPoly *geopolyFuncParam(
sqlite3_context *pCtx, /* Context for error messages */
sqlite3_value *pVal, /* The value to decode */
int *pRc /* Write error here */
){
GeoPoly *p = 0;
int nByte;
if( sqlite3_value_type(pVal)==SQLITE_BLOB
@@ -274,7 +284,10 @@ static GeoPoly *geopolyFuncParam(sqlite3_context *pCtx, sqlite3_value *pVal){
&& (nVertex*2*sizeof(GeoCoord) + 4)==nByte
){
p = sqlite3_malloc64( sizeof(*p) + (nVertex-1)*2*sizeof(GeoCoord) );
if( p ){
if( p==0 ){
if( pRc ) *pRc = SQLITE_NOMEM;
if( pCtx ) sqlite3_result_error_nomem(pCtx);
}else{
int x = 1;
p->nVertex = nVertex;
memcpy(p->hdr, a, nByte);
@@ -287,13 +300,15 @@ static GeoPoly *geopolyFuncParam(sqlite3_context *pCtx, sqlite3_value *pVal){
}
}
}
if( pRc ) *pRc = SQLITE_OK;
return p;
}else if( sqlite3_value_type(pVal)==SQLITE_TEXT ){
p = geopolyParseJson(sqlite3_value_text(pVal));
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( r<mnY ) mnY = r;
else if( r>mxY ) mxY = r;
}
if( pRc ) *pRc = SQLITE_OK;
if( aCoord==0 ){
pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6);
if( pOut==0 ){
sqlite3_free(p);
sqlite3_result_error_nomem(context);
if( context ) sqlite3_result_error_nomem(context);
if( pRc ) *pRc = SQLITE_NOMEM;
return 0;
}
pOut->nVertex = 4;
@@ -451,17 +469,15 @@ static GeoPoly *geopolyBBox(
pOut->a[5] = mxY;
pOut->a[6] = mnX;
pOut->a[7] = mxY;
return pOut;
}else{
sqlite3_free(p);
aCoord[0] = mnX;
aCoord[1] = mxX;
aCoord[2] = mnY;
aCoord[3] = mxY;
return (GeoPoly*)aCoord;
aCoord[0].f = mnX;
aCoord[1].f = mxX;
aCoord[2].f = mnY;
aCoord[3].f = mxY;
}
}
return 0;
return pOut;
}
/*
@@ -472,7 +488,7 @@ static void geopolyBBoxFunc(
int argc,
sqlite3_value **argv
){
GeoPoly *p = geopolyBBox(context, argv[0], 0);
GeoPoly *p = geopolyBBox(context, argv[0], 0, 0);
if( p ){
sqlite3_result_blob(context, p->hdr,
4+8*p->nVertex, SQLITE_TRANSIENT);
@@ -530,7 +546,7 @@ static void geopolyWithinFunc(
int argc,
sqlite3_value **argv
){
GeoPoly *p = geopolyFuncParam(context, argv[0]);
GeoPoly *p = geopolyFuncParam(context, argv[0], 0);
double x0 = sqlite3_value_double(argv[1]);
double y0 = sqlite3_value_double(argv[2]);
if( p ){
@@ -874,8 +890,8 @@ static void geopolyOverlapFunc(
int argc,
sqlite3_value **argv
){
GeoPoly *p1 = geopolyFuncParam(context, argv[0]);
GeoPoly *p2 = geopolyFuncParam(context, argv[1]);
GeoPoly *p1 = geopolyFuncParam(context, argv[0], 0);
GeoPoly *p2 = geopolyFuncParam(context, argv[1], 0);
if( p1 && p2 ){
int x = geopolyOverlap(p1, p2);
if( x<0 ){
@@ -955,12 +971,13 @@ static int geopolyInit(
pSql = sqlite3_str_new(db);
sqlite3_str_appendf(pSql, "CREATE TABLE x");
cSep = '(';
pRtree->nAux = 1; /* Add one for _shape */
for(ii=3; ii<argc; ii++){
pRtree->nAux++;
sqlite3_str_appendf(pSql, "%c%s", cSep, argv[ii]+1);
cSep = ',';
}
sqlite3_str_appendf(pSql, "%c _poly HIDDEN, _bbox HIDDEN);", cSep);
sqlite3_str_appendf(pSql, "%c _shape, _bbox HIDDEN);", cSep);
zSql = sqlite3_str_finish(pSql);
if( !zSql ){
rc = SQLITE_NOMEM;
@@ -1164,9 +1181,13 @@ static int geopolyUpdate(
){
Rtree *pRtree = (Rtree *)pVtab;
int rc = SQLITE_OK;
// RtreeCell cell; /* New cell to insert if nData>1 */
// int bHaveRowid = 0; /* Set to 1 after new rowid is determined */
// int iShapeCol; /* Index of the _shape column */
RtreeCell cell; /* New cell to insert if nData>1 */
int iShapeCol; /* Index of the _shape column */
i64 oldRowid; /* The old rowid */
int oldRowidValid; /* True if oldRowid is valid */
i64 newRowid; /* The new rowid */
int newRowidValid; /* True if newRowid is valid */
int coordChange = 0; /* Change in coordinates */
if( pRtree->nNodeRef ){
/* Unable to write to the btree while another cursor is reading from it,
@@ -1177,72 +1198,43 @@ static int geopolyUpdate(
rtreeReference(pRtree);
assert(nData>=1);
// cell.iRowid = 0; /* Used only to suppress a compiler warning */
// iShapeCol = pRtree->nAux;
iShapeCol = pRtree->nAux;
rc = SQLITE_ERROR;
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; ii<nn; ii+=2){
cell.aCoord[ii].f = rtreeValueDown(aData[ii+3]);
cell.aCoord[ii+1].f = rtreeValueUp(aData[ii+4]);
if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
rc = rtreeConstraintError(pRtree, ii+1);
goto constraint;
}
}
}else
#endif
{
for(ii=0; ii<nn; ii+=2){
cell.aCoord[ii].i = sqlite3_value_int(aData[ii+3]);
cell.aCoord[ii+1].i = sqlite3_value_int(aData[ii+4]);
if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){
rc = rtreeConstraintError(pRtree, ii+1);
goto constraint;
}
geopolyBBox(0, aData[iShapeCol+2], cell.aCoord, &rc);
if( rc ){
if( rc==SQLITE_ERROR ){
pVtab->zErrMsg =
sqlite3_mprintf("_shape does not contain a valid polygon");
}
return rc;
}
coordChange = 1;
/* If a rowid value was supplied, check if it is already present in
** the table. If so, the constraint has failed. */
if( sqlite3_value_type(aData[2])!=SQLITE_NULL ){
cell.iRowid = sqlite3_value_int64(aData[2]);
if( sqlite3_value_type(aData[0])==SQLITE_NULL
|| sqlite3_value_int64(aData[0])!=cell.iRowid
){
int steprc;
sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid);
steprc = sqlite3_step(pRtree->pReadRowid);
rc = sqlite3_reset(pRtree->pReadRowid);
if( SQLITE_ROW==steprc ){
if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
rc = rtreeDeleteRowid(pRtree, cell.iRowid);
}else{
rc = rtreeConstraintError(pRtree, 0);
goto constraint;
}
if( oldRowidValid && oldRowid!=newRowid ){
int steprc;
sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid);
steprc = sqlite3_step(pRtree->pReadRowid);
rc = sqlite3_reset(pRtree->pReadRowid);
if( SQLITE_ROW==steprc ){
if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
rc = rtreeDeleteRowid(pRtree, cell.iRowid);
}else{
rc = rtreeConstraintError(pRtree, 0);
}
}
bHaveRowid = 1;
}
}
@@ -1250,24 +1242,18 @@ static int geopolyUpdate(
** record to delete from the r-tree table. The following block does
** just that.
*/
if( sqlite3_value_type(aData[0])!=SQLITE_NULL ){
rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(aData[0]));
if( rc==SQLITE_OK && (nData==1 || coordChange) ){
rc = rtreeDeleteRowid(pRtree, oldRowid);
}
/* If the aData[] array contains more than one element, elements
** (aData[2]..aData[argc-1]) contain a new record to insert into
** the r-tree structure.
*/
if( rc==SQLITE_OK && nData>1 ){
if( rc==SQLITE_OK && nData>1 && coordChange ){
/* Insert the new record into the r-tree */
RtreeNode *pLeaf = 0;
/* Figure out the rowid of the new row. */
if( bHaveRowid==0 ){
rc = newRowid(pRtree, &cell.iRowid);
}
*pRowid = cell.iRowid;
if( rc==SQLITE_OK ){
rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf);
}
@@ -1280,19 +1266,23 @@ static int geopolyUpdate(
rc = rc2;
}
}
if( pRtree->nAux ){
sqlite3_stmt *pUp = pRtree->pWriteAux;
int jj;
sqlite3_bind_int64(pUp, 1, *pRowid);
for(jj=0; jj<pRtree->nAux; jj++){
sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]);
}
}
/* Change the data */
if( rc==SQLITE_OK && pRtree->nAux>0 ){
sqlite3_stmt *pUp = pRtree->pWriteAux;
int jj;
int nChange = 0;
sqlite3_bind_int64(pUp, 1, newRowid);
for(jj=0; jj<pRtree->nAux; jj++){
if( !sqlite3_value_nochange(aData[jj+2]) ) nChange++;
sqlite3_bind_value(pUp, jj+2, aData[jj+2]);
}
if( nChange ){
sqlite3_step(pUp);
rc = sqlite3_reset(pUp);
}
}
constraint:
#endif /* 0 */
rtreeRelease(pRtree);
return rc;

View File

@@ -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

View File

@@ -1 +1 @@
9b7d6f986a19f8fbe26d880dc368870a10df80e06097be34ee3639f78c50be61
b27451910b6880b166d4777e05b14ab2731c3483b5ed0f42c459bbb61c6cd095