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:
@ -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 ){
|
||||
|
Reference in New Issue
Block a user