mirror of
https://github.com/sqlite/sqlite.git
synced 2026-10-23 21:49:02 +03:00
298 lines
7.9 KiB
Plaintext
298 lines
7.9 KiB
Plaintext
# 2026 May 11
|
|
#
|
|
# 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.
|
|
#
|
|
#***********************************************************************
|
|
#
|
|
|
|
source [file join [file dirname [info script]] fts5_common.tcl]
|
|
set testprefix fts5corruptA
|
|
|
|
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
|
|
ifcapable !fts5 {
|
|
finish_test
|
|
return
|
|
}
|
|
sqlite3_fts5_may_be_corrupt 1
|
|
|
|
do_execsql_test 1.0 {
|
|
CREATE VIRTUAL TABLE t USING fts5(x, detail='full');
|
|
INSERT INTO t(t, rank) VALUES('pgsz', 32);
|
|
}
|
|
|
|
set big [string repeat "a " 200]
|
|
do_execsql_test 1.1 {
|
|
INSERT INTO t(rowid, x) VALUES(1, $big)
|
|
}
|
|
|
|
do_test 1.2 {
|
|
db eval {
|
|
SELECT min(rowid) AS base_rowid, count(*) AS page_count FROM t_data
|
|
WHERE rowid>1000
|
|
} {}
|
|
} {}
|
|
|
|
do_test 1.3 {
|
|
for {set ii 0} {$ii < 5} {incr ii} {
|
|
db eval {
|
|
INSERT INTO t_data(rowid, block)
|
|
VALUES( $base_rowid + $page_count + $ii, zeroblob(4) );
|
|
}
|
|
}
|
|
db eval {
|
|
INSERT INTO t_data(rowid, block)
|
|
VALUES( $base_rowid + $page_count + 5,
|
|
unhex('00000080' || 'CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC') );
|
|
}
|
|
set {} {}
|
|
} {}
|
|
|
|
db close
|
|
|
|
do_test 1.4 {
|
|
set hex [hexio_read test.db 0 [file size test.db]]
|
|
|
|
set off [string first "023061018310" $hex]
|
|
set hex [string replace $hex $off [expr $off+11] 023061018370]
|
|
hexio_write test.db 0 $hex
|
|
} {6144}
|
|
|
|
sqlite3 db test.db
|
|
|
|
do_catchsql_test 1.5 {
|
|
SELECT rowid FROM t WHERE t MATCH 'a'
|
|
} {1 {fts5: corruption found reading blob 137438953481 from table "t"}}
|
|
|
|
#-------------------------------------------------------------------------
|
|
reset_db
|
|
|
|
do_execsql_test 2.0 {
|
|
CREATE VIRTUAL TABLE t1 USING fts5(a);
|
|
BEGIN;
|
|
INSERT INTO t1(rowid, a) VALUES(1, 'aaaa');
|
|
INSERT INTO t1(rowid, a) VALUES(2, 'bbbb');
|
|
INSERT INTO t1(rowid, a) VALUES(3, 'cccc');
|
|
COMMIT;
|
|
}
|
|
|
|
db close
|
|
|
|
do_test 2.1 {
|
|
set hex [hexio_read test.db 0 [file size test.db]]
|
|
set off [string first "010463636363" $hex]
|
|
set hex [string replace $hex $off [expr $off+11] 017F63636363]
|
|
hexio_write test.db 0 $hex
|
|
set {} {}
|
|
} {}
|
|
|
|
sqlite3 db test.db
|
|
|
|
do_catchsql_test 2.2 {
|
|
SELECT rowid FROM t1('cccccccccccccccccccccccccccccccccccccccccccccccc');
|
|
} {1 {fts5: corruption on page 1, segment 1, table "t1"}}
|
|
|
|
#-------------------------------------------------------------------------
|
|
reset_db
|
|
do_execsql_test 3.0 {
|
|
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c);
|
|
INSERT INTO t1 VALUES(
|
|
'hello',
|
|
'alpha bravo charlie delta echo foxtrot golf hotel india juliet kilo lima mike november oscar papa quebec romeo sierra tango uniform victor whiskey xray yankee zulu',
|
|
'ant bear cat dog elephant fox gorilla hippo iguana jaguar kangaroo lion monkey newt octopus panda quail rabbit snake turtle unicorn vulture walrus xerus yak zebra'
|
|
);
|
|
|
|
UPDATE t1_data SET block = unhex(
|
|
-- Preserve bytes 0-168: header through hello's nSz field
|
|
hex(substr(block, 1, 169))
|
|
-- Inject 448 bytes of 0xFF: corrupted poslist + subsequent term data
|
|
|| replace(hex(zeroblob(448)), '00', 'FF')
|
|
-- Preserve 16 bytes of page index needed for hello lookup
|
|
|| hex(substr(block, 618, 16))
|
|
-- Corrupt remaining 37 footer bytes (not needed for hello lookup)
|
|
|| replace(hex(zeroblob(37)), '00', 'FF')
|
|
)
|
|
WHERE id = 137438953473;
|
|
}
|
|
|
|
do_test 3.1 {
|
|
execsql { SELECT * FROM t1 WHERE t1 MATCH '{a b}: hello' }
|
|
set {} {}
|
|
} {}
|
|
|
|
#-------------------------------------------------------------------------
|
|
reset_db
|
|
do_execsql_test 4.0 {
|
|
CREATE VIRTUAL TABLE t1 USING fts5(content);
|
|
INSERT INTO t1(t1, rank) VALUES('pgsz', 32);
|
|
BEGIN;
|
|
WITH s(i) AS (
|
|
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<5000
|
|
)
|
|
INSERT INTO t1(content) SELECT 'xyzterm' FROM s;
|
|
COMMIT;
|
|
INSERT INTO t1(t1) VALUES('optimize');
|
|
}
|
|
|
|
do_test 4.1 {
|
|
db eval {
|
|
SELECT rowid AS a, hex(block) AS block FROM t1_data
|
|
WHERE ((rowid>>36) & 0x01)==1
|
|
AND ((rowid>>31) & 0x1F)==0
|
|
} {
|
|
set n [string length $block]
|
|
set block [string range $block 0 11]
|
|
append block [string repeat "00" [expr ($n/2)-7-2]]
|
|
append block "8080"
|
|
db eval {
|
|
UPDATE t1_data SET block = unhex($block) WHERE rowid = $a
|
|
}
|
|
}
|
|
} {}
|
|
|
|
do_catchsql_test 4.2 {
|
|
SELECT count(*) FROM (
|
|
SELECT rowid FROM t1 WHERE t1 MATCH 'xyzterm' ORDER BY rowid ASC
|
|
)
|
|
} {0 5000}
|
|
|
|
do_catchsql_test 4.3 {
|
|
SELECT count(*) FROM (
|
|
SELECT rowid FROM t1 WHERE t1 MATCH 'xyzterm' ORDER BY rowid DESC
|
|
)
|
|
} {0 4987}
|
|
|
|
do_test 4.4 {
|
|
db eval {
|
|
SELECT rowid AS a, hex(block) AS block FROM t1_data
|
|
WHERE ((rowid>>36) & 0x01)==1
|
|
AND ((rowid>>31) & 0x1F)==0
|
|
} {
|
|
set n [string length $block]
|
|
set block [string range $block 0 $n-5]
|
|
append block [string repeat "00" 2]
|
|
db eval {
|
|
UPDATE t1_data SET block = unhex($block) WHERE rowid = $a
|
|
}
|
|
}
|
|
} {}
|
|
|
|
do_catchsql_test 4.5 {
|
|
SELECT count(*) FROM (
|
|
SELECT rowid FROM t1 WHERE t1 MATCH 'xyzterm' ORDER BY rowid ASC
|
|
)
|
|
} {0 5000}
|
|
|
|
do_catchsql_test 4.6 {
|
|
SELECT count(*) FROM (
|
|
SELECT rowid FROM t1 WHERE t1 MATCH 'xyzterm' ORDER BY rowid DESC
|
|
)
|
|
} {0 4879}
|
|
|
|
#-------------------------------------------------------------------------
|
|
reset_db
|
|
|
|
do_execsql_test 5.0 {
|
|
CREATE VIRTUAL TABLE t USING fts5(x);
|
|
INSERT INTO t(t,rank) VALUES('pgsz', 64);
|
|
WITH s(i) AS (
|
|
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<80
|
|
)
|
|
INSERT INTO t SELECT 'shared word' || (i%10) || ' shared shared' FROM s;
|
|
INSERT INTO t(t) VALUES('optimize');
|
|
}
|
|
|
|
set lLeaf [db eval { SELECT id FROM t_data }]
|
|
db_save_and_close
|
|
|
|
foreach leaf $lLeaf {
|
|
db_restore_and_reopen
|
|
set leaf [expr $leaf]
|
|
set hex [db one {
|
|
SELECT hex(block) FROM t_data WHERE id=$leaf
|
|
}]
|
|
|
|
# Replace the first 4 bytes of each leaf page with the size of the leaf in
|
|
# bytes plus 50 as a 2 byte integer, followed by 0x7FFF.
|
|
#
|
|
set nn [expr [string length $hex]/2]
|
|
set first "[format %.4x [expr $nn+50]]7FFF"
|
|
set hex [string replace $hex 0 7 $first]
|
|
|
|
db eval { UPDATE t_data SET block=unhex($hex) WHERE id=$leaf }
|
|
do_test 5.1.$leaf {
|
|
catchsql {
|
|
SELECT rowid FROM t WHERE t MATCH 'shared' ORDER BY rowid DESC;
|
|
}
|
|
set {} {}
|
|
} {}
|
|
|
|
do_test 5.1.$leaf.2 {
|
|
catchsql {
|
|
PRAGMA integrity_check;
|
|
}
|
|
set {} {}
|
|
} {}
|
|
}
|
|
|
|
#-------------------------------------------------------------------------
|
|
reset_db
|
|
|
|
do_execsql_test 6.0 {
|
|
CREATE VIRTUAL TABLE t USING fts5(x, content='', contentless_delete=1);
|
|
INSERT INTO t(rowid,x)
|
|
VALUES(1,'a b'), (2,'c d'), (3,'e f'), (4,'g h'), (5,'i j');
|
|
INSERT INTO t(t) VALUES('optimize');
|
|
DELETE FROM t WHERE rowid=2;
|
|
}
|
|
|
|
do_test 6.1 {
|
|
db eval {
|
|
SELECT rowid AS rid, hex(block) AS blk
|
|
FROM t_data WHERE rowid>1_000_000_000_000
|
|
} {}
|
|
|
|
set blk [string replace $blk 8 15 20000000]
|
|
execsql {
|
|
UPDATE t_data SET block = unhex($blk) WHERE rowid=$rid
|
|
}
|
|
} {}
|
|
|
|
do_execsql_test 6.2 {
|
|
DELETE FROM t WHERE rowid=3;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------
|
|
reset_db
|
|
do_execsql_test 7.0 {
|
|
CREATE VIRTUAL TABLE ft USING fts5(x);
|
|
INSERT INTO ft(ft,rank) VALUES('pgsz',64);
|
|
WITH s(i) AS (
|
|
SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<10
|
|
)
|
|
INSERT INTO ft SELECT 'a b b a c c d' FROM s;
|
|
}
|
|
|
|
set B "00000040FFFF61010402050104020501040205010402050104020501040205010402050104020501040205010402050101620104030301040303010403030104042b"
|
|
set N "306162[string repeat 00 5000]"
|
|
|
|
do_execsql_test 7.1 {
|
|
UPDATE ft_data SET block = unhex($B) WHERE id = 137438953473;
|
|
UPDATE ft_idx SET term=unhex($N) WHERE segid=1 AND pgno=2;
|
|
}
|
|
|
|
do_execsql_test 7.2 {
|
|
PRAGMA integrity_check
|
|
} {
|
|
{fts5: corruption found reading blob 137438953473 from table "ft"}
|
|
}
|
|
|
|
sqlite3_fts5_may_be_corrupt 0
|
|
finish_test
|
|
|
|
|