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

Fix for [e9a9fde1f4]. When opening an existing rtree, determine the node size by inspecting the root node of the r-tree structure (instead of assuming it is a function of the page-size).

FossilOrigin-Name: ebc9433fddf78ef7b4237686951d8d79c1c98f03
This commit is contained in:
dan
2010-02-16 10:59:40 +00:00
parent 9a6ffc845b
commit 5dcb3937b6
4 changed files with 149 additions and 73 deletions

View File

@ -423,6 +423,7 @@ nodeAcquire(
rc = sqlite3_step(pRtree->pReadNode);
if( rc==SQLITE_ROW ){
const u8 *zBlob = sqlite3_column_blob(pRtree->pReadNode, 0);
assert( sqlite3_column_bytes(pRtree->pReadNode, 0)==pRtree->iNodeSize );
memcpy(pNode->zData, zBlob, pRtree->iNodeSize);
nodeReference(pParent);
}else{
@ -2619,31 +2620,69 @@ static int rtreeSqlInit(
}
/*
** This routine queries database handle db for the page-size used by
** database zDb. If successful, the page-size in bytes is written to
** *piPageSize and SQLITE_OK returned. Otherwise, and an SQLite error
** code is returned.
** The second argument to this function contains the text of an SQL statement
** that returns a single integer value. The statement is compiled and executed
** using database connection db. If successful, the integer value returned
** is written to *piVal and SQLITE_OK returned. Otherwise, an SQLite error
** code is returned and the value of *piVal after returning is not defined.
*/
static int getPageSize(sqlite3 *db, const char *zDb, int *piPageSize){
static int getIntFromStmt(sqlite3 *db, const char *zSql, int *piVal){
int rc = SQLITE_NOMEM;
if( zSql ){
sqlite3_stmt *pStmt = 0;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc==SQLITE_OK ){
if( SQLITE_ROW==sqlite3_step(pStmt) ){
*piVal = sqlite3_column_int(pStmt, 0);
}
rc = sqlite3_finalize(pStmt);
}
}
return rc;
}
/*
** This function is called from within the xConnect() or xCreate() method to
** determine the node-size used by the rtree table being created or connected
** to. If successful, pRtree->iNodeSize is populated and SQLITE_OK returned.
** Otherwise, an SQLite error code is returned.
**
** If this function is being called as part of an xConnect(), then the rtree
** table already exists. In this case the node-size is determined by inspecting
** the root node of the tree.
**
** Otherwise, for an xCreate(), use 64 bytes less than the database page-size.
** This ensures that each node is stored on a single database page. If the
** database page-size is so large that more than RTREE_MAXCELLS entries
** would fit in a single node, use a smaller node-size.
*/
static int getNodeSize(
sqlite3 *db, /* Database handle */
Rtree *pRtree, /* Rtree handle */
int isCreate /* True for xCreate, false for xConnect */
){
int rc;
char *zSql;
sqlite3_stmt *pStmt = 0;
zSql = sqlite3_mprintf("PRAGMA %Q.page_size", zDb);
if( !zSql ){
return SQLITE_NOMEM;
if( isCreate ){
int iPageSize;
zSql = sqlite3_mprintf("PRAGMA %Q.page_size", pRtree->zDb);
rc = getIntFromStmt(db, zSql, &iPageSize);
if( rc==SQLITE_OK ){
pRtree->iNodeSize = iPageSize-64;
if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
}
}
}else{
zSql = sqlite3_mprintf(
"SELECT length(data) FROM '%q'.'%q_node' WHERE nodeno = 1",
pRtree->zDb, pRtree->zName
);
rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
}
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc!=SQLITE_OK ){
return rc;
}
if( SQLITE_ROW==sqlite3_step(pStmt) ){
*piPageSize = sqlite3_column_int(pStmt, 0);
}
return sqlite3_finalize(pStmt);
return rc;
}
/*
@ -2683,11 +2722,6 @@ static int rtreeInit(
return SQLITE_ERROR;
}
rc = getPageSize(db, argv[1], &iPageSize);
if( rc!=SQLITE_OK ){
return rc;
}
/* Allocate the sqlite3_vtab structure */
nDb = strlen(argv[1]);
nName = strlen(argv[2]);
@ -2706,44 +2740,37 @@ static int rtreeInit(
memcpy(pRtree->zDb, argv[1], nDb);
memcpy(pRtree->zName, argv[2], nName);
/* Figure out the node size to use. By default, use 64 bytes less than
** the database page-size. This ensures that each node is stored on
** a single database page.
**
** If the databasd page-size is so large that more than RTREE_MAXCELLS
** entries would fit in a single node, use a smaller node-size.
*/
pRtree->iNodeSize = iPageSize-64;
if( (4+pRtree->nBytesPerCell*RTREE_MAXCELLS)<pRtree->iNodeSize ){
pRtree->iNodeSize = 4+pRtree->nBytesPerCell*RTREE_MAXCELLS;
}
/* Figure out the node size to use. */
rc = getNodeSize(db, pRtree, isCreate);
/* Create/Connect to the underlying relational database schema. If
** that is successful, call sqlite3_declare_vtab() to configure
** the r-tree table schema.
*/
if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}else{
char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
char *zTmp;
int ii;
for(ii=4; zSql && ii<argc; ii++){
zTmp = zSql;
zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
sqlite3_free(zTmp);
}
if( zSql ){
zTmp = zSql;
zSql = sqlite3_mprintf("%s);", zTmp);
sqlite3_free(zTmp);
}
if( !zSql ){
rc = SQLITE_NOMEM;
}else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
if( rc==SQLITE_OK ){
if( (rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}else{
char *zSql = sqlite3_mprintf("CREATE TABLE x(%s", argv[3]);
char *zTmp;
int ii;
for(ii=4; zSql && ii<argc; ii++){
zTmp = zSql;
zSql = sqlite3_mprintf("%s, %s", zTmp, argv[ii]);
sqlite3_free(zTmp);
}
if( zSql ){
zTmp = zSql;
zSql = sqlite3_mprintf("%s);", zTmp);
sqlite3_free(zTmp);
}
if( !zSql ){
rc = SQLITE_NOMEM;
}else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}
sqlite3_free(zSql);
}
sqlite3_free(zSql);
}
if( rc==SQLITE_OK ){