xref: /sqlite-3.40.0/test/func6.test (revision d024eca3)
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