Index: ext/rtree/rtree.c ================================================================== --- ext/rtree/rtree.c +++ ext/rtree/rtree.c @@ -3074,12 +3074,15 @@ 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 */ + RtreeCell cell; /* New cell to insert if nData>1 */ + int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ + int bRtreeInsert = 0; /* True if rtree data is to be inserted */ + int nCoord; /* Number of coordinate columns */ + int ii; /* Loop counter */ 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. */ @@ -3087,10 +3090,39 @@ } rtreeReference(pRtree); assert(nData>=1); cell.iRowid = 0; /* Used only to suppress a compiler warning */ + + /* Set bRtreeInsert if this is an INSERT statement, or if it is an + ** UPDATE statement that changes the rowid or one of the coordinates. + ** Leave bRtreeInsert at zero if this is a DELETE or if this is an + ** UPDATE that only changes auxiliary columns. + */ + if( nData>1 ){ + nCoord = pRtree->nDim2; + + /* NB: nData can only be less than nDim2+3 if the rtree is mis-declared + ** with "column" that are interpreted as table constraints. + ** Example: CREATE VIRTUAL TABLE bad USING rtree(x,y,CHECK(y>5)); + ** This problem was discovered after years of use, so we silently ignore + ** these kinds of misdeclared tables to avoid breaking any legacy. + */ + if( nCoord > nData-3 ) nCoord = nData - 3; + + if( sqlite3_value_type(aData[0])==SQLITE_NULL ){ + bRtreeInsert = 1; /* This is an INSERT statement */ + }else{ + /* This is an UPDATE statement. Check to see if the rowid (aData[2]) + ** or any coordinate column (aData[3] through aData[nCoord+2]) + ** has changed. */ + for(ii=nCoord+2; ii>=2; ii--){ + if( !sqlite3_value_nochange(aData[ii]) ) break; + } + bRtreeInsert = ii>=2; + } + } /* Constraint handling. A write operation on an r-tree table may return ** SQLITE_CONSTRAINT for two reasons: ** ** 1. A duplicate rowid value, or @@ -3099,27 +3131,14 @@ ** 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 ){ - int ii; - int nn = nData - 4; - - if( nn > pRtree->nDim2 ) nn = pRtree->nDim2; - /* Populate the cell.aCoord[] array. The first coordinate is aData[3]. - ** - ** NB: nData can only be less than nDim*2+3 if the rtree is mis-declared - ** with "column" that are interpreted as table constraints. - ** Example: CREATE VIRTUAL TABLE bad USING rtree(x,y,CHECK(y>5)); - ** This problem was discovered after years of use, so we silently ignore - ** these kinds of misdeclared tables to avoid breaking any legacy. - */ - + if( bRtreeInsert ){ #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; @@ -3126,11 +3145,11 @@ } } }else #endif { - for(ii=0; iicell.aCoord[ii+1].i ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; @@ -3164,25 +3183,28 @@ /* 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 ){ + if( sqlite3_value_type(aData[0])!=SQLITE_NULL + && (bRtreeInsert || nData==1) + ){ 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 ){ + if( rc==SQLITE_OK && bRtreeInsert ){ /* 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); + bHaveRowid = 1; } *pRowid = cell.iRowid; if( rc==SQLITE_OK ){ rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); @@ -3194,14 +3216,35 @@ rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ rc = rc2; } } - if( pRtree->nAux ){ + } + + /* Handle INSERT and UPDATE of auxiliary column data */ + if( rc==SQLITE_OK && nData>1 && pRtree->nAux ){ + if( sqlite3_value_type(aData[0])==SQLITE_NULL ){ + /* This is an INSERT statement. Check to see if any + ** auxiliary column is non-NULL and hence needs to be set */ + for(ii=pRtree->nAux+pRtree->nDim2+3; iinAux+pRtree->nDim2+3; iipWriteAux; int jj; - sqlite3_bind_int64(pUp, 1, *pRowid); + if( bHaveRowid ){ + sqlite3_bind_int64(pUp, 1, cell.iRowid); + }else{ + sqlite3_bind_int64(pUp, 1, sqlite3_value_int64(aData[1])); + } for(jj=0; jjnAux; jj++){ sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]); } sqlite3_step(pUp); rc = sqlite3_reset(pUp);