/ Check-in [02b7640f]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:The SQLITE_RTREE_INT_ONLY compile-time option causes the RTree extension to use only integer math and store only integer coordinates.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 02b7640f5118e0a635b68f65765191bb3171b7bd
User & Date: drh 2012-04-02 21:35:42
Context
2012-04-03
14:59
Enhance the "showdb" utility program with the "pgidx" option. Now requires linkage with the amalgamation. check-in: 4b573701 user: drh tags: trunk
2012-04-02
21:35
The SQLITE_RTREE_INT_ONLY compile-time option causes the RTree extension to use only integer math and store only integer coordinates. check-in: 02b7640f user: drh tags: trunk
17:18
Add #ifdefs to allow a test build to succeed even if SQLITE_ENABLE_FTS3 is not defined. check-in: fb121980 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to ext/rtree/rtree.c.

   178    178     int eCoordType;
   179    179   };
   180    180   
   181    181   /* Possible values for eCoordType: */
   182    182   #define RTREE_COORD_REAL32 0
   183    183   #define RTREE_COORD_INT32  1
   184    184   
          185  +/*
          186  +** If SQLITE_RTREE_INT_ONLY is defined, then this virtual table will
          187  +** only deal with integer coordinates.  No floating point operations
          188  +** will be done.
          189  +*/
          190  +#ifdef SQLITE_RTREE_INT_ONLY
          191  +  typedef sqlite3_int64 RtreeDValue;       /* High accuracy coordinate */
          192  +  typedef int RtreeValue;                  /* Low accuracy coordinate */
          193  +#else
          194  +  typedef double RtreeDValue;              /* High accuracy coordinate */
          195  +  typedef float RtreeValue;                /* Low accuracy coordinate */
          196  +#endif
          197  +
   185    198   /*
   186    199   ** The minimum number of cells allowed for a node is a third of the 
   187    200   ** maximum. In Gutman's notation:
   188    201   **
   189    202   **     m = M/3
   190    203   **
   191    204   ** If an R*-tree "Reinsert" operation is required, the same number of
................................................................................
   213    226     int iCell;                        /* Index of current cell in pNode */
   214    227     int iStrategy;                    /* Copy of idxNum search parameter */
   215    228     int nConstraint;                  /* Number of entries in aConstraint */
   216    229     RtreeConstraint *aConstraint;     /* Search constraints. */
   217    230   };
   218    231   
   219    232   union RtreeCoord {
   220         -  float f;
          233  +  RtreeValue f;
   221    234     int i;
   222    235   };
   223    236   
   224    237   /*
   225    238   ** The argument is an RtreeCoord. Return the value stored within the RtreeCoord
   226         -** formatted as a double. This macro assumes that local variable pRtree points
   227         -** to the Rtree structure associated with the RtreeCoord.
          239  +** formatted as a RtreeDValue (double or int64). This macro assumes that local
          240  +** variable pRtree points to the Rtree structure associated with the
          241  +** RtreeCoord.
   228    242   */
          243  +#ifdef SQLITE_RTREE_INT_ONLY
          244  +# define DCOORD(coord) ((RtreeDValue)coord.i)
          245  +#else
   229    246   #define DCOORD(coord) (                           \
   230    247     (pRtree->eCoordType==RTREE_COORD_REAL32) ?      \
   231    248       ((double)coord.f) :                           \
   232    249       ((double)coord.i)                             \
   233    250   )
          251  +#endif
   234    252   
   235    253   /*
   236    254   ** A search constraint.
   237    255   */
   238    256   struct RtreeConstraint {
   239    257     int iCoord;                     /* Index of constrained coordinate */
   240    258     int op;                         /* Constraining operation */
   241         -  double rValue;                  /* Constraint value. */
   242         -  int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
          259  +  RtreeDValue rValue;             /* Constraint value. */
          260  +  int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);
   243    261     sqlite3_rtree_geometry *pGeom;  /* Constraint callback argument for a MATCH */
   244    262   };
   245    263   
   246    264   /* Possible values for RtreeConstraint.op */
   247    265   #define RTREE_EQ    0x41
   248    266   #define RTREE_LE    0x42
   249    267   #define RTREE_LT    0x43
................................................................................
   283    301   /*
   284    302   ** An instance of this structure must be supplied as a blob argument to
   285    303   ** the right-hand-side of an SQL MATCH operator used to constrain an
   286    304   ** r-tree query.
   287    305   */
   288    306   struct RtreeMatchArg {
   289    307     u32 magic;                      /* Always RTREE_GEOMETRY_MAGIC */
   290         -  int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
          308  +  int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue*, int *);
   291    309     void *pContext;
   292    310     int nParam;
   293         -  double aParam[1];
          311  +  RtreeDValue aParam[1];
   294    312   };
   295    313   
   296    314   /*
   297    315   ** When a geometry callback is created (see sqlite3_rtree_geometry_callback),
   298    316   ** a single instance of the following structure is allocated. It is used
   299    317   ** as the context for the user-function created by by s_r_g_c(). The object
   300    318   ** is eventually deleted by the destructor mechanism provided by
   301    319   ** sqlite3_create_function_v2() (which is called by s_r_g_c() to create
   302    320   ** the geometry callback function).
   303    321   */
   304    322   struct RtreeGeomCallback {
   305         -  int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *);
          323  +  int (*xGeom)(sqlite3_rtree_geometry*, int, RtreeDValue*, int*);
   306    324     void *pContext;
   307    325   };
   308    326   
   309    327   #ifndef MAX
   310    328   # define MAX(x,y) ((x) < (y) ? (y) : (x))
   311    329   #endif
   312    330   #ifndef MIN
................................................................................
   864    882   static int testRtreeGeom(
   865    883     Rtree *pRtree,                  /* R-Tree object */
   866    884     RtreeConstraint *pConstraint,   /* MATCH constraint to test */
   867    885     RtreeCell *pCell,               /* Cell to test */
   868    886     int *pbRes                      /* OUT: Test result */
   869    887   ){
   870    888     int i;
   871         -  double aCoord[RTREE_MAX_DIMENSIONS*2];
          889  +  RtreeDValue aCoord[RTREE_MAX_DIMENSIONS*2];
   872    890     int nCoord = pRtree->nDim*2;
   873    891   
   874    892     assert( pConstraint->op==RTREE_MATCH );
   875    893     assert( pConstraint->pGeom );
   876    894   
   877    895     for(i=0; i<nCoord; i++){
   878    896       aCoord[i] = DCOORD(pCell->aCoord[i]);
................................................................................
   894    912     int ii;
   895    913     int bRes = 0;
   896    914     int rc = SQLITE_OK;
   897    915   
   898    916     nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
   899    917     for(ii=0; bRes==0 && ii<pCursor->nConstraint; ii++){
   900    918       RtreeConstraint *p = &pCursor->aConstraint[ii];
   901         -    double cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]);
   902         -    double cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);
          919  +    RtreeDValue cell_min = DCOORD(cell.aCoord[(p->iCoord>>1)*2]);
          920  +    RtreeDValue cell_max = DCOORD(cell.aCoord[(p->iCoord>>1)*2+1]);
   903    921   
   904    922       assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE 
   905    923           || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
   906    924       );
   907    925   
   908    926       switch( p->op ){
   909    927         case RTREE_LE: case RTREE_LT: 
................................................................................
   947    965     RtreeCell cell;
   948    966     int ii;
   949    967     *pbEof = 0;
   950    968   
   951    969     nodeGetCell(pRtree, pCursor->pNode, pCursor->iCell, &cell);
   952    970     for(ii=0; ii<pCursor->nConstraint; ii++){
   953    971       RtreeConstraint *p = &pCursor->aConstraint[ii];
   954         -    double coord = DCOORD(cell.aCoord[p->iCoord]);
          972  +    RtreeDValue coord = DCOORD(cell.aCoord[p->iCoord]);
   955    973       int res;
   956    974       assert(p->op==RTREE_LE || p->op==RTREE_LT || p->op==RTREE_GE 
   957    975           || p->op==RTREE_GT || p->op==RTREE_EQ || p->op==RTREE_MATCH
   958    976       );
   959    977       switch( p->op ){
   960    978         case RTREE_LE: res = (coord<=p->rValue); break;
   961    979         case RTREE_LT: res = (coord<p->rValue);  break;
................................................................................
  1145   1163   
  1146   1164     if( i==0 ){
  1147   1165       i64 iRowid = nodeGetRowid(pRtree, pCsr->pNode, pCsr->iCell);
  1148   1166       sqlite3_result_int64(ctx, iRowid);
  1149   1167     }else{
  1150   1168       RtreeCoord c;
  1151   1169       nodeGetCoord(pRtree, pCsr->pNode, pCsr->iCell, i-1, &c);
         1170  +#ifndef SQLITE_RTREE_INT_ONLY
  1152   1171       if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
  1153   1172         sqlite3_result_double(ctx, c.f);
  1154         -    }else{
         1173  +    }else
         1174  +#endif
         1175  +    {
  1155   1176         assert( pRtree->eCoordType==RTREE_COORD_INT32 );
  1156   1177         sqlite3_result_int(ctx, c.i);
  1157   1178       }
  1158   1179     }
  1159   1180   
  1160   1181     return SQLITE_OK;
  1161   1182   }
................................................................................
  1194   1215   
  1195   1216     /* Check that value is actually a blob. */
  1196   1217     if( sqlite3_value_type(pValue)!=SQLITE_BLOB ) return SQLITE_ERROR;
  1197   1218   
  1198   1219     /* Check that the blob is roughly the right size. */
  1199   1220     nBlob = sqlite3_value_bytes(pValue);
  1200   1221     if( nBlob<(int)sizeof(RtreeMatchArg) 
  1201         -   || ((nBlob-sizeof(RtreeMatchArg))%sizeof(double))!=0
         1222  +   || ((nBlob-sizeof(RtreeMatchArg))%sizeof(RtreeDValue))!=0
  1202   1223     ){
  1203   1224       return SQLITE_ERROR;
  1204   1225     }
  1205   1226   
  1206   1227     pGeom = (sqlite3_rtree_geometry *)sqlite3_malloc(
  1207   1228         sizeof(sqlite3_rtree_geometry) + nBlob
  1208   1229     );
  1209   1230     if( !pGeom ) return SQLITE_NOMEM;
  1210   1231     memset(pGeom, 0, sizeof(sqlite3_rtree_geometry));
  1211   1232     p = (RtreeMatchArg *)&pGeom[1];
  1212   1233   
  1213   1234     memcpy(p, sqlite3_value_blob(pValue), nBlob);
  1214   1235     if( p->magic!=RTREE_GEOMETRY_MAGIC 
  1215         -   || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(double))
         1236  +   || nBlob!=(int)(sizeof(RtreeMatchArg) + (p->nParam-1)*sizeof(RtreeDValue))
  1216   1237     ){
  1217   1238       sqlite3_free(pGeom);
  1218   1239       return SQLITE_ERROR;
  1219   1240     }
  1220   1241   
  1221   1242     pGeom->pContext = p->pContext;
  1222   1243     pGeom->nParam = p->nParam;
................................................................................
  1280   1301               ** an sqlite3_rtree_geometry_callback() SQL user function.
  1281   1302               */
  1282   1303               rc = deserializeGeometry(argv[ii], p);
  1283   1304               if( rc!=SQLITE_OK ){
  1284   1305                 break;
  1285   1306               }
  1286   1307             }else{
         1308  +#ifdef SQLITE_RTREE_INT_ONLY
         1309  +            p->rValue = sqlite3_value_int64(argv[ii]);
         1310  +#else
  1287   1311               p->rValue = sqlite3_value_double(argv[ii]);
         1312  +#endif
  1288   1313             }
  1289   1314           }
  1290   1315         }
  1291   1316       }
  1292   1317     
  1293   1318       if( rc==SQLITE_OK ){
  1294   1319         pCsr->pNode = 0;
................................................................................
  1414   1439     pIdxInfo->estimatedCost = (2000000.0 / (double)(iIdx + 1));
  1415   1440     return rc;
  1416   1441   }
  1417   1442   
  1418   1443   /*
  1419   1444   ** Return the N-dimensional volumn of the cell stored in *p.
  1420   1445   */
  1421         -static float cellArea(Rtree *pRtree, RtreeCell *p){
  1422         -  float area = 1.0;
         1446  +static RtreeDValue cellArea(Rtree *pRtree, RtreeCell *p){
         1447  +  RtreeDValue area = (RtreeDValue)1;
  1423   1448     int ii;
  1424   1449     for(ii=0; ii<(pRtree->nDim*2); ii+=2){
  1425         -    area = (float)(area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])));
         1450  +    area = (area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])));
  1426   1451     }
  1427   1452     return area;
  1428   1453   }
  1429   1454   
  1430   1455   /*
  1431   1456   ** Return the margin length of cell p. The margin length is the sum
  1432   1457   ** of the objects size in each dimension.
  1433   1458   */
  1434         -static float cellMargin(Rtree *pRtree, RtreeCell *p){
  1435         -  float margin = 0.0;
         1459  +static RtreeDValue cellMargin(Rtree *pRtree, RtreeCell *p){
         1460  +  RtreeDValue margin = (RtreeDValue)0;
  1436   1461     int ii;
  1437   1462     for(ii=0; ii<(pRtree->nDim*2); ii+=2){
  1438         -    margin += (float)(DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
         1463  +    margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii]));
  1439   1464     }
  1440   1465     return margin;
  1441   1466   }
  1442   1467   
  1443   1468   /*
  1444   1469   ** Store the union of cells p1 and p2 in p1.
  1445   1470   */
................................................................................
  1476   1501     }
  1477   1502     return 1;
  1478   1503   }
  1479   1504   
  1480   1505   /*
  1481   1506   ** Return the amount cell p would grow by if it were unioned with pCell.
  1482   1507   */
  1483         -static float cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
  1484         -  float area;
         1508  +static RtreeDValue cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){
         1509  +  RtreeDValue area;
  1485   1510     RtreeCell cell;
  1486   1511     memcpy(&cell, p, sizeof(RtreeCell));
  1487   1512     area = cellArea(pRtree, &cell);
  1488   1513     cellUnion(pRtree, &cell, pCell);
  1489   1514     return (cellArea(pRtree, &cell)-area);
  1490   1515   }
  1491   1516   
  1492   1517   #if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLIT
  1493         -static float cellOverlap(
         1518  +static RtreeDValue cellOverlap(
  1494   1519     Rtree *pRtree, 
  1495   1520     RtreeCell *p, 
  1496   1521     RtreeCell *aCell, 
  1497   1522     int nCell, 
  1498   1523     int iExclude
  1499   1524   ){
  1500   1525     int ii;
  1501         -  float overlap = 0.0;
         1526  +  RtreeDValue overlap = 0.0;
  1502   1527     for(ii=0; ii<nCell; ii++){
  1503   1528   #if VARIANT_RSTARTREE_CHOOSESUBTREE
  1504   1529       if( ii!=iExclude )
  1505   1530   #else
  1506   1531       assert( iExclude==-1 );
  1507   1532       UNUSED_PARAMETER(iExclude);
  1508   1533   #endif
  1509   1534       {
  1510   1535         int jj;
  1511         -      float o = 1.0;
         1536  +      RtreeDValue o = (RtreeDValue)1;
  1512   1537         for(jj=0; jj<(pRtree->nDim*2); jj+=2){
  1513         -        double x1;
  1514         -        double x2;
         1538  +        RtreeDValue x1, x2;
  1515   1539   
  1516   1540           x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj]));
  1517   1541           x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1]));
  1518   1542   
  1519   1543           if( x2<x1 ){
  1520   1544             o = 0.0;
  1521   1545             break;
  1522   1546           }else{
  1523         -          o = o * (float)(x2-x1);
         1547  +          o = o * (x2-x1);
  1524   1548           }
  1525   1549         }
  1526   1550         overlap += o;
  1527   1551       }
  1528   1552     }
  1529   1553     return overlap;
  1530   1554   }
  1531   1555   #endif
  1532   1556   
  1533   1557   #if VARIANT_RSTARTREE_CHOOSESUBTREE
  1534         -static float cellOverlapEnlargement(
         1558  +static RtreeDValue cellOverlapEnlargement(
  1535   1559     Rtree *pRtree, 
  1536   1560     RtreeCell *p, 
  1537   1561     RtreeCell *pInsert, 
  1538   1562     RtreeCell *aCell, 
  1539   1563     int nCell, 
  1540   1564     int iExclude
  1541   1565   ){
  1542         -  double before;
  1543         -  double after;
         1566  +  RtreeDValue before, after;
  1544   1567     before = cellOverlap(pRtree, p, aCell, nCell, iExclude);
  1545   1568     cellUnion(pRtree, p, pInsert);
  1546   1569     after = cellOverlap(pRtree, p, aCell, nCell, iExclude);
  1547         -  return (float)(after-before);
         1570  +  return (after-before);
  1548   1571   }
  1549   1572   #endif
  1550   1573   
  1551   1574   
  1552   1575   /*
  1553   1576   ** This function implements the ChooseLeaf algorithm from Gutman[84].
  1554   1577   ** ChooseSubTree in r*tree terminology.
................................................................................
  1564   1587     RtreeNode *pNode;
  1565   1588     rc = nodeAcquire(pRtree, 1, 0, &pNode);
  1566   1589   
  1567   1590     for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){
  1568   1591       int iCell;
  1569   1592       sqlite3_int64 iBest = 0;
  1570   1593   
  1571         -    float fMinGrowth = 0.0;
  1572         -    float fMinArea = 0.0;
         1594  +    RtreeDValue fMinGrowth = 0.0;
         1595  +    RtreeDValue fMinArea = 0.0;
  1573   1596   #if VARIANT_RSTARTREE_CHOOSESUBTREE
  1574         -    float fMinOverlap = 0.0;
  1575         -    float overlap;
         1597  +    RtreeDValue fMinOverlap = 0.0;
         1598  +    RtreeDValue overlap;
  1576   1599   #endif
  1577   1600   
  1578   1601       int nCell = NCELL(pNode);
  1579   1602       RtreeCell cell;
  1580   1603       RtreeNode *pChild;
  1581   1604   
  1582   1605       RtreeCell *aCell = 0;
................................................................................
  1599   1622   
  1600   1623       /* Select the child node which will be enlarged the least if pCell
  1601   1624       ** is inserted into it. Resolve ties by choosing the entry with
  1602   1625       ** the smallest area.
  1603   1626       */
  1604   1627       for(iCell=0; iCell<nCell; iCell++){
  1605   1628         int bBest = 0;
  1606         -      float growth;
  1607         -      float area;
         1629  +      RtreeDValue growth;
         1630  +      RtreeDValue area;
  1608   1631         nodeGetCell(pRtree, pNode, iCell, &cell);
  1609   1632         growth = cellGrowth(pRtree, &cell, pCell);
  1610   1633         area = cellArea(pRtree, &cell);
  1611   1634   
  1612   1635   #if VARIANT_RSTARTREE_CHOOSESUBTREE
  1613   1636         if( ii==(pRtree->iDepth-1) ){
  1614   1637           overlap = cellOverlapEnlargement(pRtree,&cell,pCell,aCell,nCell,iCell);
................................................................................
  1727   1750     int nCell, 
  1728   1751     int *piLeftSeed, 
  1729   1752     int *piRightSeed
  1730   1753   ){
  1731   1754     int i;
  1732   1755     int iLeftSeed = 0;
  1733   1756     int iRightSeed = 1;
  1734         -  float maxNormalInnerWidth = 0.0;
         1757  +  RtreeDValue maxNormalInnerWidth = (RtreeDValue)0;
  1735   1758   
  1736   1759     /* Pick two "seed" cells from the array of cells. The algorithm used
  1737   1760     ** here is the LinearPickSeeds algorithm from Gutman[1984]. The 
  1738   1761     ** indices of the two seed cells in the array are stored in local
  1739   1762     ** variables iLeftSeek and iRightSeed.
  1740   1763     */
  1741   1764     for(i=0; i<pRtree->nDim; i++){
  1742         -    float x1 = DCOORD(aCell[0].aCoord[i*2]);
  1743         -    float x2 = DCOORD(aCell[0].aCoord[i*2+1]);
  1744         -    float x3 = x1;
  1745         -    float x4 = x2;
         1765  +    RtreeDValue x1 = DCOORD(aCell[0].aCoord[i*2]);
         1766  +    RtreeDValue x2 = DCOORD(aCell[0].aCoord[i*2+1]);
         1767  +    RtreeDValue x3 = x1;
         1768  +    RtreeDValue x4 = x2;
  1746   1769       int jj;
  1747   1770   
  1748   1771       int iCellLeft = 0;
  1749   1772       int iCellRight = 0;
  1750   1773   
  1751   1774       for(jj=1; jj<nCell; jj++){
  1752         -      float left = DCOORD(aCell[jj].aCoord[i*2]);
  1753         -      float right = DCOORD(aCell[jj].aCoord[i*2+1]);
         1775  +      RtreeDValue left = DCOORD(aCell[jj].aCoord[i*2]);
         1776  +      RtreeDValue right = DCOORD(aCell[jj].aCoord[i*2+1]);
  1754   1777   
  1755   1778         if( left<x1 ) x1 = left;
  1756   1779         if( right>x4 ) x4 = right;
  1757   1780         if( left>x3 ){
  1758   1781           x3 = left;
  1759   1782           iCellRight = jj;
  1760   1783         }
................................................................................
  1761   1784         if( right<x2 ){
  1762   1785           x2 = right;
  1763   1786           iCellLeft = jj;
  1764   1787         }
  1765   1788       }
  1766   1789   
  1767   1790       if( x4!=x1 ){
  1768         -      float normalwidth = (x3 - x2) / (x4 - x1);
         1791  +      RtreeDValue normalwidth = (x3 - x2) / (x4 - x1);
  1769   1792         if( normalwidth>maxNormalInnerWidth ){
  1770   1793           iLeftSeed = iCellLeft;
  1771   1794           iRightSeed = iCellRight;
  1772   1795         }
  1773   1796       }
  1774   1797     }
  1775   1798   
................................................................................
  1790   1813     RtreeCell *pLeftBox, 
  1791   1814     RtreeCell *pRightBox,
  1792   1815     int *aiUsed
  1793   1816   ){
  1794   1817     #define FABS(a) ((a)<0.0?-1.0*(a):(a))
  1795   1818   
  1796   1819     int iSelect = -1;
  1797         -  float fDiff;
         1820  +  RtreeDValue fDiff;
  1798   1821     int ii;
  1799   1822     for(ii=0; ii<nCell; ii++){
  1800   1823       if( aiUsed[ii]==0 ){
  1801         -      float left = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
  1802         -      float right = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
  1803         -      float diff = FABS(right-left);
         1824  +      RtreeDValue left = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
         1825  +      RtreeDValue right = cellGrowth(pRtree, pLeftBox, &aCell[ii]);
         1826  +      RtreeDValue diff = FABS(right-left);
  1804   1827         if( iSelect<0 || diff>fDiff ){
  1805   1828           fDiff = diff;
  1806   1829           iSelect = ii;
  1807   1830         }
  1808   1831       }
  1809   1832     }
  1810   1833     aiUsed[iSelect] = 1;
................................................................................
  1823   1846     int *piRightSeed
  1824   1847   ){
  1825   1848     int ii;
  1826   1849     int jj;
  1827   1850   
  1828   1851     int iLeftSeed = 0;
  1829   1852     int iRightSeed = 1;
  1830         -  float fWaste = 0.0;
         1853  +  RtreeDValue fWaste = 0.0;
  1831   1854   
  1832   1855     for(ii=0; ii<nCell; ii++){
  1833   1856       for(jj=ii+1; jj<nCell; jj++){
  1834         -      float right = cellArea(pRtree, &aCell[jj]);
  1835         -      float growth = cellGrowth(pRtree, &aCell[ii], &aCell[jj]);
  1836         -      float waste = growth - right;
         1857  +      RtreeDValue right = cellArea(pRtree, &aCell[jj]);
         1858  +      RtreeDValue growth = cellGrowth(pRtree, &aCell[ii], &aCell[jj]);
         1859  +      RtreeDValue waste = growth - right;
  1837   1860   
  1838   1861         if( waste>fWaste ){
  1839   1862           iLeftSeed = ii;
  1840   1863           iRightSeed = jj;
  1841   1864           fWaste = waste;
  1842   1865         }
  1843   1866       }
................................................................................
  1864   1887   **
  1865   1888   ** The aSpare array is used as temporary working space by the
  1866   1889   ** sorting algorithm.
  1867   1890   */
  1868   1891   static void SortByDistance(
  1869   1892     int *aIdx, 
  1870   1893     int nIdx, 
  1871         -  float *aDistance, 
         1894  +  RtreeDValue *aDistance, 
  1872   1895     int *aSpare
  1873   1896   ){
  1874   1897     if( nIdx>1 ){
  1875   1898       int iLeft = 0;
  1876   1899       int iRight = 0;
  1877   1900   
  1878   1901       int nLeft = nIdx/2;
................................................................................
  1890   1913         if( iLeft==nLeft ){
  1891   1914           aIdx[iLeft+iRight] = aRight[iRight];
  1892   1915           iRight++;
  1893   1916         }else if( iRight==nRight ){
  1894   1917           aIdx[iLeft+iRight] = aLeft[iLeft];
  1895   1918           iLeft++;
  1896   1919         }else{
  1897         -        float fLeft = aDistance[aLeft[iLeft]];
  1898         -        float fRight = aDistance[aRight[iRight]];
         1920  +        RtreeDValue fLeft = aDistance[aLeft[iLeft]];
         1921  +        RtreeDValue fRight = aDistance[aRight[iRight]];
  1899   1922           if( fLeft<fRight ){
  1900   1923             aIdx[iLeft+iRight] = aLeft[iLeft];
  1901   1924             iLeft++;
  1902   1925           }else{
  1903   1926             aIdx[iLeft+iRight] = aRight[iRight];
  1904   1927             iRight++;
  1905   1928           }
................................................................................
  1907   1930       }
  1908   1931   
  1909   1932   #if 0
  1910   1933       /* Check that the sort worked */
  1911   1934       {
  1912   1935         int jj;
  1913   1936         for(jj=1; jj<nIdx; jj++){
  1914         -        float left = aDistance[aIdx[jj-1]];
  1915         -        float right = aDistance[aIdx[jj]];
         1937  +        RtreeDValue left = aDistance[aIdx[jj-1]];
         1938  +        RtreeDValue right = aDistance[aIdx[jj]];
  1916   1939           assert( left<=right );
  1917   1940         }
  1918   1941       }
  1919   1942   #endif
  1920   1943     }
  1921   1944   }
  1922   1945   
................................................................................
  1951   1974   
  1952   1975       SortByDimension(pRtree, aLeft, nLeft, iDim, aCell, aSpare);
  1953   1976       SortByDimension(pRtree, aRight, nRight, iDim, aCell, aSpare);
  1954   1977   
  1955   1978       memcpy(aSpare, aLeft, sizeof(int)*nLeft);
  1956   1979       aLeft = aSpare;
  1957   1980       while( iLeft<nLeft || iRight<nRight ){
  1958         -      double xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]);
  1959         -      double xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]);
  1960         -      double xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]);
  1961         -      double xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]);
         1981  +      RtreeDValue xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]);
         1982  +      RtreeDValue xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]);
         1983  +      RtreeDValue xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]);
         1984  +      RtreeDValue xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]);
  1962   1985         if( (iLeft!=nLeft) && ((iRight==nRight)
  1963   1986          || (xleft1<xright1)
  1964   1987          || (xleft1==xright1 && xleft2<xright2)
  1965   1988         )){
  1966   1989           aIdx[iLeft+iRight] = aLeft[iLeft];
  1967   1990           iLeft++;
  1968   1991         }else{
................................................................................
  1972   1995       }
  1973   1996   
  1974   1997   #if 0
  1975   1998       /* Check that the sort worked */
  1976   1999       {
  1977   2000         int jj;
  1978   2001         for(jj=1; jj<nIdx; jj++){
  1979         -        float xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2];
  1980         -        float xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1];
  1981         -        float xright1 = aCell[aIdx[jj]].aCoord[iDim*2];
  1982         -        float xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1];
         2002  +        RtreeDValue xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2];
         2003  +        RtreeDValue xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1];
         2004  +        RtreeDValue xright1 = aCell[aIdx[jj]].aCoord[iDim*2];
         2005  +        RtreeDValue xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1];
  1983   2006           assert( xleft1<=xright1 && (xleft1<xright1 || xleft2<=xright2) );
  1984   2007         }
  1985   2008       }
  1986   2009   #endif
  1987   2010     }
  1988   2011   }
  1989   2012   
................................................................................
  2002   2025   ){
  2003   2026     int **aaSorted;
  2004   2027     int *aSpare;
  2005   2028     int ii;
  2006   2029   
  2007   2030     int iBestDim = 0;
  2008   2031     int iBestSplit = 0;
  2009         -  float fBestMargin = 0.0;
         2032  +  RtreeDValue fBestMargin = 0.0;
  2010   2033   
  2011   2034     int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int));
  2012   2035   
  2013   2036     aaSorted = (int **)sqlite3_malloc(nByte);
  2014   2037     if( !aaSorted ){
  2015   2038       return SQLITE_NOMEM;
  2016   2039     }
................................................................................
  2023   2046       for(jj=0; jj<nCell; jj++){
  2024   2047         aaSorted[ii][jj] = jj;
  2025   2048       }
  2026   2049       SortByDimension(pRtree, aaSorted[ii], nCell, ii, aCell, aSpare);
  2027   2050     }
  2028   2051   
  2029   2052     for(ii=0; ii<pRtree->nDim; ii++){
  2030         -    float margin = 0.0;
  2031         -    float fBestOverlap = 0.0;
  2032         -    float fBestArea = 0.0;
         2053  +    RtreeDValue margin = 0.0;
         2054  +    RtreeDValue fBestOverlap = 0.0;
         2055  +    RtreeDValue fBestArea = 0.0;
  2033   2056       int iBestLeft = 0;
  2034   2057       int nLeft;
  2035   2058   
  2036   2059       for(
  2037   2060         nLeft=RTREE_MINCELLS(pRtree); 
  2038   2061         nLeft<=(nCell-RTREE_MINCELLS(pRtree)); 
  2039   2062         nLeft++
  2040   2063       ){
  2041   2064         RtreeCell left;
  2042   2065         RtreeCell right;
  2043   2066         int kk;
  2044         -      float overlap;
  2045         -      float area;
         2067  +      RtreeDValue overlap;
         2068  +      RtreeDValue area;
  2046   2069   
  2047   2070         memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell));
  2048   2071         memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell));
  2049   2072         for(kk=1; kk<(nCell-1); kk++){
  2050   2073           if( kk<nLeft ){
  2051   2074             cellUnion(pRtree, &left, &aCell[aaSorted[ii][kk]]);
  2052   2075           }else{
................................................................................
  2121   2144     nodeInsertCell(pRtree, pRight, &aCell[iRightSeed]);
  2122   2145     aiUsed[iLeftSeed] = 1;
  2123   2146     aiUsed[iRightSeed] = 1;
  2124   2147   
  2125   2148     for(i=nCell-2; i>0; i--){
  2126   2149       RtreeCell *pNext;
  2127   2150       pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed);
  2128         -    float diff =  
         2151  +    RtreeDValue diff =  
  2129   2152         cellGrowth(pRtree, pBboxLeft, pNext) - 
  2130   2153         cellGrowth(pRtree, pBboxRight, pNext)
  2131   2154       ;
  2132   2155       if( (RTREE_MINCELLS(pRtree)-NCELL(pRight)==i)
  2133   2156        || (diff>0.0 && (RTREE_MINCELLS(pRtree)-NCELL(pLeft)!=i))
  2134   2157       ){
  2135   2158         nodeInsertCell(pRtree, pRight, pNext);
................................................................................
  2454   2477     RtreeNode *pNode, 
  2455   2478     RtreeCell *pCell, 
  2456   2479     int iHeight
  2457   2480   ){
  2458   2481     int *aOrder;
  2459   2482     int *aSpare;
  2460   2483     RtreeCell *aCell;
  2461         -  float *aDistance;
         2484  +  RtreeDValue *aDistance;
  2462   2485     int nCell;
  2463         -  float aCenterCoord[RTREE_MAX_DIMENSIONS];
         2486  +  RtreeDValue aCenterCoord[RTREE_MAX_DIMENSIONS];
  2464   2487     int iDim;
  2465   2488     int ii;
  2466   2489     int rc = SQLITE_OK;
         2490  +  int n;
  2467   2491   
  2468         -  memset(aCenterCoord, 0, sizeof(float)*RTREE_MAX_DIMENSIONS);
         2492  +  memset(aCenterCoord, 0, sizeof(RtreeDValue)*RTREE_MAX_DIMENSIONS);
  2469   2493   
  2470   2494     nCell = NCELL(pNode)+1;
         2495  +  n = (nCell+1)&(~1);
  2471   2496   
  2472   2497     /* Allocate the buffers used by this operation. The allocation is
  2473   2498     ** relinquished before this function returns.
  2474   2499     */
  2475         -  aCell = (RtreeCell *)sqlite3_malloc(nCell * (
         2500  +  aCell = (RtreeCell *)sqlite3_malloc(n * (
  2476   2501       sizeof(RtreeCell) +         /* aCell array */
  2477   2502       sizeof(int)       +         /* aOrder array */
  2478   2503       sizeof(int)       +         /* aSpare array */
  2479         -    sizeof(float)               /* aDistance array */
         2504  +    sizeof(RtreeDValue)             /* aDistance array */
  2480   2505     ));
  2481   2506     if( !aCell ){
  2482   2507       return SQLITE_NOMEM;
  2483   2508     }
  2484         -  aOrder    = (int *)&aCell[nCell];
  2485         -  aSpare    = (int *)&aOrder[nCell];
  2486         -  aDistance = (float *)&aSpare[nCell];
         2509  +  aOrder    = (int *)&aCell[n];
         2510  +  aSpare    = (int *)&aOrder[n];
         2511  +  aDistance = (RtreeDValue *)&aSpare[n];
  2487   2512   
  2488   2513     for(ii=0; ii<nCell; ii++){
  2489   2514       if( ii==(nCell-1) ){
  2490   2515         memcpy(&aCell[ii], pCell, sizeof(RtreeCell));
  2491   2516       }else{
  2492   2517         nodeGetCell(pRtree, pNode, ii, &aCell[ii]);
  2493   2518       }
  2494   2519       aOrder[ii] = ii;
  2495   2520       for(iDim=0; iDim<pRtree->nDim; iDim++){
  2496         -      aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2]);
  2497         -      aCenterCoord[iDim] += (float)DCOORD(aCell[ii].aCoord[iDim*2+1]);
         2521  +      aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2]);
         2522  +      aCenterCoord[iDim] += DCOORD(aCell[ii].aCoord[iDim*2+1]);
  2498   2523       }
  2499   2524     }
  2500   2525     for(iDim=0; iDim<pRtree->nDim; iDim++){
  2501         -    aCenterCoord[iDim] = (float)(aCenterCoord[iDim]/((float)nCell*2.0));
         2526  +    aCenterCoord[iDim] = (aCenterCoord[iDim]/(nCell*(RtreeDValue)2));
  2502   2527     }
  2503   2528   
  2504   2529     for(ii=0; ii<nCell; ii++){
  2505   2530       aDistance[ii] = 0.0;
  2506   2531       for(iDim=0; iDim<pRtree->nDim; iDim++){
  2507         -      float coord = (float)(DCOORD(aCell[ii].aCoord[iDim*2+1]) - 
         2532  +      RtreeDValue coord = (DCOORD(aCell[ii].aCoord[iDim*2+1]) - 
  2508   2533             DCOORD(aCell[ii].aCoord[iDim*2]));
  2509   2534         aDistance[ii] += (coord-aCenterCoord[iDim])*(coord-aCenterCoord[iDim]);
  2510   2535       }
  2511   2536     }
  2512   2537   
  2513   2538     SortByDistance(aOrder, nCell, aDistance, aSpare);
  2514   2539     nodeZero(pRtree, pNode);
................................................................................
  2743   2768     ** conflict-handling mode specified by the user.
  2744   2769     */
  2745   2770     if( nData>1 ){
  2746   2771       int ii;
  2747   2772   
  2748   2773       /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */
  2749   2774       assert( nData==(pRtree->nDim*2 + 3) );
         2775  +#ifndef SQLITE_RTREE_INT_ONLY
  2750   2776       if( pRtree->eCoordType==RTREE_COORD_REAL32 ){
  2751   2777         for(ii=0; ii<(pRtree->nDim*2); ii+=2){
  2752         -        cell.aCoord[ii].f = (float)sqlite3_value_double(azData[ii+3]);
  2753         -        cell.aCoord[ii+1].f = (float)sqlite3_value_double(azData[ii+4]);
         2778  +        cell.aCoord[ii].f = (RtreeValue)sqlite3_value_double(azData[ii+3]);
         2779  +        cell.aCoord[ii+1].f = (RtreeValue)sqlite3_value_double(azData[ii+4]);
  2754   2780           if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
  2755   2781             rc = SQLITE_CONSTRAINT;
  2756   2782             goto constraint;
  2757   2783           }
  2758   2784         }
  2759         -    }else{
         2785  +    }else
         2786  +#endif
         2787  +    {
  2760   2788         for(ii=0; ii<(pRtree->nDim*2); ii+=2){
  2761   2789           cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
  2762   2790           cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]);
  2763   2791           if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){
  2764   2792             rc = SQLITE_CONSTRAINT;
  2765   2793             goto constraint;
  2766   2794           }
................................................................................
  3150   3178       RtreeCell cell;
  3151   3179       int jj;
  3152   3180   
  3153   3181       nodeGetCell(&tree, &node, ii, &cell);
  3154   3182       sqlite3_snprintf(512-nCell,&zCell[nCell],"%lld", cell.iRowid);
  3155   3183       nCell = (int)strlen(zCell);
  3156   3184       for(jj=0; jj<tree.nDim*2; jj++){
  3157         -      sqlite3_snprintf(512-nCell,&zCell[nCell]," %f",(double)cell.aCoord[jj].f);
         3185  +#ifndef SQLITE_RTREE_INT_ONLY
         3186  +      sqlite3_snprintf(512-nCell,&zCell[nCell], " %f",
         3187  +                       (double)cell.aCoord[jj].f);
         3188  +#else
         3189  +      sqlite3_snprintf(512-nCell,&zCell[nCell], " %d",
         3190  +                       cell.aCoord[jj].i);
         3191  +#endif
  3158   3192         nCell = (int)strlen(zCell);
  3159   3193       }
  3160   3194   
  3161   3195       if( zText ){
  3162   3196         char *zTextNew = sqlite3_mprintf("%s {%s}", zText, zCell);
  3163   3197         sqlite3_free(zText);
  3164   3198         zText = zTextNew;
................................................................................
  3192   3226     int rc;
  3193   3227   
  3194   3228     rc = sqlite3_create_function(db, "rtreenode", 2, utf8, 0, rtreenode, 0, 0);
  3195   3229     if( rc==SQLITE_OK ){
  3196   3230       rc = sqlite3_create_function(db, "rtreedepth", 1, utf8, 0,rtreedepth, 0, 0);
  3197   3231     }
  3198   3232     if( rc==SQLITE_OK ){
         3233  +#ifdef SQLITE_RTREE_INT_ONLY
         3234  +    void *c = (void *)RTREE_COORD_INT32;
         3235  +#else
  3199   3236       void *c = (void *)RTREE_COORD_REAL32;
         3237  +#endif
  3200   3238       rc = sqlite3_create_module_v2(db, "rtree", &rtreeModule, c, 0);
  3201   3239     }
  3202   3240     if( rc==SQLITE_OK ){
  3203   3241       void *c = (void *)RTREE_COORD_INT32;
  3204   3242       rc = sqlite3_create_module_v2(db, "rtree_i32", &rtreeModule, c, 0);
  3205   3243     }
  3206   3244   
................................................................................
  3226   3264   ** table MATCH operators.
  3227   3265   */
  3228   3266   static void geomCallback(sqlite3_context *ctx, int nArg, sqlite3_value **aArg){
  3229   3267     RtreeGeomCallback *pGeomCtx = (RtreeGeomCallback *)sqlite3_user_data(ctx);
  3230   3268     RtreeMatchArg *pBlob;
  3231   3269     int nBlob;
  3232   3270   
  3233         -  nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(double);
         3271  +  nBlob = sizeof(RtreeMatchArg) + (nArg-1)*sizeof(RtreeDValue);
  3234   3272     pBlob = (RtreeMatchArg *)sqlite3_malloc(nBlob);
  3235   3273     if( !pBlob ){
  3236   3274       sqlite3_result_error_nomem(ctx);
  3237   3275     }else{
  3238   3276       int i;
  3239   3277       pBlob->magic = RTREE_GEOMETRY_MAGIC;
  3240   3278       pBlob->xGeom = pGeomCtx->xGeom;
  3241   3279       pBlob->pContext = pGeomCtx->pContext;
  3242   3280       pBlob->nParam = nArg;
  3243   3281       for(i=0; i<nArg; i++){
         3282  +#ifdef SQLITE_RTREE_INT_ONLY
         3283  +      pBlob->aParam[i] = sqlite3_value_int64(aArg[i]);
         3284  +#else
  3244   3285         pBlob->aParam[i] = sqlite3_value_double(aArg[i]);
         3286  +#endif
  3245   3287       }
  3246   3288       sqlite3_result_blob(ctx, pBlob, nBlob, doSqlite3Free);
  3247   3289     }
  3248   3290   }
  3249   3291   
  3250   3292   /*
  3251   3293   ** Register a new geometry function for use with the r-tree MATCH operator.
  3252   3294   */
  3253   3295   int sqlite3_rtree_geometry_callback(
  3254   3296     sqlite3 *db,
  3255   3297     const char *zGeom,
  3256         -  int (*xGeom)(sqlite3_rtree_geometry *, int, double *, int *),
         3298  +  int (*xGeom)(sqlite3_rtree_geometry *, int, RtreeDValue *, int *),
  3257   3299     void *pContext
  3258   3300   ){
  3259   3301     RtreeGeomCallback *pGeomCtx;      /* Context object for new user-function */
  3260   3302   
  3261   3303     /* Allocate and populate the context object. */
  3262   3304     pGeomCtx = (RtreeGeomCallback *)sqlite3_malloc(sizeof(RtreeGeomCallback));
  3263   3305     if( !pGeomCtx ) return SQLITE_NOMEM;

Changes to ext/rtree/rtree1.test.

    99     99       catchsql " 
   100    100         CREATE VIRTUAL TABLE t1 USING rtree($columns);
   101    101       "
   102    102     } $X
   103    103   
   104    104     catchsql { DROP TABLE t1 }
   105    105   }
          106  +
          107  +# Like execsql except display output as integer where that can be
          108  +# done without loss of information.
          109  +#
          110  +proc execsql_intout {sql} {
          111  +  set out {}
          112  +  foreach term [execsql $sql] {
          113  +    regsub {\.0$} $term {} term
          114  +    lappend out $term
          115  +  }
          116  +  return $out
          117  +}
   106    118   
   107    119   # Test that it is possible to open an existing database that contains
   108    120   # r-tree tables.
   109    121   #
   110    122   do_test rtree-1.4.1 {
   111    123     execsql {
   112    124       CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2);
................................................................................
   113    125       INSERT INTO t1 VALUES(1, 5.0, 10.0);
   114    126       INSERT INTO t1 VALUES(2, 15.0, 20.0);
   115    127     }
   116    128   } {}
   117    129   do_test rtree-1.4.2 {
   118    130     db close
   119    131     sqlite3 db test.db
   120         -  execsql { SELECT * FROM t1 ORDER BY ii }
   121         -} {1 5.0 10.0 2 15.0 20.0}
          132  +  execsql_intout { SELECT * FROM t1 ORDER BY ii }
          133  +} {1 5 10 2 15 20}
   122    134   do_test rtree-1.4.3 {
   123    135     execsql { DROP TABLE t1 }
   124    136   } {}
   125    137   
   126    138   # Test that it is possible to create an r-tree table with ridiculous
   127    139   # column names.
   128    140   #
   129    141   do_test rtree-1.5.1 {
   130         -  execsql {
          142  +  execsql_intout {
   131    143       CREATE VIRTUAL TABLE t1 USING rtree("the key", "x dim.", "x2'dim");
   132    144       INSERT INTO t1 VALUES(1, 2, 3);
   133    145       SELECT "the key", "x dim.", "x2'dim" FROM t1;
   134    146     }
   135         -} {1 2.0 3.0}
          147  +} {1 2 3}
   136    148   do_test rtree-1.5.1 {
   137    149     execsql { DROP TABLE t1 }
   138    150   } {}
   139    151   
   140    152   # Force the r-tree constructor to fail.
   141    153   #
   142    154   do_test rtree-1.6.1 {
................................................................................
   157    169       CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2, y1, y2);
   158    170       SELECT * FROM t1;
   159    171     }
   160    172   } {}
   161    173   
   162    174   do_test rtree-2.1.2 {
   163    175     execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
   164         -  execsql { SELECT * FROM t1 }
   165         -} {1 1.0 3.0 2.0 4.0}
          176  +  execsql_intout { SELECT * FROM t1 }
          177  +} {1 1 3 2 4}
   166    178   do_test rtree-2.1.3 {
   167    179     execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
   168    180     execsql { SELECT rowid FROM t1 ORDER BY rowid }
   169    181   } {1 2}
   170    182   do_test rtree-2.1.3 {
   171    183     execsql { INSERT INTO t1 VALUES(NULL, 1, 3, 2, 4) }
   172    184     execsql { SELECT ii FROM t1 ORDER BY ii }
................................................................................
   197    209   do_test rtree-3.1.1 {
   198    210     execsql { 
   199    211       CREATE VIRTUAL TABLE t1 USING rtree(ii, x1, x2, y1, y2);
   200    212       SELECT * FROM t1;
   201    213     }
   202    214   } {}
   203    215   do_test rtree-3.1.2 {
   204         -  execsql { 
          216  +  execsql_intout { 
   205    217       INSERT INTO t1 VALUES(5, 1, 3, 2, 4);
   206    218       SELECT * FROM t1;
   207    219     }
   208         -} {5 1.0 3.0 2.0 4.0}
          220  +} {5 1 3 2 4}
   209    221   do_test rtree-3.1.3 {
   210         -  execsql {
          222  +  execsql_intout {
   211    223       INSERT INTO t1 VALUES(6, 2, 6, 4, 8);
   212    224       SELECT * FROM t1;
   213    225     }
   214         -} {5 1.0 3.0 2.0 4.0 6 2.0 6.0 4.0 8.0}
          226  +} {5 1 3 2 4 6 2 6 4 8}
   215    227   
   216    228   # Test the constraint on the coordinates (c[i]<=c[i+1] where (i%2==0)):
   217    229   do_test rtree-3.2.1 {
   218    230     catchsql { INSERT INTO t1 VALUES(7, 2, 6, 4, 3) }
   219    231   } {1 {constraint failed}}
   220    232   do_test rtree-3.2.2 {
   221    233     catchsql { INSERT INTO t1 VALUES(8, 2, 6, 3, 3) }
................................................................................
   224    236   #----------------------------------------------------------------------------
   225    237   # Test cases rtree-5.* test DELETE operations.
   226    238   #
   227    239   do_test rtree-5.1.1 {
   228    240     execsql { CREATE VIRTUAL TABLE t2 USING rtree(ii, x1, x2) }
   229    241   } {}
   230    242   do_test rtree-5.1.2 {
   231         -  execsql { 
          243  +  execsql_intout { 
   232    244       INSERT INTO t2 VALUES(1, 10, 20);
   233    245       INSERT INTO t2 VALUES(2, 30, 40);
   234    246       INSERT INTO t2 VALUES(3, 50, 60);
   235    247       SELECT * FROM t2 ORDER BY ii;
   236    248     }
   237         -} {1 10.0 20.0 2 30.0 40.0 3 50.0 60.0}
          249  +} {1 10 20 2 30 40 3 50 60}
   238    250   do_test rtree-5.1.3 {
   239         -  execsql { 
          251  +  execsql_intout { 
   240    252       DELETE FROM t2 WHERE ii=2;
   241    253       SELECT * FROM t2 ORDER BY ii;
   242    254     }
   243         -} {1 10.0 20.0 3 50.0 60.0}
          255  +} {1 10 20 3 50 60}
   244    256   do_test rtree-5.1.4 {
   245         -  execsql { 
          257  +  execsql_intout { 
   246    258       DELETE FROM t2 WHERE ii=1;
   247    259       SELECT * FROM t2 ORDER BY ii;
   248    260     }
   249         -} {3 50.0 60.0}
          261  +} {3 50 60}
   250    262   do_test rtree-5.1.5 {
   251    263     execsql { 
   252    264       DELETE FROM t2 WHERE ii=3;
   253    265       SELECT * FROM t2 ORDER BY ii;
   254    266     }
   255    267   } {}
   256    268   do_test rtree-5.1.6 {
................................................................................
   260    272   #----------------------------------------------------------------------------
   261    273   # Test cases rtree-5.* test UPDATE operations.
   262    274   #
   263    275   do_test rtree-6.1.1 {
   264    276     execsql { CREATE VIRTUAL TABLE t3 USING rtree(ii, x1, x2, y1, y2) }
   265    277   } {}
   266    278   do_test rtree-6.1.2 {
   267         -  execsql {
          279  +  execsql_intout {
   268    280       INSERT INTO t3 VALUES(1, 2, 3, 4, 5);
   269    281       UPDATE t3 SET x2=5;
   270    282       SELECT * FROM t3;
   271    283     }
   272         -} {1 2.0 5.0 4.0 5.0}
          284  +} {1 2 5 4 5}
   273    285   do_test rtree-6.1.3 {
   274    286     execsql { UPDATE t3 SET ii = 2 }
   275         -  execsql { SELECT * FROM t3 }
   276         -} {2 2.0 5.0 4.0 5.0}
          287  +  execsql_intout { SELECT * FROM t3 }
          288  +} {2 2 5 4 5}
   277    289   
   278    290   #----------------------------------------------------------------------------
   279    291   # Test cases rtree-7.* test rename operations.
   280    292   #
   281    293   do_test rtree-7.1.1 {
   282    294     execsql {
   283    295       CREATE VIRTUAL TABLE t4 USING rtree(ii, x1, x2, y1, y2, z1, z2);
   284    296       INSERT INTO t4 VALUES(1, 2, 3, 4, 5, 6, 7);
   285    297     }
   286    298   } {}
   287    299   do_test rtree-7.1.2 {
   288    300     execsql { ALTER TABLE t4 RENAME TO t5 }
   289         -  execsql { SELECT * FROM t5 }
   290         -} {1 2.0 3.0 4.0 5.0 6.0 7.0}
          301  +  execsql_intout { SELECT * FROM t5 }
          302  +} {1 2 3 4 5 6 7}
   291    303   do_test rtree-7.1.3 {
   292    304     db close
   293    305     sqlite3 db test.db
   294         -  execsql { SELECT * FROM t5 }
   295         -} {1 2.0 3.0 4.0 5.0 6.0 7.0}
          306  +  execsql_intout { SELECT * FROM t5 }
          307  +} {1 2 3 4 5 6 7}
   296    308   do_test rtree-7.1.4 {
   297    309     execsql { ALTER TABLE t5 RENAME TO 'raisara "one"'''}
   298         -  execsql { SELECT * FROM "raisara ""one""'" }
   299         -} {1 2.0 3.0 4.0 5.0 6.0 7.0}
          310  +  execsql_intout { SELECT * FROM "raisara ""one""'" }
          311  +} {1 2 3 4 5 6 7}
   300    312   do_test rtree-7.1.5 {
   301         -  execsql { SELECT * FROM 'raisara "one"''' }
   302         -} {1 2.0 3.0 4.0 5.0 6.0 7.0}
          313  +  execsql_intout { SELECT * FROM 'raisara "one"''' }
          314  +} {1 2 3 4 5 6 7}
   303    315   do_test rtree-7.1.6 {
   304    316     execsql { ALTER TABLE "raisara ""one""'" RENAME TO "abc 123" }
   305         -  execsql { SELECT * FROM "abc 123" }
   306         -} {1 2.0 3.0 4.0 5.0 6.0 7.0}
          317  +  execsql_intout { SELECT * FROM "abc 123" }
          318  +} {1 2 3 4 5 6 7}
   307    319   do_test rtree-7.1.7 {
   308    320     db close
   309    321     sqlite3 db test.db
   310         -  execsql { SELECT * FROM "abc 123" }
   311         -} {1 2.0 3.0 4.0 5.0 6.0 7.0}
          322  +  execsql_intout { SELECT * FROM "abc 123" }
          323  +} {1 2 3 4 5 6 7}
   312    324   
   313    325   # An error midway through a rename operation.
   314    326   do_test rtree-7.2.1 {
   315    327     execsql { 
   316    328       CREATE TABLE t4_node(a);
   317    329     }
   318    330     catchsql { ALTER TABLE "abc 123" RENAME TO t4 }
   319    331   } {1 {SQL logic error or missing database}}
   320    332   do_test rtree-7.2.2 {
   321         -  execsql { SELECT * FROM "abc 123" }
   322         -} {1 2.0 3.0 4.0 5.0 6.0 7.0}
          333  +  execsql_intout { SELECT * FROM "abc 123" }
          334  +} {1 2 3 4 5 6 7}
   323    335   do_test rtree-7.2.3 {
   324    336     execsql { 
   325    337       DROP TABLE t4_node;
   326    338       CREATE TABLE t4_rowid(a);
   327    339     }
   328    340     catchsql { ALTER TABLE "abc 123" RENAME TO t4 }
   329    341   } {1 {SQL logic error or missing database}}
   330    342   do_test rtree-7.2.4 {
   331    343     db close
   332    344     sqlite3 db test.db
   333         -  execsql { SELECT * FROM "abc 123" }
   334         -} {1 2.0 3.0 4.0 5.0 6.0 7.0}
          345  +  execsql_intout { SELECT * FROM "abc 123" }
          346  +} {1 2 3 4 5 6 7}
   335    347   do_test rtree-7.2.5 {
   336    348     execsql { DROP TABLE t4_rowid }
   337    349     execsql { ALTER TABLE "abc 123" RENAME TO t4 }
   338         -  execsql { SELECT * FROM t4 }
   339         -} {1 2.0 3.0 4.0 5.0 6.0 7.0}
          350  +  execsql_intout { SELECT * FROM t4 }
          351  +} {1 2 3 4 5 6 7}
   340    352   
   341    353   
   342    354   #----------------------------------------------------------------------------
   343    355   # Test cases rtree-8.*
   344    356   #
   345    357   
   346    358   # Test that the function to determine if a leaf cell is part of the

Changes to ext/rtree/rtree4.test.

    23     23   }
    24     24   
    25     25   set ::NROW 2500
    26     26   if {[info exists G(isquick)] && $G(isquick)} {
    27     27     set ::NROW 250
    28     28   }
    29     29   
           30  +ifcapable !rtree_int_only {
    30     31   # Return a floating point number between -X and X.
    31     32   # 
    32     33   proc rand {X} {
    33     34     return [expr {int((rand()-0.5)*1024.0*$X)/512.0}]
    34     35   }
    35     36   
    36     37   # Return a positive floating point number less than or equal to X
    37     38   #
    38     39   proc randincr {X} {
    39     40     while 1 {
    40     41       set r [expr {int(rand()*$X*32.0)/32.0}]
    41     42       if {$r>0.0} {return $r}
    42     43     }
           44  +  }
           45  +} else {
           46  +  # For rtree_int_only, return an number between -X and X.
           47  +  # 
           48  +  proc rand {X} {
           49  +    return [expr {int((rand()-0.5)*2*$X)}]
           50  +  }
           51  +  
           52  +  # Return a positive integer less than or equal to X
           53  +  #
           54  +  proc randincr {X} {
           55  +    while 1 {
           56  +      set r [expr {int(rand()*$X)+1}]
           57  +      if {$r>0} {return $r}
           58  +    }
           59  +  }
    43     60   }
    44     61   
    45     62   # Scramble the $inlist into a random order.
    46     63   #
    47     64   proc scramble {inlist} {
    48     65     set y {}
    49     66     foreach x $inlist {

Changes to ext/rtree/rtree5.test.

    45     45   do_test rtree5-1.6 { 
    46     46     execsql { SELECT x1==5.0 FROM t1 }
    47     47   } {1}
    48     48   
    49     49   do_test rtree5-1.7 { 
    50     50     execsql { SELECT count(*) FROM t1 WHERE x1==5 }
    51     51   } {1}
           52  +ifcapable !rtree_int_only {
    52     53   do_test rtree5-1.8 { 
    53     54     execsql { SELECT count(*) FROM t1 WHERE x1==5.2 }
    54     55   } {0}
           56  +}
    55     57   do_test rtree5-1.9 { 
    56     58     execsql { SELECT count(*) FROM t1 WHERE x1==5.0 }
    57     59   } {1}
    58     60   
    59     61   do_test rtree5-1.10 { 
    60     62     execsql { SELECT (1<<31)-5, (1<<31)-1, -1*(1<<31), -1*(1<<31)+5 }
    61     63   } {2147483643 2147483647 -2147483648 -2147483643}

Changes to ext/rtree/rtree6.test.

    12     12   #
    13     13   
    14     14   if {![info exists testdir]} {
    15     15     set testdir [file join [file dirname [info script]] .. .. test]
    16     16   } 
    17     17   source $testdir/tester.tcl
    18     18   
    19         -ifcapable !rtree {
           19  +ifcapable !rtree || rtree_int_only {
    20     20     finish_test
    21     21     return
    22     22   }
    23     23   
    24     24   #   Operator    Byte Value
    25     25   #   ----------------------
    26     26   #      =        0x41 ('A')

Changes to ext/rtree/rtree7.test.

    19     19   } 
    20     20   source $testdir/tester.tcl
    21     21   
    22     22   ifcapable !rtree||!vacuum {
    23     23     finish_test
    24     24     return
    25     25   }
           26  +
           27  +# Like execsql except display output as integer where that can be
           28  +# done without loss of information.
           29  +#
           30  +proc execsql_intout {sql} {
           31  +  set out {}
           32  +  foreach term [execsql $sql] {
           33  +    regsub {\.0$} $term {} term
           34  +    lappend out $term
           35  +  }
           36  +  return $out
           37  +}
    26     38   
    27     39   do_test rtree7-1.1 {
    28     40     execsql {
    29     41       PRAGMA page_size = 1024;
    30     42       CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2, y1, y2);
    31     43       INSERT INTO rt VALUES(1, 1, 2, 3, 4);
    32     44     }
    33     45   } {}
    34     46   do_test rtree7-1.2 {
    35         -  execsql { SELECT * FROM rt }
    36         -} {1 1.0 2.0 3.0 4.0}
           47  +  execsql_intout { SELECT * FROM rt }
           48  +} {1 1 2 3 4}
    37     49   do_test rtree7-1.3 {
    38         -  execsql { 
           50  +  execsql_intout { 
    39     51       PRAGMA page_size = 2048;
    40     52       VACUUM;
    41     53       SELECT * FROM rt;
    42     54     }
    43         -} {1 1.0 2.0 3.0 4.0}
           55  +} {1 1 2 3 4}
    44     56   do_test rtree7-1.4 {
    45     57     for {set i 2} {$i <= 51} {incr i} {
    46     58       execsql { INSERT INTO rt VALUES($i, 1, 2, 3, 4) }
    47     59     }
    48         -  execsql { SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt }
    49         -} {51.0 102.0 153.0 204.0}
           60  +  execsql_intout { SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt }
           61  +} {51 102 153 204}
    50     62   do_test rtree7-1.5 {
    51         -  execsql { 
           63  +  execsql_intout { 
    52     64       PRAGMA page_size = 512;
    53     65       VACUUM;
    54     66       SELECT sum(x1), sum(x2), sum(y1), sum(y2) FROM rt
    55     67     }
    56         -} {51.0 102.0 153.0 204.0}
           68  +} {51 102 153 204}
    57     69   
    58     70   finish_test

Changes to ext/rtree/rtree9.test.

    13     13   # 
    14     14   
    15     15   if {![info exists testdir]} {
    16     16     set testdir [file join [file dirname [info script]] .. .. test]
    17     17   } 
    18     18   source $testdir/tester.tcl
    19     19   ifcapable !rtree { finish_test ; return }
           20  +ifcapable rtree_int_only { finish_test; return }
    20     21   
    21     22   register_cube_geom db
    22     23   
    23     24   do_execsql_test rtree9-1.1 {
    24     25     CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2, y1, y2, z1, z2);
    25     26     INSERT INTO rt VALUES(1, 1, 2, 1, 2, 1, 2);
    26     27   } {}

Changes to ext/rtree/rtreeB.test.

    14     14   
    15     15   if {![info exists testdir]} {
    16     16     set testdir [file join [file dirname [info script]] .. .. test]
    17     17   } 
    18     18   source $testdir/tester.tcl
    19     19   ifcapable !rtree { finish_test ; return }
    20     20   
           21  +ifcapable rtree_int_only {
           22  +  do_test rtreeB-1.1-intonly {
           23  +    db eval {
           24  +      CREATE VIRTUAL TABLE t1 USING rtree(ii, x0, y0, x1, y1);
           25  +      INSERT INTO t1 VALUES(1073741824, 0.0, 0.0, 100.0, 100.0);
           26  +      INSERT INTO t1 VALUES(2147483646, 0.0, 0.0, 200.0, 200.0);
           27  +      INSERT INTO t1 VALUES(4294967296, 0.0, 0.0, 300.0, 300.0);
           28  +      INSERT INTO t1 VALUES(8589934592, 20.0, 20.0, 150.0, 150.0);
           29  +      INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400);
           30  +      SELECT rtreenode(2, data) FROM t1_node;
           31  +    }
           32  +  } {{{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}}}
           33  +} else {  
    21     34   do_test rtreeB-1.1 {
    22     35     db eval {
    23     36       CREATE VIRTUAL TABLE t1 USING rtree(ii, x0, y0, x1, y1);
    24     37       INSERT INTO t1 VALUES(1073741824, 0.0, 0.0, 100.0, 100.0);
    25     38       INSERT INTO t1 VALUES(2147483646, 0.0, 0.0, 200.0, 200.0);
    26     39       INSERT INTO t1 VALUES(4294967296, 0.0, 0.0, 300.0, 300.0);
    27     40       INSERT INTO t1 VALUES(8589934592, 20.0, 20.0, 150.0, 150.0);
    28     41       INSERT INTO t1 VALUES(9223372036854775807, 150, 150, 400, 400);
    29     42       SELECT rtreenode(2, data) FROM t1_node;
    30     43     }
    31     44   } {{{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}}}
    32         -
           45  +}
    33     46   
    34     47   finish_test

Changes to ext/rtree/sqlite3rtree.h.

    27     27   ** R-Tree geometry query as follows:
    28     28   **
    29     29   **   SELECT ... FROM <rtree> WHERE <rtree col> MATCH $zGeom(... params ...)
    30     30   */
    31     31   int sqlite3_rtree_geometry_callback(
    32     32     sqlite3 *db,
    33     33     const char *zGeom,
    34         -  int (*xGeom)(sqlite3_rtree_geometry *, int nCoord, double *aCoord, int *pRes),
           34  +#ifdef SQLITE_RTREE_INT_ONLY
           35  +  int (*xGeom)(sqlite3_rtree_geometry*, int n, sqlite3_int64 *a, int *pRes),
           36  +#else
           37  +  int (*xGeom)(sqlite3_rtree_geometry*, int n, double *a, int *pRes),
           38  +#endif
    35     39     void *pContext
    36     40   );
    37     41   
    38     42   
    39     43   /*
    40     44   ** A pointer to a structure of the following type is passed as the first
    41     45   ** argument to callbacks registered using rtree_geometry_callback().

Changes to src/test_config.c.

   415    415   #endif
   416    416   
   417    417   #ifdef SQLITE_ENABLE_RTREE
   418    418     Tcl_SetVar2(interp, "sqlite_options", "rtree", "1", TCL_GLOBAL_ONLY);
   419    419   #else
   420    420     Tcl_SetVar2(interp, "sqlite_options", "rtree", "0", TCL_GLOBAL_ONLY);
   421    421   #endif
          422  +
          423  +#ifdef SQLITE_RTREE_INT_ONLY
          424  +  Tcl_SetVar2(interp, "sqlite_options", "rtree_int_only", "1", TCL_GLOBAL_ONLY);
          425  +#else
          426  +  Tcl_SetVar2(interp, "sqlite_options", "rtree_int_only", "0", TCL_GLOBAL_ONLY);
          427  +#endif
   422    428   
   423    429   #ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
   424    430     Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL_GLOBAL_ONLY);
   425    431   #else
   426    432     Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "1", TCL_GLOBAL_ONLY);
   427    433   #endif
   428    434   

Changes to src/test_rtree.c.

    45     45   
    46     46   /*
    47     47   ** Implementation of "circle" r-tree geometry callback.
    48     48   */
    49     49   static int circle_geom(
    50     50     sqlite3_rtree_geometry *p,
    51     51     int nCoord, 
           52  +#ifdef SQLITE_RTREE_INT_ONLY
           53  +  sqlite3_int64 *aCoord,
           54  +#else
    52     55     double *aCoord, 
           56  +#endif
    53     57     int *pRes
    54     58   ){
    55     59     int i;                          /* Iterator variable */
    56     60     Circle *pCircle;                /* Structure defining circular region */
    57     61     double xmin, xmax;              /* X dimensions of box being tested */
    58     62     double ymin, ymax;              /* X dimensions of box being tested */
    59     63   
................................................................................
   185    189   **   cube(x, y, z, width, height, depth)
   186    190   **
   187    191   ** The width, height and depth parameters must all be greater than zero.
   188    192   */
   189    193   static int cube_geom(
   190    194     sqlite3_rtree_geometry *p,
   191    195     int nCoord, 
          196  +#ifdef SQLITE_RTREE_INT_ONLY
          197  +  sqlite3_int64 *aCoord, 
          198  +#else
   192    199     double *aCoord, 
          200  +#endif
   193    201     int *piRes
   194    202   ){
   195    203     Cube *pCube = (Cube *)p->pUser;
   196    204   
   197    205     assert( p->pContext==(void *)&gHere );
   198    206   
   199    207     if( pCube==0 ){