12fc865c1Sdrh# 2017-12-16 22fc865c1Sdrh# 32fc865c1Sdrh# The author disclaims copyright to this source code. In place of 42fc865c1Sdrh# a legal notice, here is a blessing: 52fc865c1Sdrh# 62fc865c1Sdrh# May you do good and not evil. 72fc865c1Sdrh# May you find forgiveness for yourself and forgive others. 82fc865c1Sdrh# May you share freely, never taking more than you give. 92fc865c1Sdrh# 102fc865c1Sdrh#************************************************************************* 112fc865c1Sdrh# 1235100fb1Sdrh# Test cases for the sqlite_offset() function. 132fc865c1Sdrh# 149af41ff4Sdrh# Some of the tests in this file depend on the exact placement of content 159af41ff4Sdrh# within b-tree pages. Such placement is at the implementations discretion, 169af41ff4Sdrh# and so it is possible for results to change from one release to the next. 179af41ff4Sdrh# 182fc865c1Sdrhset testdir [file dirname $argv0] 192fc865c1Sdrhsource $testdir/tester.tcl 20092457b1Sdrhifcapable !offset_sql_func { 21092457b1Sdrh finish_test 22092457b1Sdrh return 23092457b1Sdrh} 242fc865c1Sdrh 251db7db1fSdanset bNullTrim 0 261db7db1fSdanifcapable null_trim { 271db7db1fSdan set bNullTrim 1 281db7db1fSdan} 291db7db1fSdan 302fc865c1Sdrhdo_execsql_test func6-100 { 319af41ff4Sdrh PRAGMA page_size=4096; 329af41ff4Sdrh PRAGMA auto_vacuum=NONE; 332fc865c1Sdrh CREATE TABLE t1(a,b,c,d); 342fc865c1Sdrh WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100) 352fc865c1Sdrh INSERT INTO t1(a,b,c,d) SELECT printf('abc%03x',x), x, 1000-x, NULL FROM c; 369af41ff4Sdrh CREATE INDEX t1a ON t1(a); 379af41ff4Sdrh CREATE INDEX t1bc ON t1(b,c); 389af41ff4Sdrh CREATE TABLE t2(x TEXT PRIMARY KEY, y) WITHOUT ROWID; 399af41ff4Sdrh INSERT INTO t2(x,y) SELECT a, b FROM t1; 402fc865c1Sdrh} 4191347c06Sdan 4291347c06Sdan# Load the contents of $file from disk and return it encoded as a hex 4391347c06Sdan# string. 4491347c06Sdanproc loadhex {file} { 4591347c06Sdan set fd [open $file] 4691347c06Sdan fconfigure $fd -translation binary -encoding binary 4791347c06Sdan set data [read $fd] 4891347c06Sdan close $fd 4991347c06Sdan binary encode hex $data 5091347c06Sdan} 5191347c06Sdan 5291347c06Sdan# Each argument is either an integer between 0 and 65535, a text value, or 5391347c06Sdan# an empty string representing an SQL NULL. This command builds an SQLite 5491347c06Sdan# record containing the values passed as arguments and returns it encoded 5591347c06Sdan# as a hex string. 5691347c06Sdanproc hexrecord {args} { 5791347c06Sdan set hdr "" 5891347c06Sdan set body "" 591db7db1fSdan 601db7db1fSdan if {$::bNullTrim} { 611db7db1fSdan while {[llength $args] && [lindex $args end]=={}} { 621db7db1fSdan set args [lrange $args 0 end-1] 631db7db1fSdan } 641db7db1fSdan } 651db7db1fSdan 6691347c06Sdan foreach x $args { 6791347c06Sdan if {$x==""} { 6891347c06Sdan append hdr 00 6991347c06Sdan } elseif {[string is integer $x]==0} { 7091347c06Sdan set n [string length $x] 7191347c06Sdan append hdr [format %02x [expr $n*2 + 13]] 7291347c06Sdan append body [binary encode hex $x] 7391347c06Sdan } elseif {$x == 0} { 7491347c06Sdan append hdr 08 7591347c06Sdan } elseif {$x == 1} { 7691347c06Sdan append hdr 09 7791347c06Sdan } elseif {$x <= 127} { 7891347c06Sdan append hdr 01 7991347c06Sdan append body [format %02x $x] 8091347c06Sdan } else { 8191347c06Sdan append hdr 02 8291347c06Sdan append body [format %04x $x] 8391347c06Sdan } 8491347c06Sdan } 8591347c06Sdan set res [format %02x [expr 1 + [string length $hdr]/2]] 8691347c06Sdan append res $hdr 8791347c06Sdan append res $body 8891347c06Sdan} 8991347c06Sdan 9091347c06Sdan# Argument $off is an offset into the database image encoded as a hex string 9191347c06Sdan# in argument $hexdb. This command returns 0 if the offset contains the hex 9291347c06Sdan# $hexrec, or throws an exception otherwise. 9391347c06Sdan# 9491347c06Sdanproc offset_contains_record {off hexdb hexrec} { 9591347c06Sdan set n [string length $hexrec] 9691347c06Sdan set off [expr $off*2] 9791347c06Sdan if { [string compare $hexrec [string range $hexdb $off [expr $off+$n-1]]] } { 9891347c06Sdan error "record not found!" 9991347c06Sdan } 10091347c06Sdan return 0 10191347c06Sdan} 10291347c06Sdan 10391347c06Sdan# This command is the implementation of SQL function "offrec()". The first 10491347c06Sdan# argument to this is an offset value. The remaining values are used to 10591347c06Sdan# formulate an SQLite record. If database file test.db does not contain 10691347c06Sdan# an equivalent record at the specified offset, an exception is thrown. 10791347c06Sdan# Otherwise, 0 is returned. 10891347c06Sdan# 10991347c06Sdanproc offrec {args} { 11091347c06Sdan set offset [lindex $args 0] 11191347c06Sdan set rec [hexrecord {*}[lrange $args 1 end]] 11291347c06Sdan offset_contains_record $offset $::F $rec 11391347c06Sdan} 11491347c06Sdanset F [loadhex test.db] 11591347c06Sdandb func offrec offrec 11691347c06Sdan 11791347c06Sdan# Test the sanity of the tests. 1181db7db1fSdanif {$bNullTrim} { 1191db7db1fSdan set offset 8180 1201db7db1fSdan} else { 1211db7db1fSdan set offset 8179 1221db7db1fSdan} 12391347c06Sdando_execsql_test func6-105 { 12491347c06Sdan SELECT sqlite_offset(d) FROM t1 ORDER BY rowid LIMIT 1; 1251db7db1fSdan} $offset 12691347c06Sdando_test func6-106 { 12791347c06Sdan set r [hexrecord abc001 1 999 {}] 1281db7db1fSdan offset_contains_record $offset $F $r 12991347c06Sdan} 0 13091347c06Sdan 13191347c06Sdanset z100 [string trim [string repeat "0 " 100]] 13291347c06Sdan 13391347c06Sdan# Test offsets within table b-tree t1. 1342fc865c1Sdrhdo_execsql_test func6-110 { 13591347c06Sdan SELECT offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY rowid 13691347c06Sdan} $z100 13791347c06Sdan 1382fc865c1Sdrhdo_execsql_test func6-120 { 13935100fb1Sdrh SELECT a, typeof(sqlite_offset(+a)) FROM t1 140092457b1Sdrh ORDER BY rowid LIMIT 2; 1412fc865c1Sdrh} {abc001 null abc002 null} 14291347c06Sdan 14391347c06Sdan# Test offsets within index b-tree t1a. 1442fc865c1Sdrhdo_execsql_test func6-130 { 14591347c06Sdan SELECT offrec(sqlite_offset(a), a, rowid) FROM t1 ORDER BY a 14691347c06Sdan} $z100 14791347c06Sdan 14891347c06Sdan# Test offsets within table b-tree t1 with a temp b-tree ORDER BY. 1492fc865c1Sdrhdo_execsql_test func6-140 { 15091347c06Sdan SELECT offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY a 15191347c06Sdan} $z100 15291347c06Sdan 15391347c06Sdan# Test offsets from both index t1a and table t1 in the same query. 1549af41ff4Sdrhdo_execsql_test func6-150 { 15591347c06Sdan SELECT offrec(sqlite_offset(a), a, rowid), 15691347c06Sdan offrec(sqlite_offset(d), a, b, c, d) 15791347c06Sdan FROM t1 ORDER BY a 15891347c06Sdan} [concat $z100 $z100] 15991347c06Sdan 16091347c06Sdan# Test offsets from both index t1bc and table t1 in the same query. 1619af41ff4Sdrhdo_execsql_test func6-160 { 16291347c06Sdan SELECT offrec(sqlite_offset(b), b, c, rowid), 16391347c06Sdan offrec(sqlite_offset(c), b, c, rowid), 16491347c06Sdan offrec(sqlite_offset(d), a, b, c, d) 1659af41ff4Sdrh FROM t1 16691347c06Sdan ORDER BY b 16791347c06Sdan} [concat $z100 $z100 $z100] 1689af41ff4Sdrh 16991347c06Sdan# Test offsets in WITHOUT ROWID table t2. 1709af41ff4Sdrhdo_execsql_test func6-200 { 17191347c06Sdan SELECT offrec( sqlite_offset(y), x, y ) FROM t2 ORDER BY x 17291347c06Sdan} $z100 1732fc865c1Sdrh 174*d024eca3Sdrh# 2022-03-14 dbsqlfuzz 474499f3977d95fdf2dbcd99c50be1d0082e4c92 175*d024eca3Sdrhreset_db 176*d024eca3Sdrhdo_execsql_test func6-300 { 177*d024eca3Sdrh CREATE TABLE t2(a INT, b INT PRIMARY KEY) WITHOUT ROWID; 178*d024eca3Sdrh CREATE INDEX x3 ON t2(b); 179*d024eca3Sdrh CREATE TABLE t1(a INT PRIMARY KEY, b TEXT); 180*d024eca3Sdrh SELECT * FROM t1 WHERE a IN (SELECT sqlite_offset(b) FROM t2); 181*d024eca3Sdrh} {} 182*d024eca3Sdrh 1832fc865c1Sdrhfinish_test 184