blob: fe90a755d7f52ac91875c7c0e843d4c399846944 [file] [log] [blame]
drh2fc865c2017-12-16 20:20:37 +00001# 2017-12-16
2#
3# The author disclaims copyright to this source code. In place of
4# a legal notice, here is a blessing:
5#
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.
9#
10#*************************************************************************
11#
drh35100fb2018-01-04 19:20:37 +000012# Test cases for the sqlite_offset() function.
drh2fc865c2017-12-16 20:20:37 +000013#
drh9af41ff2017-12-29 16:37:33 +000014# 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.
17#
drh2fc865c2017-12-16 20:20:37 +000018set testdir [file dirname $argv0]
19source $testdir/tester.tcl
drh092457b2017-12-29 15:04:49 +000020ifcapable !offset_sql_func {
21 finish_test
22 return
23}
drh2fc865c2017-12-16 20:20:37 +000024
dan1db7db12018-02-12 15:27:32 +000025set bNullTrim 0
26ifcapable null_trim {
27 set bNullTrim 1
28}
29
drh2fc865c2017-12-16 20:20:37 +000030do_execsql_test func6-100 {
drh9af41ff2017-12-29 16:37:33 +000031 PRAGMA page_size=4096;
32 PRAGMA auto_vacuum=NONE;
drh2fc865c2017-12-16 20:20:37 +000033 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;
drh9af41ff2017-12-29 16:37:33 +000036 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;
drh2fc865c2017-12-16 20:20:37 +000040}
dan91347c02018-02-09 15:42:40 +000041
42# Load the contents of $file from disk and return it encoded as a hex
43# string.
44proc loadhex {file} {
45 set fd [open $file]
46 fconfigure $fd -translation binary -encoding binary
47 set data [read $fd]
48 close $fd
49 binary encode hex $data
50}
51
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
55# as a hex string.
56proc hexrecord {args} {
57 set hdr ""
58 set body ""
dan1db7db12018-02-12 15:27:32 +000059
60 if {$::bNullTrim} {
61 while {[llength $args] && [lindex $args end]=={}} {
62 set args [lrange $args 0 end-1]
63 }
64 }
65
dan91347c02018-02-09 15:42:40 +000066 foreach x $args {
67 if {$x==""} {
68 append hdr 00
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]
73 } elseif {$x == 0} {
74 append hdr 08
75 } elseif {$x == 1} {
76 append hdr 09
77 } elseif {$x <= 127} {
78 append hdr 01
79 append body [format %02x $x]
80 } else {
81 append hdr 02
82 append body [format %04x $x]
83 }
84 }
85 set res [format %02x [expr 1 + [string length $hdr]/2]]
86 append res $hdr
87 append res $body
88}
89
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.
93#
94proc offset_contains_record {off hexdb hexrec} {
95 set n [string length $hexrec]
96 set off [expr $off*2]
97 if { [string compare $hexrec [string range $hexdb $off [expr $off+$n-1]]] } {
98 error "record not found!"
99 }
100 return 0
101}
102
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.
108#
109proc offrec {args} {
110 set offset [lindex $args 0]
111 set rec [hexrecord {*}[lrange $args 1 end]]
112 offset_contains_record $offset $::F $rec
113}
114set F [loadhex test.db]
115db func offrec offrec
116
117# Test the sanity of the tests.
dan1db7db12018-02-12 15:27:32 +0000118if {$bNullTrim} {
119 set offset 8180
120} else {
121 set offset 8179
122}
dan91347c02018-02-09 15:42:40 +0000123do_execsql_test func6-105 {
124 SELECT sqlite_offset(d) FROM t1 ORDER BY rowid LIMIT 1;
dan1db7db12018-02-12 15:27:32 +0000125} $offset
dan91347c02018-02-09 15:42:40 +0000126do_test func6-106 {
127 set r [hexrecord abc001 1 999 {}]
dan1db7db12018-02-12 15:27:32 +0000128 offset_contains_record $offset $F $r
dan91347c02018-02-09 15:42:40 +0000129} 0
130
131set z100 [string trim [string repeat "0 " 100]]
132
133# Test offsets within table b-tree t1.
drh2fc865c2017-12-16 20:20:37 +0000134do_execsql_test func6-110 {
dan91347c02018-02-09 15:42:40 +0000135 SELECT offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY rowid
136} $z100
137
drh2fc865c2017-12-16 20:20:37 +0000138do_execsql_test func6-120 {
drh35100fb2018-01-04 19:20:37 +0000139 SELECT a, typeof(sqlite_offset(+a)) FROM t1
drh092457b2017-12-29 15:04:49 +0000140 ORDER BY rowid LIMIT 2;
drh2fc865c2017-12-16 20:20:37 +0000141} {abc001 null abc002 null}
dan91347c02018-02-09 15:42:40 +0000142
143# Test offsets within index b-tree t1a.
drh2fc865c2017-12-16 20:20:37 +0000144do_execsql_test func6-130 {
dan91347c02018-02-09 15:42:40 +0000145 SELECT offrec(sqlite_offset(a), a, rowid) FROM t1 ORDER BY a
146} $z100
147
148# Test offsets within table b-tree t1 with a temp b-tree ORDER BY.
drh2fc865c2017-12-16 20:20:37 +0000149do_execsql_test func6-140 {
dan91347c02018-02-09 15:42:40 +0000150 SELECT offrec(sqlite_offset(d), a, b, c, d) FROM t1 ORDER BY a
151} $z100
152
153# Test offsets from both index t1a and table t1 in the same query.
drh9af41ff2017-12-29 16:37:33 +0000154do_execsql_test func6-150 {
dan91347c02018-02-09 15:42:40 +0000155 SELECT offrec(sqlite_offset(a), a, rowid),
156 offrec(sqlite_offset(d), a, b, c, d)
157 FROM t1 ORDER BY a
158} [concat $z100 $z100]
159
160# Test offsets from both index t1bc and table t1 in the same query.
drh9af41ff2017-12-29 16:37:33 +0000161do_execsql_test func6-160 {
dan91347c02018-02-09 15:42:40 +0000162 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)
165 FROM t1
166 ORDER BY b
167} [concat $z100 $z100 $z100]
drh9af41ff2017-12-29 16:37:33 +0000168
dan91347c02018-02-09 15:42:40 +0000169# Test offsets in WITHOUT ROWID table t2.
drh9af41ff2017-12-29 16:37:33 +0000170do_execsql_test func6-200 {
dan91347c02018-02-09 15:42:40 +0000171 SELECT offrec( sqlite_offset(y), x, y ) FROM t2 ORDER BY x
172} $z100
drh2fc865c2017-12-16 20:20:37 +0000173
drhd024eca2022-03-14 22:58:04 +0000174# 2022-03-14 dbsqlfuzz 474499f3977d95fdf2dbcd99c50be1d0082e4c92
175reset_db
176do_execsql_test func6-300 {
177 CREATE TABLE t2(a INT, b INT PRIMARY KEY) WITHOUT ROWID;
178 CREATE INDEX x3 ON t2(b);
179 CREATE TABLE t1(a INT PRIMARY KEY, b TEXT);
180 SELECT * FROM t1 WHERE a IN (SELECT sqlite_offset(b) FROM t2);
181} {}
182
drh2fc865c2017-12-16 20:20:37 +0000183finish_test