Add tests cases and fix minor issues in the rtreecheck() function.
FossilOrigin-Name: d6130cd226c0ca95e02f0cbabfdc27071acdcf83e0d0cb0eaa47d992479ed9a1
This commit is contained in:
parent
2c0d084400
commit
7e2b38c53b
@ -3659,7 +3659,11 @@ static sqlite3_stmt *rtreeCheckPrepare(
|
||||
z = sqlite3_vmprintf(zFmt, ap);
|
||||
|
||||
if( pCheck->rc==SQLITE_OK ){
|
||||
pCheck->rc = sqlite3_prepare_v2(pCheck->db, z, -1, &pRet, 0);
|
||||
if( z==0 ){
|
||||
pCheck->rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
pCheck->rc = sqlite3_prepare_v2(pCheck->db, z, -1, &pRet, 0);
|
||||
}
|
||||
}
|
||||
|
||||
sqlite3_free(z);
|
||||
@ -3781,7 +3785,7 @@ static void rtreeCheckMapping(
|
||||
);
|
||||
}else if( rc==SQLITE_ROW ){
|
||||
i64 ii = sqlite3_column_int64(pStmt, 0);
|
||||
if( ii!=iVal ){
|
||||
if( ii!=iVal ){
|
||||
rtreeCheckAppendMsg(pCheck,
|
||||
"Found (%lld -> %lld) in %s table, expected (%lld -> %lld)",
|
||||
iKey, ii, (bLeaf ? "%_rowid" : "%_parent"), iKey, iVal
|
||||
@ -3791,10 +3795,22 @@ static void rtreeCheckMapping(
|
||||
rtreeCheckReset(pCheck, pStmt);
|
||||
}
|
||||
|
||||
/*
|
||||
** Argument pCell points to an array of coordinates stored on an rtree page.
|
||||
** This function checks that the coordinates are internally consistent (no
|
||||
** x1>x2 conditions) and adds an error message to the RtreeCheck object
|
||||
** if they are not.
|
||||
**
|
||||
** Additionally, if pParent is not NULL, then it is assumed to point to
|
||||
** the array of coordinates on the parent page that bound the page
|
||||
** containing pCell. In this case it is also verified that the two
|
||||
** sets of coordinates are mutually consistent and an error message added
|
||||
** to the RtreeCheck object if they are not.
|
||||
*/
|
||||
static void rtreeCheckCellCoord(
|
||||
RtreeCheck *pCheck,
|
||||
i64 iNode,
|
||||
int iCell,
|
||||
i64 iNode, /* Node id to use in error messages */
|
||||
int iCell, /* Cell number to use in error messages */
|
||||
u8 *pCell, /* Pointer to cell coordinates */
|
||||
u8 *pParent /* Pointer to parent coordinates */
|
||||
){
|
||||
@ -3829,6 +3845,14 @@ static void rtreeCheckCellCoord(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Run rtreecheck() checks on node iNode, which is at depth iDepth within
|
||||
** the r-tree structure. Argument aParent points to the array of coordinates
|
||||
** that bound node iNode on the parent node.
|
||||
**
|
||||
** If any problems are discovered, an error message is appended to the
|
||||
** report accumulated in the RtreeCheck object.
|
||||
*/
|
||||
static void rtreeCheckNode(
|
||||
RtreeCheck *pCheck,
|
||||
int iDepth, /* Depth of iNode (0==leaf) */
|
||||
@ -3864,19 +3888,20 @@ static void rtreeCheckNode(
|
||||
"Node %lld is too small for cell count of %d (%d bytes)",
|
||||
iNode, nCell, nNode
|
||||
);
|
||||
}
|
||||
for(i=0; i<nCell; i++){
|
||||
u8 *pCell = &aNode[4 + i*(8 + pCheck->nDim*2*4)];
|
||||
i64 iVal = readInt64(pCell);
|
||||
rtreeCheckCellCoord(pCheck, iNode, i, &pCell[8], aParent);
|
||||
}else{
|
||||
for(i=0; i<nCell; i++){
|
||||
u8 *pCell = &aNode[4 + i*(8 + pCheck->nDim*2*4)];
|
||||
i64 iVal = readInt64(pCell);
|
||||
rtreeCheckCellCoord(pCheck, iNode, i, &pCell[8], aParent);
|
||||
|
||||
if( iDepth>0 ){
|
||||
rtreeCheckMapping(pCheck, 0, iVal, iNode);
|
||||
rtreeCheckNode(pCheck, iDepth-1, &pCell[8], iVal);
|
||||
pCheck->nNonLeaf++;
|
||||
}else{
|
||||
rtreeCheckMapping(pCheck, 1, iVal, iNode);
|
||||
pCheck->nLeaf++;
|
||||
if( iDepth>0 ){
|
||||
rtreeCheckMapping(pCheck, 0, iVal, iNode);
|
||||
rtreeCheckNode(pCheck, iDepth-1, &pCell[8], iVal);
|
||||
pCheck->nNonLeaf++;
|
||||
}else{
|
||||
rtreeCheckMapping(pCheck, 1, iVal, iNode);
|
||||
pCheck->nLeaf++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3884,9 +3909,14 @@ static void rtreeCheckNode(
|
||||
}
|
||||
}
|
||||
|
||||
static void rtreeCheckCount(
|
||||
RtreeCheck *pCheck, const char *zTbl, i64 nExpected
|
||||
){
|
||||
/*
|
||||
** The second argument to this function must be either "_rowid" or
|
||||
** "_parent". This function checks that the number of entries in the
|
||||
** %_rowid or %_parent table is exactly nExpect. If not, it adds
|
||||
** an error message to the report in the RtreeCheck object indicated
|
||||
** by the first argument.
|
||||
*/
|
||||
static void rtreeCheckCount(RtreeCheck *pCheck, const char *zTbl, i64 nExpect){
|
||||
if( pCheck->rc==SQLITE_OK ){
|
||||
sqlite3_stmt *pCount;
|
||||
pCount = rtreeCheckPrepare(pCheck, "SELECT count(*) FROM %Q.'%q%s'",
|
||||
@ -3895,9 +3925,9 @@ static void rtreeCheckCount(
|
||||
if( pCount ){
|
||||
if( sqlite3_step(pCount)==SQLITE_ROW ){
|
||||
i64 nActual = sqlite3_column_int64(pCount, 0);
|
||||
if( nActual!=nExpected ){
|
||||
if( nActual!=nExpect ){
|
||||
rtreeCheckAppendMsg(pCheck, "Wrong number of entries in %%%s table"
|
||||
" - expected %lld, actual %lld" , zTbl, nExpected, nActual
|
||||
" - expected %lld, actual %lld" , zTbl, nExpect, nActual
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -3906,7 +3936,11 @@ static void rtreeCheckCount(
|
||||
}
|
||||
}
|
||||
|
||||
static int rtreeCheck(
|
||||
/*
|
||||
** This function does the bulk of the work for the rtree integrity-check.
|
||||
** It is called by rtreecheck(), which is the SQL function implementation.
|
||||
*/
|
||||
static int rtreeCheckTable(
|
||||
sqlite3 *db, /* Database handle to access db through */
|
||||
const char *zDb, /* Name of db ("main", "temp" etc.) */
|
||||
const char *zTab, /* Name of rtree table to check */
|
||||
@ -3945,11 +3979,13 @@ static int rtreeCheck(
|
||||
}
|
||||
|
||||
/* Do the actual integrity-check */
|
||||
if( check.rc==SQLITE_OK ){
|
||||
rtreeCheckNode(&check, 0, 0, 1);
|
||||
if( check.nDim>=1 ){
|
||||
if( check.rc==SQLITE_OK ){
|
||||
rtreeCheckNode(&check, 0, 0, 1);
|
||||
}
|
||||
rtreeCheckCount(&check, "_rowid", check.nLeaf);
|
||||
rtreeCheckCount(&check, "_parent", check.nNonLeaf);
|
||||
}
|
||||
rtreeCheckCount(&check, "_rowid", check.nLeaf);
|
||||
rtreeCheckCount(&check, "_parent", check.nNonLeaf);
|
||||
|
||||
/* Finalize SQL statements used by the integrity-check */
|
||||
sqlite3_finalize(check.pGetNode);
|
||||
@ -4018,7 +4054,7 @@ static void rtreecheck(
|
||||
}else{
|
||||
zTab = (const char*)sqlite3_value_text(apArg[1]);
|
||||
}
|
||||
rc = rtreeCheck(sqlite3_context_db_handle(ctx), zDb, zTab, &zReport);
|
||||
rc = rtreeCheckTable(sqlite3_context_db_handle(ctx), zDb, zTab, &zReport);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_result_text(ctx, zReport ? zReport : "ok", -1, SQLITE_TRANSIENT);
|
||||
}else{
|
||||
|
@ -35,6 +35,12 @@ proc swap_int32 {blob i0 i1} {
|
||||
binary format I* $L
|
||||
}
|
||||
|
||||
proc set_int32 {blob idx val} {
|
||||
binary scan $blob I* L
|
||||
lset L $idx $val
|
||||
binary format I* $L
|
||||
}
|
||||
|
||||
do_catchsql_test 1.0 {
|
||||
SELECT rtreecheck();
|
||||
} {1 {wrong number of arguments to function rtreecheck()}}
|
||||
@ -85,7 +91,6 @@ do_execsql_test 2.5 {
|
||||
SELECT rtreecheck('r1')
|
||||
} {{Found (3 -> 2) in %_rowid table, expected (3 -> 1)}}
|
||||
|
||||
################
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE VIRTUAL TABLE r1 USING rtree_i32(id, x1, x2);
|
||||
@ -101,13 +106,53 @@ do_execsql_test 3.0 {
|
||||
SELECT rtreecheck('r1')
|
||||
} {ok}
|
||||
|
||||
breakpoint
|
||||
do_execsql_test 3.1 {
|
||||
CREATE VIRTUAL TABLE r2 USING rtree_i32(id, x1, x2);
|
||||
INSERT INTO r2 VALUES(2, -1*(1<<31), -1*(1<<31)+5);
|
||||
SELECT rtreecheck('r2')
|
||||
} {ok}
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
BEGIN;
|
||||
UPDATE r2_node SET data = X'123456';
|
||||
SELECT rtreecheck('r2')!="ok";
|
||||
} {1}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
ROLLBACK;
|
||||
UPDATE r2_node SET data = X'00001234';
|
||||
SELECT rtreecheck('r2')!="ok";
|
||||
} {1}
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE notanrtree(i);
|
||||
SELECT rtreecheck('notanrtree');
|
||||
} {{Schema corrupt or not an rtree}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
reset_db
|
||||
db func set_int32 set_int32
|
||||
do_execsql_test 5.0 {
|
||||
CREATE VIRTUAL TABLE r3 USING rtree_i32(id, x1, x2, y1, y2);
|
||||
WITH x(i) AS (
|
||||
SELECT 1 UNION ALL SELECT i+1 FROM x WHERE i<1000
|
||||
)
|
||||
INSERT INTO r3 SELECT i, i, i, i, i FROM x;
|
||||
}
|
||||
do_execsql_test 5.1 {
|
||||
BEGIN;
|
||||
UPDATE r3_node SET data = set_int32(data, 3, 5000);
|
||||
UPDATE r3_node SET data = set_int32(data, 4, 5000);
|
||||
SELECT rtreecheck('r3')=='ok'
|
||||
} 0
|
||||
do_execsql_test 5.2 {
|
||||
ROLLBACK;
|
||||
BEGIN;
|
||||
UPDATE r3_node SET data = set_int32(data, 3, 0);
|
||||
UPDATE r3_node SET data = set_int32(data, 4, 0);
|
||||
SELECT rtreecheck('r3')=='ok'
|
||||
} 0
|
||||
|
||||
finish_test
|
||||
|
||||
|
17
manifest
17
manifest
@ -1,5 +1,5 @@
|
||||
C Add\sSQL\sscalar\sfunction\srtreecheck()\sto\sthe\srtree\smodule.\sFor\srunning\schecks\sto\sensure\sthe\sshadow\stables\sused\sby\san\srtree\svirtual\stable\sare\sinternally\sconsistent.
|
||||
D 2017-10-25T18:01:58.383
|
||||
C Add\stests\scases\sand\sfix\sminor\sissues\sin\sthe\srtreecheck()\sfunction.
|
||||
D 2017-10-25T18:17:24.834
|
||||
F Makefile.in e016061b23e60ac9ec27c65cb577292b6bde0307ca55abd874ab3487b3b1beb2
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc 37740aba9c4bb359c627eadccf1cfd7be4f5f847078723777ea7763969e533b1
|
||||
@ -329,7 +329,7 @@ F ext/rbu/test_rbu.c 7073979b9cc80912bb03599ac8d85ab5d3bf03cfacd3463f2dcdd782299
|
||||
F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15
|
||||
F ext/repair/checkfreelist.c 0abb84b4545016d57ba1a2aa8884c72c73ed838968909858c03bc1f38fb6b054
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
F ext/rtree/rtree.c 49ced71763c4bd170ceb0b46ab34c749f3356a8c0e36ce6b9e2f36dc63716609
|
||||
F ext/rtree/rtree.c cc91b6905bf55512c6ebc7dfdd37ac81c86f1753db8cfa6d62f0ee864464044f
|
||||
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
|
||||
F ext/rtree/rtree1.test 82a353747fcab1083d114b2ac84723dfefdbf86c1a6e1df57bf588c7d4285436
|
||||
F ext/rtree/rtree2.test 5f25b01acd03470067a2d52783b2eb0a50bf836803d4342d20ca39e541220fe2
|
||||
@ -349,7 +349,7 @@ F ext/rtree/rtreeF.test 81ffa7ef51c4e4618d497a57328c265bf576990c7070633b623b23cd
|
||||
F ext/rtree/rtreeG.test fd3af1ca944a0bdb0cbb5455a4905c9f012e2fffcab6b791f07afa0dcbbcae0e
|
||||
F ext/rtree/rtree_perf.tcl 6c18c1f23cd48e0f948930c98dfdd37dfccb5195
|
||||
F ext/rtree/rtree_util.tcl db734b4c5e75fed6acc56d9701f2235345acfdec750b5fc7b587936f5f6bceed
|
||||
F ext/rtree/rtreecheck.test f610cb77ca1ba611e656018a7d960cd46054baecd2f12d1149bf1fec121aa230
|
||||
F ext/rtree/rtreecheck.test 4d29103d1e16fcbf90135d1c637b833688492b063b2971dfb5dc6ba76555cfee
|
||||
F ext/rtree/rtreeconnect.test 225ad3fcb483d36cbee423a25052a6bbae762c9576ae9268332360c68c170d3d
|
||||
F ext/rtree/sqlite3rtree.h 9c5777af3d2921c7b4ae4954e8e5697502289d28
|
||||
F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
|
||||
@ -1666,8 +1666,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P adfa7ed2de3e833fff65935455e71236a59602aaf7b97ece667ab300dca9f673 61870b42b033189509b244c76d28932f7a447b887ffe04a3c81461148e54cfb5
|
||||
R bbf1f0574f080f1a74b750b54fc22d8d
|
||||
T +closed 61870b42b033189509b244c76d28932f7a447b887ffe04a3c81461148e54cfb5
|
||||
U mistachkin
|
||||
Z cbebd749084c1ed38ad0d901e97967c8
|
||||
P 7d26498063bbc4525976ace698fafcf161d939908f4ffb36d7a4df8fb1bce1fb
|
||||
R b18b38b834db7af5e4754d71c435762f
|
||||
U dan
|
||||
Z f91c79bfd0a67ab59612bc897b82c53b
|
||||
|
@ -1 +1 @@
|
||||
7d26498063bbc4525976ace698fafcf161d939908f4ffb36d7a4df8fb1bce1fb
|
||||
d6130cd226c0ca95e02f0cbabfdc27071acdcf83e0d0cb0eaa47d992479ed9a1
|
Loading…
Reference in New Issue
Block a user