1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

The SQLITE_RTREE_INT_ONLY compile-time option causes the RTree extension

to use only integer math and store only integer coordinates.

FossilOrigin-Name: 02b7640f5118e0a635b68f65765191bb3171b7bd
This commit is contained in:
drh
2012-04-02 21:35:42 +00:00
parent 3b06a2a056
commit f439fbdab5
13 changed files with 313 additions and 196 deletions

View File

@ -182,6 +182,19 @@ struct Rtree {
#define RTREE_COORD_REAL32 0 #define RTREE_COORD_REAL32 0
#define RTREE_COORD_INT32 1 #define RTREE_COORD_INT32 1
/*
** If SQLITE_RTREE_INT_ONLY is defined, then this virtual table will
** only deal with integer coordinates. No floating point operations
** will be done.
*/
#ifdef SQLITE_RTREE_INT_ONLY
typedef sqlite3_int64 RtreeDValue; /* High accuracy coordinate */
typedef int RtreeValue; /* Low accuracy coordinate */
#else
typedef double RtreeDValue; /* High accuracy coordinate */
typedef float RtreeValue; /* Low accuracy coordinate */
#endif
/* /*
** The minimum number of cells allowed for a node is a third of the ** The minimum number of cells allowed for a node is a third of the
** maximum. In Gutman's notation: ** maximum. In Gutman's notation:
@ -217,20 +230,25 @@ struct RtreeCursor {
}; };
union RtreeCoord { union RtreeCoord {
float f; RtreeValue f;
int i; int i;
}; };
/* /*
** The argument is an RtreeCoord. Return the value stored within the RtreeCoord ** The argument is an RtreeCoord. Return the value stored within the RtreeCoord
** formatted as a double. This macro assumes that local variable pRtree points ** formatted as a RtreeDValue (double or int64). This macro assumes that local
** to the Rtree structure associated with the RtreeCoord. ** variable pRtree points to the Rtree structure associated with the
** RtreeCoord.
*/ */
#define DCOORD(coord) ( \ #ifdef SQLITE_RTREE_INT_ONLY
(pRtree->eCoordType==RTREE_COORD_REAL32) ? \ # define DCOORD(coord) ((RtreeDValue)coord.i)
((double)coord.f) : \ #else
((double)coord.i) \ # define DCOORD(coord) ( \
) (pRtree->eCoordType==RTREE_COORD_REAL32) ? \
((double)coord.f) : \
((double)coord.i) \
)
#endif
/* /*
** A search constraint. ** A search constraint.
@ -238,8 +256,8 @@ union RtreeCoord {
struct RtreeConstraint { struct RtreeConstraint {
int iCoord; /* Index of constrained coordinate */ int iCoord; /* Index of constrained coordinate */
int op; /* Constraining operation */ int op; /* Constraining operation */
double rValue; /* Constraint value. */ RtreeDValue rValue; /* Constraint value. */
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *); int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);
sqlite3_rtree_geometry *pGeom; /* Constraint callback argument for a MATCH */ sqlite3_rtree_geometry *pGeom; /* Constraint callback argument for a MATCH */
}; };
@ -287,10 +305,10 @@ struct RtreeCell {
*/ */
struct RtreeMatchArg { struct RtreeMatchArg {
u32 magic; /* Always RTREE_GEOMETRY_MAGIC */ u32 magic; /* Always RTREE_GEOMETRY_MAGIC */
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *); int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue*, int *);
void *pContext; void *pContext;
int nParam; int nParam;
double aParam[1]; RtreeDValue aParam[1];
}; };
/* /*
@ -302,7 +320,7 @@ struct RtreeMatchArg {
** the geometry callback function). ** the geometry callback function).
*/ */
struct RtreeGeomCallback { struct RtreeGeomCallback {
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *); int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);
void *pContext; void *pContext;
}; };
@ -868,7 +886,7 @@ static int testRtreeGeom(
int *pbRes /* OUT: Test result */ int *pbRes /* OUT: Test result */
){ ){
int i; int i;
double aCoord[RTREE_MAX_DIMENSIONS*2]; RtreeDValue aCoord[RTREE_MAX_DIMENSIONS*2];
int nCoord = pRtree->nDim*2; int nCoord = pRtree->nDim*2;
assert( pConstraint->op==RTREE_MATCH ); assert( pConstraint->op==RTREE_MATCH );
@ -898,8 +916,8 @@ static int testRtreeCell(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){ for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){
RtreeConstraint *p = &pCursor->aConstraint[ii]; RtreeConstraint *p = &pCursor->aConstraint[ii];
double cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]); RtreeDValue cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]);
double cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]); RtreeDValue cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
@ -951,7 +969,7 @@ static int testRtreeEntry(Rtree *pRtree, RtreeCursor *pCursor, int *pbEof){
nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell); nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
for(ii=0; ii<pCursor->nConstraint; ii++){ for(ii=0; ii<pCursor->nConstraint; ii++){
RtreeConstraint *p = &pCursor->aConstraint[ii]; RtreeConstraint *p = &pCursor->aConstraint[ii];
double coord = DCOORD(cell.aCoord[p->iCoord]); RtreeDValue coord = DCOORD(cell.aCoord[p->iCoord]);
int res; int res;
assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE
|| p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
@ -1149,9 +1167,12 @@ static int rtreeColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
}else{ }else{
RtreeCoord c; RtreeCoord c;
nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c); nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c);
#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
sqlite3_result_double(ctx, c.f); sqlite3_result_double(ctx, c.f);
}else{ }else
#endif
{
assert( pRtree->eCoordType==RTREE_COORD_INT32 ); assert( pRtree->eCoordType==RTREE_COORD_INT32 );
sqlite3_result_int(ctx, c.i); sqlite3_result_int(ctx, c.i);
} }
@ -1198,7 +1219,7 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
/* Check that the blob is roughly the right size. */ /* Check that the blob is roughly the right size. */
nBlob = sqlite3_value_bytes(pValue); nBlob = sqlite3_value_bytes(pValue);
if( nBlob<(int)sizeof(RtreeMatchArg) if( nBlob<(int)sizeof(RtreeMatchArg)
|| ((nBlob-sizeof(RtreeMatchArg))%sizeof(double))!=0 || ((nBlob-sizeof(RtreeMatchArg))%sizeof(RtreeDValue))!=0
){ ){
return SQLITE_ERROR; return SQLITE_ERROR;
} }
@ -1212,7 +1233,7 @@ static int deserializeGeometry(sqlite3_value *pValue, RtreeConstraint *pCons){
memcpy(p, sqlite3_value_blob(pValue), nBlob); memcpy(p, sqlite3_value_blob(pValue), nBlob);
if( p->magic!=RTREE_GEOMETRY_MAGIC if( p->magic!=RTREE_GEOMETRY_MAGIC
|| nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(double)) || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(RtreeDValue))
){ ){
sqlite3_free(pGeom); sqlite3_free(pGeom);
return SQLITE_ERROR; return SQLITE_ERROR;
@ -1284,7 +1305,11 @@ static int rtreeFilter(
break; break;
} }
}else{ }else{
#ifdef SQLITE_RTREE_INT_ONLY
p->rValue = sqlite3_value_int64(argv[ii]);
#else
p->rValue = sqlite3_value_double(argv[ii]); p->rValue = sqlite3_value_double(argv[ii]);
#endif
} }
} }
} }
@ -1418,11 +1443,11 @@ static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
/* /*
** Return the N-dimensional volumn of the cell stored in *p. ** Return the N-dimensional volumn of the cell stored in *p.
*/ */
static float cellArea(Rtree *pRtree, RtreeCell *p){ static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
float area = 1.0; RtreeDValue area = (RtreeDValue)1;
int ii; int ii;
for(ii=0; ii<(pRtree->nDim*2); ii+=2){ for(ii=0; ii<(pRtree->nDim*2); ii+=2){
area = (float)(area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]))); area = (area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])));
} }
return area; return area;
} }
@ -1431,11 +1456,11 @@ static float cellArea(Rtree *pRtree, RtreeCell *p){
** Return the margin length of cell p. The margin length is the sum ** Return the margin length of cell p. The margin length is the sum
** of the objects size in each dimension. ** of the objects size in each dimension.
*/ */
static float cellMargin(Rtree *pRtree, RtreeCell *p){ static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
float margin = 0.0; RtreeDValue margin = (RtreeDValue)0;
int ii; int ii;
for(ii=0; ii<(pRtree->nDim*2); ii+=2){ for(ii=0; ii<(pRtree->nDim*2); ii+=2){
margin += (float)(DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])); margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
} }
return margin; return margin;
} }
@ -1480,8 +1505,8 @@ static int cellContains(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){
/* /*
** Return the amount cell p would grow by if it were unioned with pCell. ** Return the amount cell p would grow by if it were unioned with pCell.
*/ */
static float cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){ static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
float area; RtreeDValue area;
RtreeCell cell; RtreeCell cell;
memcpy(&cell, p, sizeof(RtreeCell)); memcpy(&cell, p, sizeof(RtreeCell));
area = cellArea(pRtree, &cell); area = cellArea(pRtree, &cell);
@ -1490,7 +1515,7 @@ static float cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
} }
#if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLIT #if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLIT
static float cellOverlap( static RtreeDValue cellOverlap(
Rtree *pRtree, Rtree *pRtree,
RtreeCell *p, RtreeCell *p,
RtreeCell *aCell, RtreeCell *aCell,
@ -1498,7 +1523,7 @@ static float cellOverlap(
int iExclude int iExclude
){ ){
int ii; int ii;
float overlap = 0.0; RtreeDValue overlap = 0.0;
for(ii=0; ii<nCell; ii++){ for(ii=0; ii<nCell; ii++){
#if VARIANT_RSTARTREE_CHOOSESUBTREE #if VARIANT_RSTARTREE_CHOOSESUBTREE
if( ii!=iExclude ) if( ii!=iExclude )
@ -1508,10 +1533,9 @@ static float cellOverlap(
#endif #endif
{ {
int jj; int jj;
float o = 1.0; RtreeDValue o = (RtreeDValue)1;
for(jj=0; jj<(pRtree->nDim*2); jj+=2){ for(jj=0; jj<(pRtree->nDim*2); jj+=2){
double x1; RtreeDValue x1, x2;
double x2;
x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj]));
x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1]));
@ -1520,7 +1544,7 @@ static float cellOverlap(
o = 0.0; o = 0.0;
break; break;
}else{ }else{
o = o * (float)(x2-x1); o = o * (x2-x1);
} }
} }
overlap += o; overlap += o;
@ -1531,7 +1555,7 @@ static float cellOverlap(
#endif #endif
#if VARIANT_RSTARTREE_CHOOSESUBTREE #if VARIANT_RSTARTREE_CHOOSESUBTREE
static float cellOverlapEnlargement( static RtreeDValue cellOverlapEnlargement(
Rtree *pRtree, Rtree *pRtree,
RtreeCell *p, RtreeCell *p,
RtreeCell *pInsert, RtreeCell *pInsert,
@ -1539,12 +1563,11 @@ static float cellOverlapEnlargement(
int nCell, int nCell,
int iExclude int iExclude
){ ){
double before; RtreeDValue before, after;
double after;
before = cellOverlap(pRtree, p, aCell, nCell, iExclude); before = cellOverlap(pRtree, p, aCell, nCell, iExclude);
cellUnion(pRtree, p, pInsert); cellUnion(pRtree, p, pInsert);
after = cellOverlap(pRtree, p, aCell, nCell, iExclude); after = cellOverlap(pRtree, p, aCell, nCell, iExclude);
return (float)(after-before); return (after-before);
} }
#endif #endif
@ -1568,11 +1591,11 @@ static int ChooseLeaf(
int iCell; int iCell;
sqlite3_int64 iBest = 0; sqlite3_int64 iBest = 0;
float fMinGrowth = 0.0; RtreeDValue fMinGrowth = 0.0;
float fMinArea = 0.0; RtreeDValue fMinArea = 0.0;
#if VARIANT_RSTARTREE_CHOOSESUBTREE #if VARIANT_RSTARTREE_CHOOSESUBTREE
float fMinOverlap = 0.0; RtreeDValue fMinOverlap = 0.0;
float overlap; RtreeDValue overlap;
#endif #endif
int nCell = NCELL(pNode); int nCell = NCELL(pNode);
@ -1603,8 +1626,8 @@ static int ChooseLeaf(
*/ */
for(iCell=0; iCell<nCell; iCell++){ for(iCell=0; iCell<nCell; iCell++){
int bBest = 0; int bBest = 0;
float growth; RtreeDValue growth;
float area; RtreeDValue area;
nodeGetCell(pRtree, pNode, iCell, &cell); nodeGetCell(pRtree, pNode, iCell, &cell);
growth = cellGrowth(pRtree, &cell, pCell); growth = cellGrowth(pRtree, &cell, pCell);
area = cellArea(pRtree, &cell); area = cellArea(pRtree, &cell);
@ -1731,7 +1754,7 @@ static void LinearPickSeeds(
int i; int i;
int iLeftSeed = 0; int iLeftSeed = 0;
int iRightSeed = 1; int iRightSeed = 1;
float maxNormalInnerWidth = 0.0; RtreeDValue maxNormalInnerWidth = (RtreeDValue)0;
/* Pick two "seed" cells from the array of cells. The algorithm used /* Pick two "seed" cells from the array of cells. The algorithm used
** here is the LinearPickSeeds algorithm from Gutman[1984]. The ** here is the LinearPickSeeds algorithm from Gutman[1984]. The
@ -1739,18 +1762,18 @@ static void LinearPickSeeds(
** variables iLeftSeek and iRightSeed. ** variables iLeftSeek and iRightSeed.
*/ */
for(i=0; i<pRtree->nDim; i++){ for(i=0; i<pRtree->nDim; i++){
float x1 = DCOORD(aCell[0].aCoord[i*2]); RtreeDValue x1 = DCOORD(aCell[0].aCoord[i*2]);
float x2 = DCOORD(aCell[0].aCoord[i*2+1]); RtreeDValue x2 = DCOORD(aCell[0].aCoord[i*2+1]);
float x3 = x1; RtreeDValue x3 = x1;
float x4 = x2; RtreeDValue x4 = x2;
int jj; int jj;
int iCellLeft = 0; int iCellLeft = 0;
int iCellRight = 0; int iCellRight = 0;
for(jj=1; jj<nCell; jj++){ for(jj=1; jj<nCell; jj++){
float left = DCOORD(aCell[jj].aCoord[i*2]); RtreeDValue left = DCOORD(aCell[jj].aCoord[i*2]);
float right = DCOORD(aCell[jj].aCoord[i*2+1]); RtreeDValue right = DCOORD(aCell[jj].aCoord[i*2+1]);
if( left<x1 ) x1 = left; if( left<x1 ) x1 = left;
if( right>x4 ) x4 = right; if( right>x4 ) x4 = right;
@ -1765,7 +1788,7 @@ static void LinearPickSeeds(
} }
if( x4!=x1 ){ if( x4!=x1 ){
float normalwidth = (x3 - x2) / (x4 - x1); RtreeDValue normalwidth = (x3 - x2) / (x4 - x1);
if( normalwidth>maxNormalInnerWidth ){ if( normalwidth>maxNormalInnerWidth ){
iLeftSeed = iCellLeft; iLeftSeed = iCellLeft;
iRightSeed = iCellRight; iRightSeed = iCellRight;
@ -1794,13 +1817,13 @@ static RtreeCell *QuadraticPickNext(
#define FABS(a) ((a)<0.0?-1.0*(a):(a)) #define FABS(a) ((a)<0.0?-1.0*(a):(a))
int iSelect = -1; int iSelect = -1;
float fDiff; RtreeDValue fDiff;
int ii; int ii;
for(ii=0; ii<nCell; ii++){ for(ii=0; ii<nCell; ii++){
if( aiUsed[ii]==0 ){ if( aiUsed[ii]==0 ){
float left = cellGrowth(pRtree, pLeftBox, &aCell[ii]); RtreeDValue left = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
float right = cellGrowth(pRtree, pLeftBox, &aCell[ii]); RtreeDValue right = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
float diff = FABS(right-left); RtreeDValue diff = FABS(right-left);
if( iSelect<0 || diff>fDiff ){ if( iSelect<0 || diff>fDiff ){
fDiff = diff; fDiff = diff;
iSelect = ii; iSelect = ii;
@ -1827,13 +1850,13 @@ static void QuadraticPickSeeds(
int iLeftSeed = 0; int iLeftSeed = 0;
int iRightSeed = 1; int iRightSeed = 1;
float fWaste = 0.0; RtreeDValue fWaste = 0.0;
for(ii=0; ii<nCell; ii++){ for(ii=0; ii<nCell; ii++){
for(jj=ii+1; jj<nCell; jj++){ for(jj=ii+1; jj<nCell; jj++){
float right = cellArea(pRtree, &aCell[jj]); RtreeDValue right = cellArea(pRtree, &aCell[jj]);
float growth = cellGrowth(pRtree, &aCell[ii], &aCell[jj]); RtreeDValue growth = cellGrowth(pRtree, &aCell[ii], &aCell[jj]);
float waste = growth - right; RtreeDValue waste = growth - right;
if( waste>fWaste ){ if( waste>fWaste ){
iLeftSeed = ii; iLeftSeed = ii;
@ -1868,7 +1891,7 @@ static void QuadraticPickSeeds(
static void SortByDistance( static void SortByDistance(
int *aIdx, int *aIdx,
int nIdx, int nIdx,
float *aDistance, RtreeDValue *aDistance,
int *aSpare int *aSpare
){ ){
if( nIdx>1 ){ if( nIdx>1 ){
@ -1894,8 +1917,8 @@ static void SortByDistance(
aIdx[iLeft+iRight] = aLeft[iLeft]; aIdx[iLeft+iRight] = aLeft[iLeft];
iLeft++; iLeft++;
}else{ }else{
float fLeft = aDistance[aLeft[iLeft]]; RtreeDValue fLeft = aDistance[aLeft[iLeft]];
float fRight = aDistance[aRight[iRight]]; RtreeDValue fRight = aDistance[aRight[iRight]];
if( fLeft<fRight ){ if( fLeft<fRight ){
aIdx[iLeft+iRight] = aLeft[iLeft]; aIdx[iLeft+iRight] = aLeft[iLeft];
iLeft++; iLeft++;
@ -1911,8 +1934,8 @@ static void SortByDistance(
{ {
int jj; int jj;
for(jj=1; jj<nIdx; jj++){ for(jj=1; jj<nIdx; jj++){
float left = aDistance[aIdx[jj-1]]; RtreeDValue left = aDistance[aIdx[jj-1]];
float right = aDistance[aIdx[jj]]; RtreeDValue right = aDistance[aIdx[jj]];
assert( left<=right ); assert( left<=right );
} }
} }
@ -1955,10 +1978,10 @@ static void SortByDimension(
memcpy(aSpare, aLeft, sizeof(int)*nLeft); memcpy(aSpare, aLeft, sizeof(int)*nLeft);
aLeft = aSpare; aLeft = aSpare;
while( iLeft<nLeft || iRight<nRight ){ while( iLeft<nLeft || iRight<nRight ){
double xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]); RtreeDValue xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]);
double xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]); RtreeDValue xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]);
double xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]); RtreeDValue xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]);
double xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]); RtreeDValue xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]);
if( (iLeft!=nLeft) && ((iRight==nRight) if( (iLeft!=nLeft) && ((iRight==nRight)
|| (xleft1<xright1) || (xleft1<xright1)
|| (xleft1==xright1 && xleft2<xright2) || (xleft1==xright1 && xleft2<xright2)
@ -1976,10 +1999,10 @@ static void SortByDimension(
{ {
int jj; int jj;
for(jj=1; jj<nIdx; jj++){ for(jj=1; jj<nIdx; jj++){
float xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2]; RtreeDValue xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2];
float xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1]; RtreeDValue xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1];
float xright1 = aCell[aIdx[jj]].aCoord[iDim*2]; RtreeDValue xright1 = aCell[aIdx[jj]].aCoord[iDim*2];
float xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1]; RtreeDValue xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1];
assert( xleft1<=xright1 && (xleft1<xright1 || xleft2<=xright2) ); assert( xleft1<=xright1 && (xleft1<xright1 || xleft2<=xright2) );
} }
} }
@ -2006,7 +2029,7 @@ static int splitNodeStartree(
int iBestDim = 0; int iBestDim = 0;
int iBestSplit = 0; int iBestSplit = 0;
float fBestMargin = 0.0; RtreeDValue fBestMargin = 0.0;
int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int)); int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
@ -2027,9 +2050,9 @@ static int splitNodeStartree(
} }
for(ii=0; ii<pRtree->nDim; ii++){ for(ii=0; ii<pRtree->nDim; ii++){
float margin = 0.0; RtreeDValue margin = 0.0;
float fBestOverlap = 0.0; RtreeDValue fBestOverlap = 0.0;
float fBestArea = 0.0; RtreeDValue fBestArea = 0.0;
int iBestLeft = 0; int iBestLeft = 0;
int nLeft; int nLeft;
@ -2041,8 +2064,8 @@ static int splitNodeStartree(
RtreeCell left; RtreeCell left;
RtreeCell right; RtreeCell right;
int kk; int kk;
float overlap; RtreeDValue overlap;
float area; RtreeDValue area;
memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell)); memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell));
memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell)); memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell));
@ -2125,7 +2148,7 @@ static int splitNodeGuttman(
for(i=nCell-2; i>0; i--){ for(i=nCell-2; i>0; i--){
RtreeCell *pNext; RtreeCell *pNext;
pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed); pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed);
float diff = RtreeDValue diff =
cellGrowth(pRtree, pBboxLeft, pNext) - cellGrowth(pRtree, pBboxLeft, pNext) -
cellGrowth(pRtree, pBboxRight, pNext) cellGrowth(pRtree, pBboxRight, pNext)
; ;
@ -2458,32 +2481,34 @@ static int Reinsert(
int *aOrder; int *aOrder;
int *aSpare; int *aSpare;
RtreeCell *aCell; RtreeCell *aCell;
float *aDistance; RtreeDValue *aDistance;
int nCell; int nCell;
float aCenterCoord[RTREE_MAX_DIMENSIONS]; RtreeDValue aCenterCoord[RTREE_MAX_DIMENSIONS];
int iDim; int iDim;
int ii; int ii;
int rc = SQLITE_OK; int rc = SQLITE_OK;
int n;
memset(aCenterCoord, 0, sizeof(float)*RTREE_MAX_DIMENSIONS); memset(aCenterCoord, 0, sizeof(RtreeDValue)*RTREE_MAX_DIMENSIONS);
nCell = NCELL(pNode)+1; nCell = NCELL(pNode)+1;
n = (nCell+1)&(~1);
/* Allocate the buffers used by this operation. The allocation is /* Allocate the buffers used by this operation. The allocation is
** relinquished before this function returns. ** relinquished before this function returns.
*/ */
aCell = (RtreeCell *)sqlite3_malloc(nCell * ( aCell = (RtreeCell *)sqlite3_malloc(n * (
sizeof(RtreeCell) + /* aCell array */ sizeof(RtreeCell) + /* aCell array */
sizeof(int) + /* aOrder array */ sizeof(int) + /* aOrder array */
sizeof(int) + /* aSpare array */ sizeof(int) + /* aSpare array */
sizeof(float) /* aDistance array */ sizeof(RtreeDValue) /* aDistance array */
)); ));
if( !aCell ){ if( !aCell ){
return SQLITE_NOMEM; return SQLITE_NOMEM;
} }
aOrder = (int *)&aCell[nCell]; aOrder = (int *)&aCell[n];
aSpare = (int *)&aOrder[nCell]; aSpare = (int *)&aOrder[n];
aDistance = (float *)&aSpare[nCell]; aDistance = (RtreeDValue *)&aSpare[n];
for(ii=0; ii<nCell; ii++){ for(ii=0; ii<nCell; ii++){
if( ii==(nCell-1) ){ if( ii==(nCell-1) ){
@ -2493,19 +2518,19 @@ static int Reinsert(
} }
aOrder[ii] = ii; aOrder[ii] = ii;
for(iDim=0; iDim<pRtree->nDim; iDim++){ for(iDim=0; iDim<pRtree->nDim; iDim++){
aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2]); aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]);
aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2+1]); aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]);
} }
} }
for(iDim=0; iDim<pRtree->nDim; iDim++){ for(iDim=0; iDim<pRtree->nDim; iDim++){
aCenterCoord[iDim] = (float)(aCenterCoord[iDim]/((float)nCell*2.0)); aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2));
} }
for(ii=0; ii<nCell; ii++){ for(ii=0; ii<nCell; ii++){
aDistance[ii] = 0.0; aDistance[ii] = 0.0;
for(iDim=0; iDim<pRtree->nDim; iDim++){ for(iDim=0; iDim<pRtree->nDim; iDim++){
float coord = (float)(DCOORD(aCell[ii].aCoord[iDim*2+1]) - RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) -
DCOORD(aCell[ii].aCoord[iDim*2])); DCOORD(aCell[ii].aCoord[iDim*2]));
aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]); aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
} }
} }
@ -2747,16 +2772,19 @@ static int rtreeUpdate(
/* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */ /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */
assert( nData==(pRtree->nDim*2 + 3) ); assert( nData==(pRtree->nDim*2 + 3) );
#ifndef SQLITE_RTREE_INT_ONLY
if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
for(ii=0; ii<(pRtree->nDim*2); ii+=2){ for(ii=0; ii<(pRtree->nDim*2); ii+=2){
cell.aCoord[ii].f = (float)sqlite3_value_double(azData[ii+3]); cell.aCoord[ii].f = (RtreeValue)sqlite3_value_double(azData[ii+3]);
cell.aCoord[ii+1].f = (float)sqlite3_value_double(azData[ii+4]); cell.aCoord[ii+1].f = (RtreeValue)sqlite3_value_double(azData[ii+4]);
if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){ if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
rc = SQLITE_CONSTRAINT; rc = SQLITE_CONSTRAINT;
goto constraint; goto constraint;
} }
} }
}else{ }else
#endif
{
for(ii=0; ii<(pRtree->nDim*2); ii+=2){ for(ii=0; ii<(pRtree->nDim*2); ii+=2){
cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]); cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]); cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]);
@ -3154,7 +3182,13 @@ static void rtreenode(sqlite3_context *ctx, int nArg, sqlite3_value **apArg){
sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid); sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
nCell = (int)strlen(zCell); nCell = (int)strlen(zCell);
for(jj=0; jj<tree.nDim*2; jj++){ for(jj=0; jj<tree.nDim*2; jj++){
sqlite3_snprintf(512-nCell,&zCell[nCell]," %f",(double)cell.aCoord[jj].f); #ifndef SQLITE_RTREE_INT_ONLY
sqlite3_snprintf(512-nCell,&zCell[nCell], " %f",
(double)cell.aCoord[jj].f);
#else
sqlite3_snprintf(512-nCell,&zCell[nCell], " %d",
cell.aCoord[jj].i);
#endif
nCell = (int)strlen(zCell); nCell = (int)strlen(zCell);
} }
@ -3196,7 +3230,11 @@ int sqlite3RtreeInit(sqlite3 *db){
rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0); rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
#ifdef SQLITE_RTREE_INT_ONLY
void *c = (void *)RTREE_COORD_INT32;
#else
void *c = (void *)RTREE_COORD_REAL32; void *c = (void *)RTREE_COORD_REAL32;
#endif
rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0); rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0);
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
@ -3230,7 +3268,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
RtreeMatchArg *pBlob; RtreeMatchArg *pBlob;
int nBlob; int nBlob;
nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(double); nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue);
pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob); pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob);
if( !pBlob ){ if( !pBlob ){
sqlite3_result_error_nomem(ctx); sqlite3_result_error_nomem(ctx);
@ -3241,7 +3279,11 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
pBlob->pContext = pGeomCtx->pContext; pBlob->pContext = pGeomCtx->pContext;
pBlob->nParam = nArg; pBlob->nParam = nArg;
for(i=0; i<nArg; i++){ for(i=0; i<nArg; i++){
#ifdef SQLITE_RTREE_INT_ONLY
pBlob->aParam[i] = sqlite3_value_int64(aArg[i]);
#else
pBlob->aParam[i] = sqlite3_value_double(aArg[i]); pBlob->aParam[i] = sqlite3_value_double(aArg[i]);
#endif
} }
sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free); sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free);
} }
@ -3253,7 +3295,7 @@ static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
int sqlite3_rtree_geometry_callback( int sqlite3_rtree_geometry_callback(
sqlite3 *db, sqlite3 *db,
const char *zGeom, const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *), int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue *, int *),
void *pContext void *pContext
){ ){
RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */ RtreeGeomCallback *pGeomCtx; /* Context object for new user-function */

View File

@ -104,6 +104,18 @@ for {set nCol 1} {$nCol<[llength $cols]} {incr nCol} {
catchsql { DROP TABLE t1 } catchsql { DROP TABLE t1 }
} }
# Like execsql except display output as integer where that can be
# done without loss of information.
#
proc execsql_intout {sql} {
set out {}
foreach term [execsql $sql] {
regsub {\.0$} $term {} term
lappend out $term
}
return $out
}
# Test that it is possible to open an existing database that contains # Test that it is possible to open an existing database that contains
# r-tree tables. # r-tree tables.
# #
@ -117,8 +129,8 @@ do_test rtree-1.4.1 {
do_test rtree-1.4.2 { do_test rtree-1.4.2 {
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql { SELECT * FROM t1 ORDER BY ii } execsql_intout { SELECT * FROM t1 ORDER BY ii }
} {1 5.0 10.0 2 15.0 20.0} } {1 5 10 2 15 20}
do_test rtree-1.4.3 { do_test rtree-1.4.3 {
execsql { DROP TABLE t1 } execsql { DROP TABLE t1 }
} {} } {}
@ -127,12 +139,12 @@ do_test rtree-1.4.3 {
# column names. # column names.
# #
do_test rtree-1.5.1 { do_test rtree-1.5.1 {
execsql { execsql_intout {
CREATE VIRTUAL TABLE t1 USING rtree("the key", "x dim.", "x2'dim"); CREATE VIRTUAL TABLE t1 USING rtree("the key", "x dim.", "x2'dim");
INSERT INTO t1 VALUES(1, 2, 3); INSERT INTO t1 VALUES(1, 2, 3);
SELECT "the key", "x dim.", "x2'dim" FROM t1; SELECT "the key", "x dim.", "x2'dim" FROM t1;
} }
} {1 2.0 3.0} } {1 2 3}
do_test rtree-1.5.1 { do_test rtree-1.5.1 {
execsql { DROP TABLE t1 } execsql { DROP TABLE t1 }
} {} } {}
@ -161,8 +173,8 @@ do_test rtree-2.1.1 {
do_test rtree-2.1.2 { do_test rtree-2.1.2 {
execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) } execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
execsql { SELECT * FROM t1 } execsql_intout { SELECT * FROM t1 }
} {1 1.0 3.0 2.0 4.0} } {1 1 3 2 4}
do_test rtree-2.1.3 { do_test rtree-2.1.3 {
execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) } execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
execsql { SELECT rowid FROM t1 ORDER BY rowid } execsql { SELECT rowid FROM t1 ORDER BY rowid }
@ -201,17 +213,17 @@ do_test rtree-3.1.1 {
} }
} {} } {}
do_test rtree-3.1.2 { do_test rtree-3.1.2 {
execsql { execsql_intout {
INSERT INTO t1 VALUES(5, 1, 3, 2, 4); INSERT INTO t1 VALUES(5, 1, 3, 2, 4);
SELECT * FROM t1; SELECT * FROM t1;
} }
} {5 1.0 3.0 2.0 4.0} } {5 1 3 2 4}
do_test rtree-3.1.3 { do_test rtree-3.1.3 {
execsql { execsql_intout {
INSERT INTO t1 VALUES(6, 2, 6, 4, 8); INSERT INTO t1 VALUES(6, 2, 6, 4, 8);
SELECT * FROM t1; SELECT * FROM t1;
} }
} {5 1.0 3.0 2.0 4.0 6 2.0 6.0 4.0 8.0} } {5 1 3 2 4 6 2 6 4 8}
# Test the constraint on the coordinates (c[i]<=c[i+1] where (i%2==0)): # Test the constraint on the coordinates (c[i]<=c[i+1] where (i%2==0)):
do_test rtree-3.2.1 { do_test rtree-3.2.1 {
@ -228,25 +240,25 @@ do_test rtree-5.1.1 {
execsql { CREATE VIRTUAL TABLE t2 USING rtree(ii, x1, x2) } execsql { CREATE VIRTUAL TABLE t2 USING rtree(ii, x1, x2) }
} {} } {}
do_test rtree-5.1.2 { do_test rtree-5.1.2 {
execsql { execsql_intout {
INSERT INTO t2 VALUES(1, 10, 20); INSERT INTO t2 VALUES(1, 10, 20);
INSERT INTO t2 VALUES(2, 30, 40); INSERT INTO t2 VALUES(2, 30, 40);
INSERT INTO t2 VALUES(3, 50, 60); INSERT INTO t2 VALUES(3, 50, 60);
SELECT * FROM t2 ORDER BY ii; SELECT * FROM t2 ORDER BY ii;
} }
} {1 10.0 20.0 2 30.0 40.0 3 50.0 60.0} } {1 10 20 2 30 40 3 50 60}
do_test rtree-5.1.3 { do_test rtree-5.1.3 {
execsql { execsql_intout {
DELETE FROM t2 WHERE ii=2; DELETE FROM t2 WHERE ii=2;
SELECT * FROM t2 ORDER BY ii; SELECT * FROM t2 ORDER BY ii;
} }
} {1 10.0 20.0 3 50.0 60.0} } {1 10 20 3 50 60}
do_test rtree-5.1.4 { do_test rtree-5.1.4 {
execsql { execsql_intout {
DELETE FROM t2 WHERE ii=1; DELETE FROM t2 WHERE ii=1;
SELECT * FROM t2 ORDER BY ii; SELECT * FROM t2 ORDER BY ii;
} }
} {3 50.0 60.0} } {3 50 60}
do_test rtree-5.1.5 { do_test rtree-5.1.5 {
execsql { execsql {
DELETE FROM t2 WHERE ii=3; DELETE FROM t2 WHERE ii=3;
@ -264,16 +276,16 @@ do_test rtree-6.1.1 {
execsql { CREATE VIRTUAL TABLE t3 USING rtree(ii, x1, x2, y1, y2) } execsql { CREATE VIRTUAL TABLE t3 USING rtree(ii, x1, x2, y1, y2) }
} {} } {}
do_test rtree-6.1.2 { do_test rtree-6.1.2 {
execsql { execsql_intout {
INSERT INTO t3 VALUES(1, 2, 3, 4, 5); INSERT INTO t3 VALUES(1, 2, 3, 4, 5);
UPDATE t3 SET x2=5; UPDATE t3 SET x2=5;
SELECT * FROM t3; SELECT * FROM t3;
} }
} {1 2.0 5.0 4.0 5.0} } {1 2 5 4 5}
do_test rtree-6.1.3 { do_test rtree-6.1.3 {
execsql { UPDATE t3 SET ii = 2 } execsql { UPDATE t3 SET ii = 2 }
execsql { SELECT * FROM t3 } execsql_intout { SELECT * FROM t3 }
} {2 2.0 5.0 4.0 5.0} } {2 2 5 4 5}
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------
# Test cases rtree-7.* test rename operations. # Test cases rtree-7.* test rename operations.
@ -286,29 +298,29 @@ do_test rtree-7.1.1 {
} {} } {}
do_test rtree-7.1.2 { do_test rtree-7.1.2 {
execsql { ALTER TABLE t4 RENAME TO t5 } execsql { ALTER TABLE t4 RENAME TO t5 }
execsql { SELECT * FROM t5 } execsql_intout { SELECT * FROM t5 }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.1.3 { do_test rtree-7.1.3 {
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql { SELECT * FROM t5 } execsql_intout { SELECT * FROM t5 }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.1.4 { do_test rtree-7.1.4 {
execsql { ALTER TABLE t5 RENAME TO 'raisara "one"'''} execsql { ALTER TABLE t5 RENAME TO 'raisara "one"'''}
execsql { SELECT * FROM "raisara ""one""'" } execsql_intout { SELECT * FROM "raisara ""one""'" }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.1.5 { do_test rtree-7.1.5 {
execsql { SELECT * FROM 'raisara "one"''' } execsql_intout { SELECT * FROM 'raisara "one"''' }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.1.6 { do_test rtree-7.1.6 {
execsql { ALTER TABLE "raisara ""one""'" RENAME TO "abc 123" } execsql { ALTER TABLE "raisara ""one""'" RENAME TO "abc 123" }
execsql { SELECT * FROM "abc 123" } execsql_intout { SELECT * FROM "abc 123" }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.1.7 { do_test rtree-7.1.7 {
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql { SELECT * FROM "abc 123" } execsql_intout { SELECT * FROM "abc 123" }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
# An error midway through a rename operation. # An error midway through a rename operation.
do_test rtree-7.2.1 { do_test rtree-7.2.1 {
@ -318,8 +330,8 @@ do_test rtree-7.2.1 {
catchsql { ALTER TABLE "abc 123" RENAME TO t4 } catchsql { ALTER TABLE "abc 123" RENAME TO t4 }
} {1 {SQL logic error or missing database}} } {1 {SQL logic error or missing database}}
do_test rtree-7.2.2 { do_test rtree-7.2.2 {
execsql { SELECT * FROM "abc 123" } execsql_intout { SELECT * FROM "abc 123" }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.2.3 { do_test rtree-7.2.3 {
execsql { execsql {
DROP TABLE t4_node; DROP TABLE t4_node;
@ -330,13 +342,13 @@ do_test rtree-7.2.3 {
do_test rtree-7.2.4 { do_test rtree-7.2.4 {
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql { SELECT * FROM "abc 123" } execsql_intout { SELECT * FROM "abc 123" }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
do_test rtree-7.2.5 { do_test rtree-7.2.5 {
execsql { DROP TABLE t4_rowid } execsql { DROP TABLE t4_rowid }
execsql { ALTER TABLE "abc 123" RENAME TO t4 } execsql { ALTER TABLE "abc 123" RENAME TO t4 }
execsql { SELECT * FROM t4 } execsql_intout { SELECT * FROM t4 }
} {1 2.0 3.0 4.0 5.0 6.0 7.0} } {1 2 3 4 5 6 7}
#---------------------------------------------------------------------------- #----------------------------------------------------------------------------

View File

@ -27,21 +27,38 @@ if {[info exists G(isquick)] && $G(isquick)} {
set ::NROW 250 set ::NROW 250
} }
# Return a floating point number between -X and X. ifcapable !rtree_int_only {
# # Return a floating point number between -X and X.
proc rand {X} { #
return [expr {int((rand()-0.5)*1024.0*$X)/512.0}] proc rand {X} {
} return [expr {int((rand()-0.5)*1024.0*$X)/512.0}]
}
# Return a positive floating point number less than or equal to X
# # Return a positive floating point number less than or equal to X
proc randincr {X} { #
while 1 { proc randincr {X} {
set r [expr {int(rand()*$X*32.0)/32.0}] while 1 {
if {$r>0.0} {return $r} set r [expr {int(rand()*$X*32.0)/32.0}]
if {$r>0.0} {return $r}
}
}
} else {
# For rtree_int_only, return an number between -X and X.
#
proc rand {X} {
return [expr {int((rand()-0.5)*2*$X)}]
}
# Return a positive integer less than or equal to X
#
proc randincr {X} {
while 1 {
set r [expr {int(rand()*$X)+1}]
if {$r>0} {return $r}
}
} }
} }
# Scramble the $inlist into a random order. # Scramble the $inlist into a random order.
# #
proc scramble {inlist} { proc scramble {inlist} {

View File

@ -49,9 +49,11 @@ do_test rtree5-1.6 {
do_test rtree5-1.7 { do_test rtree5-1.7 {
execsql { SELECT count(*) FROM t1 WHERE x1==5 } execsql { SELECT count(*) FROM t1 WHERE x1==5 }
} {1} } {1}
do_test rtree5-1.8 { ifcapable !rtree_int_only {
execsql { SELECT count(*) FROM t1 WHERE x1==5.2 } do_test rtree5-1.8 {
} {0} execsql { SELECT count(*) FROM t1 WHERE x1==5.2 }
} {0}
}
do_test rtree5-1.9 { do_test rtree5-1.9 {
execsql { SELECT count(*) FROM t1 WHERE x1==5.0 } execsql { SELECT count(*) FROM t1 WHERE x1==5.0 }
} {1} } {1}

View File

@ -16,7 +16,7 @@ if {![info exists testdir]} {
} }
source $testdir/tester.tcl source $testdir/tester.tcl
ifcapable !rtree { ifcapable !rtree || rtree_int_only {
finish_test finish_test
return return
} }

View File

@ -24,6 +24,18 @@ ifcapable !rtree||!vacuum {
return return
} }
# Like execsql except display output as integer where that can be
# done without loss of information.
#
proc execsql_intout {sql} {
set out {}
foreach term [execsql $sql] {
regsub {\.0$} $term {} term
lappend out $term
}
return $out
}
do_test rtree7-1.1 { do_test rtree7-1.1 {
execsql { execsql {
PRAGMA page_size = 1024; PRAGMA page_size = 1024;
@ -32,27 +44,27 @@ do_test rtree7-1.1 {
} }
} {} } {}
do_test rtree7-1.2 { do_test rtree7-1.2 {
execsql { SELECT * FROM rt } execsql_intout { SELECT * FROM rt }
} {1 1.0 2.0 3.0 4.0} } {1 1 2 3 4}
do_test rtree7-1.3 { do_test rtree7-1.3 {
execsql { execsql_intout {
PRAGMA page_size = 2048; PRAGMA page_size = 2048;
VACUUM; VACUUM;
SELECT * FROM rt; SELECT * FROM rt;
} }
} {1 1.0 2.0 3.0 4.0} } {1 1 2 3 4}
do_test rtree7-1.4 { do_test rtree7-1.4 {
for {set i 2} {$i <= 51} {incr i} { for {set i 2} {$i <= 51} {incr i} {
execsql { INSERT INTO rt VALUES($i, 1, 2, 3, 4) } execsql { INSERT INTO rt VALUES($i, 1, 2, 3, 4) }
} }
execsql { SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt } execsql_intout { SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt }
} {51.0 102.0 153.0 204.0} } {51 102 153 204}
do_test rtree7-1.5 { do_test rtree7-1.5 {
execsql { execsql_intout {
PRAGMA page_size = 512; PRAGMA page_size = 512;
VACUUM; VACUUM;
SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt
} }
} {51.0 102.0 153.0 204.0} } {51 102 153 204}
finish_test finish_test

View File

@ -17,6 +17,7 @@ if {![info exists testdir]} {
} }
source $testdir/tester.tcl source $testdir/tester.tcl
ifcapable !rtree { finish_test ; return } ifcapable !rtree { finish_test ; return }
ifcapable rtree_int_only { finish_test; return }
register_cube_geom db register_cube_geom db

View File

@ -18,17 +18,30 @@ if {![info exists testdir]} {
source $testdir/tester.tcl source $testdir/tester.tcl
ifcapable !rtree { finish_test ; return } ifcapable !rtree { finish_test ; return }
do_test rtreeB-1.1 { ifcapable rtree_int_only {
db eval { do_test rtreeB-1.1-intonly {
CREATE VIRTUAL TABLE t1 USING rtree(ii, x0, y0, x1, y1); db eval {
INSERT INTO t1 VALUES(1073741824, 0.0, 0.0, 100.0, 100.0); CREATE VIRTUAL TABLE t1 USING rtree(ii, x0, y0, x1, y1);
INSERT INTO t1 VALUES(2147483646, 0.0, 0.0, 200.0, 200.0); INSERT INTO t1 VALUES(1073741824, 0.0, 0.0, 100.0, 100.0);
INSERT INTO t1 VALUES(4294967296, 0.0, 0.0, 300.0, 300.0); INSERT INTO t1 VALUES(2147483646, 0.0, 0.0, 200.0, 200.0);
INSERT INTO t1 VALUES(8589934592, 20.0, 20.0, 150.0, 150.0); INSERT INTO t1 VALUES(4294967296, 0.0, 0.0, 300.0, 300.0);
INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400); INSERT INTO t1 VALUES(8589934592, 20.0, 20.0, 150.0, 150.0);
SELECT rtreenode(2, data) FROM t1_node; INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400);
} SELECT rtreenode(2, data) FROM t1_node;
} {{{1073741824 0.000000 0.000000 100.000000 100.000000} {2147483646 0.000000 0.000000 200.000000 200.000000} {4294967296 0.000000 0.000000 300.000000 300.000000} {8589934592 20.000000 20.000000 150.000000 150.000000} {9223372036854775807 150.000000 150.000000 400.000000 400.000000}}} }
} {{{1073741824 0 0 100 100} {2147483646 0 0 200 200} {4294967296 0 0 300 300} {8589934592 20 20 150 150} {9223372036854775807 150 150 400 400}}}
} else {
do_test rtreeB-1.1 {
db eval {
CREATE VIRTUAL TABLE t1 USING rtree(ii, x0, y0, x1, y1);
INSERT INTO t1 VALUES(1073741824, 0.0, 0.0, 100.0, 100.0);
INSERT INTO t1 VALUES(2147483646, 0.0, 0.0, 200.0, 200.0);
INSERT INTO t1 VALUES(4294967296, 0.0, 0.0, 300.0, 300.0);
INSERT INTO t1 VALUES(8589934592, 20.0, 20.0, 150.0, 150.0);
INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400);
SELECT rtreenode(2, data) FROM t1_node;
}
} {{{1073741824 0.000000 0.000000 100.000000 100.000000} {2147483646 0.000000 0.000000 200.000000 200.000000} {4294967296 0.000000 0.000000 300.000000 300.000000} {8589934592 20.000000 20.000000 150.000000 150.000000} {9223372036854775807 150.000000 150.000000 400.000000 400.000000}}}
}
finish_test finish_test

View File

@ -31,7 +31,11 @@ typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry;
int sqlite3_rtree_geometry_callback( int sqlite3_rtree_geometry_callback(
sqlite3 *db, sqlite3 *db,
const char *zGeom, const char *zGeom,
int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes), #ifdef SQLITE_RTREE_INT_ONLY
int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes),
#else
int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes),
#endif
void *pContext void *pContext
); );

View File

@ -1,5 +1,5 @@
C Add\s#ifdefs\sto\sallow\sa\stest\sbuild\sto\ssucceed\seven\sif\sSQLITE_ENABLE_FTS3\sis\nnot\sdefined. C The\sSQLITE_RTREE_INT_ONLY\scompile-time\soption\scauses\sthe\sRTree\sextension\s\nto\suse\sonly\sinteger\smath\sand\sstore\sonly\sinteger\scoordinates.
D 2012-04-02T17:18:23.248 D 2012-04-02T21:35:42.939
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20 F Makefile.in 2f37e468503dbe79d35c9f6dffcf3fae1ae9ec20
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -86,22 +86,22 @@ F ext/icu/README.txt bf8461d8cdc6b8f514c080e4e10dc3b2bbdfefa9
F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a F ext/icu/icu.c eb9ae1d79046bd7871aa97ee6da51eb770134b5a
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
F ext/rtree/rtree.c 4c1878818fc50efe5c2c7b8809d5cd0d88c7d396 F ext/rtree/rtree.c 73502e5336162fdc8f5d1c4bdd4ec6b1299c2f2a
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
F ext/rtree/rtree1.test 28e1b8da4da98093ce3210187434dd760a8d89d8 F ext/rtree/rtree1.test e474a2b5eff231496dbd073fe67e5fbaf7f444c9
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc
F ext/rtree/rtree4.test 0061e6f464fd3dc6a79f82454c5a1c3dadbe42af F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
F ext/rtree/rtree5.test ce3d7ccae2cfd9d2e1052b462424964c9bdcda12 F ext/rtree/rtree5.test 9a229678a00f40e6aedb40cb3a07ec5444af892c
F ext/rtree/rtree6.test 0b380bd9af93f3bc496eef42502a336f58949c1b F ext/rtree/rtree6.test f67ed7d362ab9a0d13dc2b3d34939e69e0829542
F ext/rtree/rtree7.test bcb647b42920b3b5d025846689147778485cc318 F ext/rtree/rtree7.test 1fa710b9e6bf997a0c1a537b81be7bb6fded1971
F ext/rtree/rtree8.test 9772e16da71e17e02bdebf0a5188590f289ab37d F ext/rtree/rtree8.test 9772e16da71e17e02bdebf0a5188590f289ab37d
F ext/rtree/rtree9.test df9843d1a9195249c8d3b4ea6aedda2d5c73e9c2 F ext/rtree/rtree9.test d86ebf08ff6328895613ed577dd8a2a37c472c34
F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf F ext/rtree/rtreeA.test ace05e729a36e342d40cf94e9efc7b4723d9dcdf
F ext/rtree/rtreeB.test b1916a9cecb86b02529c4cc5a546e8d6e7ff10da F ext/rtree/rtreeB.test 983e567b49b5dca165940f66b87e161aa30e82b2
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195 F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea F ext/rtree/rtree_util.tcl 06aab2ed5b826545bf215fff90ecb9255a8647ea
F ext/rtree/sqlite3rtree.h 1af0899c63a688e272d69d8e746f24e76f10a3f0 F ext/rtree/sqlite3rtree.h c34c1e41d1ab80bb8ad09aae402c9c956871a765
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
@ -203,7 +203,7 @@ F src/test_async.c 0612a752896fad42d55c3999a5122af10dcf22ad
F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e F src/test_autoext.c 30e7bd98ab6d70a62bb9ba572e4c7df347fe645e
F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de F src/test_backup.c c129c91127e9b46e335715ae2e75756e25ba27de
F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2 F src/test_btree.c 47cd771250f09cdc6e12dda5bc71bc0b3abc96e2
F src/test_config.c a036a69b550ebc477ab9ca2b37269201f888436e F src/test_config.c 0de329e736eb4aa5845069bed630e5c72f012264
F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094 F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
F src/test_func.c 6232d722a4ddb193035aa13a03796bf57d6c12fd F src/test_func.c 6232d722a4ddb193035aa13a03796bf57d6c12fd
@ -223,7 +223,7 @@ F src/test_osinst.c 7f790ac89c5a585d51b341274d9691c3391e0923
F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00
F src/test_quota.c a545115f837da4ef32f6b5578f147b44cfb13fd7 F src/test_quota.c a545115f837da4ef32f6b5578f147b44cfb13fd7
F src/test_quota.h 9ffa1d3ad6d0a6a24e8670ea64b909c717ec3358 F src/test_quota.h 9ffa1d3ad6d0a6a24e8670ea64b909c717ec3358
F src/test_rtree.c 6d06306e29946dc36f528a3a2cdc3add794656f1 F src/test_rtree.c aba603c949766c4193f1068b91c787f57274e0d9
F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f
F src/test_stat.c d7035cfcc0ff1f93c000b621f36524318e004e11 F src/test_stat.c d7035cfcc0ff1f93c000b621f36524318e004e11
@ -1000,7 +1000,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
P af602d87736b52802a4e760ffeeaa28112b99d9a P fb121980e48af368353431fd04924e414b65c852
R 1de8fb5482810a4710e15863a31ff0ee R 5f487522a2da2d1baf5cda41d792b333
U drh U drh
Z 057914300e7aa29e2f4f5068087794b4 Z f6050a33b89113e7c2cd85615563f7a3

View File

@ -1 +1 @@
fb121980e48af368353431fd04924e414b65c852 02b7640f5118e0a635b68f65765191bb3171b7bd

View File

@ -420,6 +420,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
Tcl_SetVar2(interp, "sqlite_options", "rtree", "0", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "rtree", "0", TCL_GLOBAL_ONLY);
#endif #endif
#ifdef SQLITE_RTREE_INT_ONLY
Tcl_SetVar2(interp, "sqlite_options", "rtree_int_only", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "rtree_int_only", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS #ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL_GLOBAL_ONLY);
#else #else

View File

@ -49,7 +49,11 @@ static void circle_del(void *p){
static int circle_geom( static int circle_geom(
sqlite3_rtree_geometry *p, sqlite3_rtree_geometry *p,
int nCoord, int nCoord,
#ifdef SQLITE_RTREE_INT_ONLY
sqlite3_int64 *aCoord,
#else
double *aCoord, double *aCoord,
#endif
int *pRes int *pRes
){ ){
int i; /* Iterator variable */ int i; /* Iterator variable */
@ -188,8 +192,12 @@ static int gHere = 42;
*/ */
static int cube_geom( static int cube_geom(
sqlite3_rtree_geometry *p, sqlite3_rtree_geometry *p,
int nCoord, int nCoord,
#ifdef SQLITE_RTREE_INT_ONLY
sqlite3_int64 *aCoord,
#else
double *aCoord, double *aCoord,
#endif
int *piRes int *piRes
){ ){
Cube *pCube = (Cube *)p->pUser; Cube *pCube = (Cube *)p->pUser;