3 # The author disclaims copyright to this source code. In place of
4 # a legal notice, here is a blessing:
6 # May you do good and not evil.
7 # May you find forgiveness for yourself and forgive others.
8 # May you share freely, never taking more than you give.
10 #*************************************************************************
12 # Test cases for the sqlite_offset() function.
14 # Some of the tests in this file depend on the exact placement of content
15 # within b-tree pages. Such placement is at the implementations discretion,
16 # and so it is possible for results to change from one release to the next.
18 set testdir [file dirname $argv0]
19 source $testdir/tester.tcl
20 ifcapable !offset_sql_func {
30 do_execsql_test func6-100 {
31 PRAGMA page_size=4096;
32 PRAGMA auto_vacuum=NONE;
33 CREATE TABLE t1(a,b,c,d);
34 WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<100)
35 INSERT INTO t1(a,b,c,d) SELECT printf('abc%03x',x), x, 1000-x, NULL FROM c;
36 CREATE INDEX t1a ON t1(a);
37 CREATE INDEX t1bc ON t1(b,c);
38 CREATE TABLE t2(x TEXT PRIMARY KEY, y) WITHOUT ROWID;
39 INSERT INTO t2(x,y) SELECT a, b FROM t1;
42 # Load the contents of $file from disk and return it encoded as a hex
46 fconfigure $fd -translation binary -encoding binary
49 binary encode hex $data
52 # Each argument is either an integer between 0 and 65535, a text value, or
53 # an empty string representing an SQL NULL. This command builds an SQLite
54 # record containing the values passed as arguments and returns it encoded
56 proc hexrecord {args} {
61 while {[llength $args] && [lindex $args end]=={}} {
62 set args [lrange $args 0 end-1]
69 } elseif {[string is integer $x]==0} {
70 set n [string length $x]
71 append hdr [format %02x [expr $n*2 + 13]]
72 append body [binary encode hex $x]
77 } elseif {$x <= 127} {
79 append body [format %02x $x]
82 append body [format %04x $x]
85 set res [format %02x [expr 1 + [string length $hdr]/2]]
90 # Argument $off is an offset into the database image encoded as a hex string
91 # in argument $hexdb. This command returns 0 if the offset contains the hex
92 # $hexrec, or throws an exception otherwise.
94 proc offset_contains_record {off hexdb hexrec} {
95 set n [string length $hexrec]
97 if { [string compare $hexrec [string range $hexdb $off [expr $off+$n-1]]] } {
98 error "record not found!"
103 # This command is the implementation of SQL function "offrec()". The first
104 # argument to this is an offset value. The remaining values are used to
105 # formulate an SQLite record. If database file test.db does not contain
106 # an equivalent record at the specified offset, an exception is thrown.
107 # Otherwise, 0 is returned.
110 set offset [lindex $args 0]
111 set rec [hexrecord {*}[lrange $args 1 end]]
112 offset_contains_record $offset $::F $rec
114 set F [loadhex test.db]
115 db func offrec offrec
117 # Test the sanity of the tests.
123 do_execsql_test func6-105 {
124 SELECT sqlite_offset(d) FROM t1 ORDER BY rowid LIMIT 1;
127 set r [hexrecord abc001 1 999 {}]
128 offset_contains_record $offset $F $r
131 set z100 [string trim [string repeat "0 " 100]]
133 # Test offsets within table b-tree t1.
134 do_execsql_test func6-110 {
135 SELECT offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY rowid
138 do_execsql_test func6-120 {
139 SELECT a, typeof(sqlite_offset(+a)) FROM t1
140 ORDER BY rowid LIMIT 2;
141 } {abc001 null abc002 null}
143 # Test offsets within index b-tree t1a.
144 do_execsql_test func6-130 {
145 SELECT offrec(sqlite_offset(a), a, rowid) FROM t1 ORDER BY a
148 # Test offsets within table b-tree t1 with a temp b-tree ORDER BY.
149 do_execsql_test func6-140 {
150 SELECT offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY a
153 # Test offsets from both index t1a and table t1 in the same query.
154 do_execsql_test func6-150 {
155 SELECT offrec(sqlite_offset(a), a, rowid),
156 offrec(sqlite_offset(d), a, b, c, d)
158 } [concat $z100 $z100]
160 # Test offsets from both index t1bc and table t1 in the same query.
161 do_execsql_test func6-160 {
162 SELECT offrec(sqlite_offset(b), b, c, rowid),
163 offrec(sqlite_offset(c), b, c, rowid),
164 offrec(sqlite_offset(d), a, b, c, d)
167 } [concat $z100 $z100 $z100]
169 # Test offsets in WITHOUT ROWID table t2.
170 do_execsql_test func6-200 {
171 SELECT offrec( sqlite_offset(y), x, y ) FROM t2 ORDER BY x