⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtree.c

📁 最新的sqlite3.6.2源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/*** 2001 September 15**** The author disclaims copyright to this source code.  In place of** a legal notice, here is a blessing:****    May you do good and not evil.**    May you find forgiveness for yourself and forgive others.**    May you share freely, never taking more than you give.***************************************************************************** This file contains code for implementations of the r-tree and r*-tree** algorithms packaged as an SQLite virtual table module.**** $Id: rtree.c,v 1.7 2008/07/16 14:43:35 drh Exp $*/#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RTREE)/*** This file contains an implementation of a couple of different variants** of the r-tree algorithm. See the README file for further details. The ** same data-structure is used for all, but the algorithms for insert and** delete operations vary. The variants used are selected at compile time ** by defining the following symbols:*//* Either, both or none of the following may be set to activate ** r*tree variant algorithms.*/#define VARIANT_RSTARTREE_CHOOSESUBTREE 0#define VARIANT_RSTARTREE_REINSERT      1/* ** Exactly one of the following must be set to 1.*/#define VARIANT_GUTTMAN_QUADRATIC_SPLIT 0#define VARIANT_GUTTMAN_LINEAR_SPLIT    0#define VARIANT_RSTARTREE_SPLIT         1#define VARIANT_GUTTMAN_SPLIT \        (VARIANT_GUTTMAN_LINEAR_SPLIT||VARIANT_GUTTMAN_QUADRATIC_SPLIT)#if VARIANT_GUTTMAN_QUADRATIC_SPLIT  #define PickNext QuadraticPickNext  #define PickSeeds QuadraticPickSeeds  #define AssignCells splitNodeGuttman#endif#if VARIANT_GUTTMAN_LINEAR_SPLIT  #define PickNext LinearPickNext  #define PickSeeds LinearPickSeeds  #define AssignCells splitNodeGuttman#endif#if VARIANT_RSTARTREE_SPLIT  #define AssignCells splitNodeStartree#endif#ifndef SQLITE_CORE  #include "sqlite3ext.h"  SQLITE_EXTENSION_INIT1#else  #include "sqlite3.h"#endif#include <string.h>#include <assert.h>#ifndef SQLITE_AMALGAMATIONtypedef sqlite3_int64 i64;typedef unsigned char u8;typedef unsigned int u32;#endiftypedef struct Rtree Rtree;typedef struct RtreeCursor RtreeCursor;typedef struct RtreeNode RtreeNode;typedef struct RtreeCell RtreeCell;typedef struct RtreeConstraint RtreeConstraint;typedef union RtreeCoord RtreeCoord;/* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */#define RTREE_MAX_DIMENSIONS 5/* Size of hash table Rtree.aHash. This hash table is not expected to** ever contain very many entries, so a fixed number of buckets is ** used.*/#define HASHSIZE 128/* ** An rtree virtual-table object.*/struct Rtree {  sqlite3_vtab base;  sqlite3 *db;                /* Host database connection */  int iNodeSize;              /* Size in bytes of each node in the node table */  int nDim;                   /* Number of dimensions */  int nBytesPerCell;          /* Bytes consumed per cell */  int iDepth;                 /* Current depth of the r-tree structure */  char *zDb;                  /* Name of database containing r-tree table */  char *zName;                /* Name of r-tree table */   RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */   int nBusy;                  /* Current number of users of this structure */  /* List of nodes removed during a CondenseTree operation. List is  ** linked together via the pointer normally used for hash chains -  ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree   ** headed by the node (leaf nodes have RtreeNode.iNode==0).  */  RtreeNode *pDeleted;  int iReinsertHeight;        /* Height of sub-trees Reinsert() has run on */  /* Statements to read/write/delete a record from xxx_node */  sqlite3_stmt *pReadNode;  sqlite3_stmt *pWriteNode;  sqlite3_stmt *pDeleteNode;  /* Statements to read/write/delete a record from xxx_rowid */  sqlite3_stmt *pReadRowid;  sqlite3_stmt *pWriteRowid;  sqlite3_stmt *pDeleteRowid;  /* Statements to read/write/delete a record from xxx_parent */  sqlite3_stmt *pReadParent;  sqlite3_stmt *pWriteParent;  sqlite3_stmt *pDeleteParent;  int eCoordType;};/* Possible values for eCoordType: */#define RTREE_COORD_REAL32 0#define RTREE_COORD_INT32  1/*** The minimum number of cells allowed for a node is a third of the ** maximum. In Gutman's notation:****     m = M/3**** If an R*-tree "Reinsert" operation is required, the same number of** cells are removed from the overfull node and reinserted into the tree.*/#define RTREE_MINCELLS(p) ((((p)->iNodeSize-4)/(p)->nBytesPerCell)/3)#define RTREE_REINSERT(p) RTREE_MINCELLS(p)#define RTREE_MAXCELLS 51/* ** An rtree cursor object.*/struct RtreeCursor {  sqlite3_vtab_cursor base;  RtreeNode *pNode;                 /* Node cursor is currently pointing at */  int iCell;                        /* Index of current cell in pNode */  int iStrategy;                    /* Copy of idxNum search parameter */  int nConstraint;                  /* Number of entries in aConstraint */  RtreeConstraint *aConstraint;     /* Search constraints. */};union RtreeCoord {  float f;  int i;};/*** The argument is an RtreeCoord. Return the value stored within the RtreeCoord** formatted as a double. This macro assumes that local variable pRtree points** to the Rtree structure associated with the RtreeCoord.*/#define DCOORD(coord) (                           \  (pRtree->eCoordType==RTREE_COORD_REAL32) ?      \    ((double)coord.f) :                           \    ((double)coord.i)                             \)/*** A search constraint.*/struct RtreeConstraint {  int iCoord;                       /* Index of constrained coordinate */  int op;                           /* Constraining operation */  double rValue;                    /* Constraint value. */};/* Possible values for RtreeConstraint.op */#define RTREE_EQ 0x41#define RTREE_LE 0x42#define RTREE_LT 0x43#define RTREE_GE 0x44#define RTREE_GT 0x45/* ** An rtree structure node.**** Data format (RtreeNode.zData):****   1. If the node is the root node (node 1), then the first 2 bytes**      of the node contain the tree depth as a big-endian integer.**      For non-root nodes, the first 2 bytes are left unused.****   2. The next 2 bytes contain the number of entries currently **      stored in the node.****   3. The remainder of the node contains the node entries. Each entry**      consists of a single 8-byte integer followed by an even number**      of 4-byte coordinates. For leaf nodes the integer is the rowid**      of a record. For internal nodes it is the node number of a**      child page.*/struct RtreeNode {  RtreeNode *pParent;               /* Parent node */  i64 iNode;  int nRef;  int isDirty;  u8 *zData;  RtreeNode *pNext;                 /* Next node in this hash chain */};#define NCELL(pNode) readInt16(&(pNode)->zData[2])/* ** Structure to store a deserialized rtree record.*/struct RtreeCell {  i64 iRowid;  RtreeCoord aCoord[RTREE_MAX_DIMENSIONS*2];};#define MAX(x,y) ((x) < (y) ? (y) : (x))#define MIN(x,y) ((x) > (y) ? (y) : (x))/*** Functions to deserialize a 16 bit integer, 32 bit real number and** 64 bit integer. The deserialized value is returned.*/static int readInt16(u8 *p){  return (p[0]<<8) + p[1];}static void readCoord(u8 *p, RtreeCoord *pCoord){  u32 i = (    (((u32)p[0]) << 24) +     (((u32)p[1]) << 16) +     (((u32)p[2]) <<  8) +     (((u32)p[3]) <<  0)  );  *(u32 *)pCoord = i;}static i64 readInt64(u8 *p){  return (    (((i64)p[0]) << 56) +     (((i64)p[1]) << 48) +     (((i64)p[2]) << 40) +     (((i64)p[3]) << 32) +     (((i64)p[4]) << 24) +     (((i64)p[5]) << 16) +     (((i64)p[6]) <<  8) +     (((i64)p[7]) <<  0)  );}/*** Functions to serialize a 16 bit integer, 32 bit real number and** 64 bit integer. The value returned is the number of bytes written** to the argument buffer (always 2, 4 and 8 respectively).*/static int writeInt16(u8 *p, int i){  p[0] = (i>> 8)&0xFF;  p[1] = (i>> 0)&0xFF;  return 2;}static int writeCoord(u8 *p, RtreeCoord *pCoord){  u32 i;  assert( sizeof(RtreeCoord)==4 );  assert( sizeof(u32)==4 );  i = *(u32 *)pCoord;  p[0] = (i>>24)&0xFF;  p[1] = (i>>16)&0xFF;  p[2] = (i>> 8)&0xFF;  p[3] = (i>> 0)&0xFF;  return 4;}static int writeInt64(u8 *p, i64 i){  p[0] = (i>>56)&0xFF;  p[1] = (i>>48)&0xFF;  p[2] = (i>>40)&0xFF;  p[3] = (i>>32)&0xFF;  p[4] = (i>>24)&0xFF;  p[5] = (i>>16)&0xFF;  p[6] = (i>> 8)&0xFF;  p[7] = (i>> 0)&0xFF;  return 8;}/*** Increment the reference count of node p.*/static void nodeReference(RtreeNode *p){  if( p ){    p->nRef++;  }}/*** Clear the content of node p (set all bytes to 0x00).*/static void nodeZero(Rtree *pRtree, RtreeNode *p){  if( p ){    memset(&p->zData[2], 0, pRtree->iNodeSize-2);    p->isDirty = 1;  }}/*** Given a node number iNode, return the corresponding key to use** in the Rtree.aHash table.*/static int nodeHash(i64 iNode){  return (    (iNode>>56) ^ (iNode>>48) ^ (iNode>>40) ^ (iNode>>32) ^     (iNode>>24) ^ (iNode>>16) ^ (iNode>> 8) ^ (iNode>> 0)  ) % HASHSIZE;}/*** Search the node hash table for node iNode. If found, return a pointer** to it. Otherwise, return 0.*/static RtreeNode *nodeHashLookup(Rtree *pRtree, i64 iNode){  RtreeNode *p;  assert( iNode!=0 );  for(p=pRtree->aHash[nodeHash(iNode)]; p && p->iNode!=iNode; p=p->pNext);  return p;}/*** Add node pNode to the node hash table.*/static void nodeHashInsert(Rtree *pRtree, RtreeNode *pNode){  if( pNode ){    int iHash;    assert( pNode->pNext==0 );    iHash = nodeHash(pNode->iNode);    pNode->pNext = pRtree->aHash[iHash];    pRtree->aHash[iHash] = pNode;  }}/*** Remove node pNode from the node hash table.*/static void nodeHashDelete(Rtree *pRtree, RtreeNode *pNode){  RtreeNode **pp;  if( pNode->iNode!=0 ){    pp = &pRtree->aHash[nodeHash(pNode->iNode)];    for( ; (*pp)!=pNode; pp = &(*pp)->pNext){ assert(*pp); }    *pp = pNode->pNext;    pNode->pNext = 0;  }}/*** Allocate and return new r-tree node. Initially, (RtreeNode.iNode==0),** indicating that node has not yet been assigned a node number. It is** assigned a node number when nodeWrite() is called to write the** node contents out to the database.*/static RtreeNode *nodeNew(Rtree *pRtree, RtreeNode *pParent, int zero){  RtreeNode *pNode;  pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize);  if( pNode ){    memset(pNode, 0, sizeof(RtreeNode) + (zero?pRtree->iNodeSize:0));    pNode->zData = (u8 *)&pNode[1];    pNode->nRef = 1;    pNode->pParent = pParent;    pNode->isDirty = 1;    nodeReference(pParent);  }  return pNode;}/*** Obtain a reference to an r-tree node.*/static intnodeAcquire(  Rtree *pRtree,             /* R-tree structure */  i64 iNode,                 /* Node number to load */  RtreeNode *pParent,        /* Either the parent node or NULL */  RtreeNode **ppNode         /* OUT: Acquired node */){  int rc;  RtreeNode *pNode;  /* Check if the requested node is already in the hash table. If so,  ** increase its reference count and return it.  */  if( (pNode = nodeHashLookup(pRtree, iNode)) ){    assert( !pParent || !pNode->pParent || pNode->pParent==pParent );    if( pParent ){      pNode->pParent = pParent;    }    pNode->nRef++;    *ppNode = pNode;    return SQLITE_OK;  }  pNode = (RtreeNode *)sqlite3_malloc(sizeof(RtreeNode) + pRtree->iNodeSize);  if( !pNode ){    *ppNode = 0;    return SQLITE_NOMEM;  }  pNode->pParent = pParent;  pNode->zData = (u8 *)&pNode[1];  pNode->nRef = 1;  pNode->iNode = iNode;  pNode->isDirty = 0;  pNode->pNext = 0;  sqlite3_bind_int64(pRtree->pReadNode, 1, iNode);  rc = sqlite3_step(pRtree->pReadNode);  if( rc==SQLITE_ROW ){    const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);    memcpy(pNode->zData, zBlob, pRtree->iNodeSize);    nodeReference(pParent);  }else{    sqlite3_free(pNode);    pNode = 0;  }  *ppNode = pNode;  rc = sqlite3_reset(pRtree->pReadNode);  if( rc==SQLITE_OK && iNode==1 ){    pRtree->iDepth = readInt16(pNode->zData);  }  assert( (rc==SQLITE_OK && pNode) || (pNode==0 && rc!=SQLITE_OK) );  nodeHashInsert(pRtree, pNode);  return rc;}/*** Overwrite cell iCell of node pNode with the contents of pCell.*/static void nodeOverwriteCell(  Rtree *pRtree,   RtreeNode *pNode,    RtreeCell *pCell,   int iCell){  int ii;  u8 *p = &pNode->zData[4 + pRtree->nBytesPerCell*iCell];  p += writeInt64(p, pCell->iRowid);  for(ii=0; ii<(pRtree->nDim*2); ii++){    p += writeCoord(p, &pCell->aCoord[ii]);  }  pNode->isDirty = 1;}/*** Remove cell the cell with index iCell from node pNode.*/static void nodeDeleteCell(Rtree *pRtree, RtreeNode *pNode, int iCell){  u8 *pDst = &pNode->zData[4 + pRtree->nBytesPerCell*iCell];  u8 *pSrc = &pDst[pRtree->nBytesPerCell];  int nByte = (NCELL(pNode) - iCell - 1) * pRtree->nBytesPerCell;  memmove(pDst, pSrc, nByte);  writeInt16(&pNode->zData[2], NCELL(pNode)-1);  pNode->isDirty = 1;}/*** Insert the contents of cell pCell into node pNode. If the insert** is successful, return SQLITE_OK.**** If there is not enough free space in pNode, return SQLITE_FULL.*/static intnodeInsertCell(  Rtree *pRtree,   RtreeNode *pNode,   RtreeCell *pCell ){  int nCell;                    /* Current number of cells in pNode */  int nMaxCell;                 /* Maximum number of cells for pNode */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -