1# 2001 September 15 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# This file implements regression tests for SQLite library. Specfically 12# it tests that the different storage classes (integer, real, text etc.) 13# all work correctly. 14# 15# $Id: types.test,v 1.11 2004/08/20 18:34:20 drh Exp $ 16 17set testdir [file dirname $argv0] 18source $testdir/tester.tcl 19 20# Tests in this file are organized roughly as follows: 21# 22# types-1.*.*: Test that values are stored using the expected storage 23# classes when various forms of literals are inserted into 24# columns with different affinities. 25# types-1.1.*: INSERT INTO <table> VALUES(...) 26# types-1.2.*: INSERT INTO <table> SELECT... 27# types-1.3.*: UPDATE <table> SET... 28# 29# types-2.*.*: Check that values can be stored and retrieving using the 30# various storage classes. 31# types-2.1.*: INTEGER 32# types-2.2.*: REAL 33# types-2.3.*: NULL 34# types-2.4.*: TEXT 35# types-2.5.*: Records with a few different storage classes. 36# 37# types-3.*: Test that the '=' operator respects manifest types. 38# 39 40# Disable encryption on the database for this test. 41db close 42set DB [sqlite3 db test.db] 43sqlite3_rekey $DB {} 44 45# Create a table with one column for each type of affinity 46do_test types-1.1.0 { 47 execsql { 48 CREATE TABLE t1(i integer, n numeric, t text, o blob); 49 } 50} {} 51 52# Each element of the following list represents one test case. 53# 54# The first value of each sub-list is an SQL literal. The following 55# four value are the storage classes that would be used if the 56# literal were inserted into a column with affinity INTEGER, NUMERIC, TEXT 57# or NONE, respectively. 58set values { 59 { 5.0 integer real text real } 60 { 5 integer integer text integer } 61 { '5.0' integer real text text } 62 { '-5.0' integer real text text } 63 { '-5.0' integer real text text } 64 { '5' integer integer text text } 65 { 'abc' text text text text } 66 { NULL null null null null } 67 { X'00' blob blob blob blob } 68} 69 70# This code tests that the storage classes specified above (in the $values 71# table) are correctly assigned when values are inserted using a statement 72# of the form: 73# 74# INSERT INTO <table> VALUE(<values>); 75# 76set tnum 1 77foreach val $values { 78 set lit [lindex $val 0] 79 execsql "DELETE FROM t1;" 80 execsql "INSERT INTO t1 VALUES($lit, $lit, $lit, $lit);" 81 do_test types-1.1.$tnum { 82 execsql { 83 SELECT typeof(i), typeof(n), typeof(t), typeof(o) FROM t1; 84 } 85 } [lrange $val 1 end] 86 incr tnum 87} 88 89# This code tests that the storage classes specified above (in the $values 90# table) are correctly assigned when values are inserted using a statement 91# of the form: 92# 93# INSERT INTO t1 SELECT .... 94# 95set tnum 1 96foreach val $values { 97 set lit [lindex $val 0] 98 execsql "DELETE FROM t1;" 99 execsql "INSERT INTO t1 SELECT $lit, $lit, $lit, $lit;" 100 do_test types-1.2.$tnum { 101 execsql { 102 SELECT typeof(i), typeof(n), typeof(t), typeof(o) FROM t1; 103 } 104 } [lrange $val 1 end] 105 incr tnum 106} 107 108# This code tests that the storage classes specified above (in the $values 109# table) are correctly assigned when values are inserted using a statement 110# of the form: 111# 112# UPDATE <table> SET <column> = <value>; 113# 114set tnum 1 115foreach val $values { 116 set lit [lindex $val 0] 117 execsql "UPDATE t1 SET i = $lit, n = $lit, t = $lit, o = $lit;" 118 do_test types-1.3.$tnum { 119 execsql { 120 SELECT typeof(i), typeof(n), typeof(t), typeof(o) FROM t1; 121 } 122 } [lrange $val 1 end] 123 incr tnum 124} 125 126execsql { 127 DROP TABLE t1; 128} 129 130# Open the table with root-page $rootpage at the btree 131# level. Return a list that is the length of each record 132# in the table, in the tables default scanning order. 133proc record_sizes {rootpage} { 134 set bt [btree_open test.db 10 0] 135 set c [btree_cursor $bt $rootpage 0] 136 btree_first $c 137 while 1 { 138 lappend res [btree_payload_size $c] 139 if {[btree_next $c]} break 140 } 141 btree_close_cursor $c 142 btree_close $bt 143 set res 144} 145 146 147# Create a table and insert some 1-byte integers. Make sure they 148# can be read back OK. These should be 3 byte records. 149do_test types-2.1.1 { 150 execsql { 151 CREATE TABLE t1(a integer); 152 INSERT INTO t1 VALUES(0); 153 INSERT INTO t1 VALUES(120); 154 INSERT INTO t1 VALUES(-120); 155 } 156} {} 157do_test types-2.1.2 { 158 execsql { 159 SELECT a FROM t1; 160 } 161} {0 120 -120} 162 163# Try some 2-byte integers (4 byte records) 164do_test types-2.1.3 { 165 execsql { 166 INSERT INTO t1 VALUES(30000); 167 INSERT INTO t1 VALUES(-30000); 168 } 169} {} 170do_test types-2.1.4 { 171 execsql { 172 SELECT a FROM t1; 173 } 174} {0 120 -120 30000 -30000} 175 176# 4-byte integers (6 byte records) 177do_test types-2.1.5 { 178 execsql { 179 INSERT INTO t1 VALUES(2100000000); 180 INSERT INTO t1 VALUES(-2100000000); 181 } 182} {} 183do_test types-2.1.6 { 184 execsql { 185 SELECT a FROM t1; 186 } 187} {0 120 -120 30000 -30000 2100000000 -2100000000} 188 189# 8-byte integers (10 byte records) 190do_test types-2.1.7 { 191 execsql { 192 INSERT INTO t1 VALUES(9000000*1000000*1000000); 193 INSERT INTO t1 VALUES(-9000000*1000000*1000000); 194 } 195} {} 196do_test types-2.1.8 { 197 execsql { 198 SELECT a FROM t1; 199 } 200} [list 0 120 -120 30000 -30000 2100000000 -2100000000 \ 201 9000000000000000000 -9000000000000000000] 202 203# Check that all the record sizes are as we expected. 204do_test types-2.1.9 { 205 set root [db eval {select rootpage from sqlite_master where name = 't1'}] 206 record_sizes $root 207} {3 3 3 4 4 6 6 10 10} 208 209# Insert some reals. These should be 10 byte records. 210do_test types-2.2.1 { 211 execsql { 212 CREATE TABLE t2(a float); 213 INSERT INTO t2 VALUES(0.0); 214 INSERT INTO t2 VALUES(12345.678); 215 INSERT INTO t2 VALUES(-12345.678); 216 } 217} {} 218do_test types-2.2.2 { 219 execsql { 220 SELECT a FROM t2; 221 } 222} {0.0 12345.678 -12345.678} 223 224# Check that all the record sizes are as we expected. 225do_test types-2.2.3 { 226 set root [db eval {select rootpage from sqlite_master where name = 't2'}] 227 record_sizes $root 228} {10 10 10} 229 230# Insert a NULL. This should be a two byte record. 231do_test types-2.3.1 { 232 execsql { 233 CREATE TABLE t3(a nullvalue); 234 INSERT INTO t3 VALUES(NULL); 235 } 236} {} 237do_test types-2.3.2 { 238 execsql { 239 SELECT a ISNULL FROM t3; 240 } 241} {1} 242 243# Check that all the record sizes are as we expected. 244do_test types-2.3.3 { 245 set root [db eval {select rootpage from sqlite_master where name = 't3'}] 246 record_sizes $root 247} {2} 248 249# Insert a couple of strings. 250do_test types-2.4.1 { 251 set string10 abcdefghij 252 set string500 [string repeat $string10 50] 253 set string500000 [string repeat $string10 50000] 254 255 execsql " 256 CREATE TABLE t4(a string); 257 INSERT INTO t4 VALUES('$string10'); 258 INSERT INTO t4 VALUES('$string500'); 259 INSERT INTO t4 VALUES('$string500000'); 260 " 261} {} 262do_test types-2.4.2 { 263 execsql { 264 SELECT a FROM t4; 265 } 266} [list $string10 $string500 $string500000] 267 268# Check that all the record sizes are as we expected. This is dependant on 269# the database encoding. 270if { [execsql {pragma encoding}] == "UTF-8" } { 271 do_test types-2.4.3 { 272 set root [db eval {select rootpage from sqlite_master where name = 't4'}] 273 record_sizes $root 274 } {12 503 500004} 275} else { 276 do_test types-2.4.3 { 277 set root [db eval {select rootpage from sqlite_master where name = 't4'}] 278 record_sizes $root 279 } {22 1003 1000004} 280} 281 282do_test types-2.5.1 { 283 execsql { 284 DROP TABLE t1; 285 DROP TABLE t2; 286 DROP TABLE t3; 287 DROP TABLE t4; 288 CREATE TABLE t1(a, b, c); 289 } 290} {} 291do_test types-2.5.2 { 292 set string10 abcdefghij 293 set string500 [string repeat $string10 50] 294 set string500000 [string repeat $string10 50000] 295 296 execsql "INSERT INTO t1 VALUES(NULL, '$string10', 4000);" 297 execsql "INSERT INTO t1 VALUES('$string500', 4000, NULL);" 298 execsql "INSERT INTO t1 VALUES(4000, NULL, '$string500000');" 299} {} 300do_test types-2.5.3 { 301 execsql { 302 SELECT * FROM t1; 303 } 304} [list {} $string10 4000 $string500 4000 {} 4000 {} $string500000] 305 306finish_test 307