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.14 2004/11/14 21:56:31 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} 68ifcapable {bloblit} { 69 lappend values { X'00' blob blob blob blob } 70} 71 72# This code tests that the storage classes specified above (in the $values 73# table) are correctly assigned when values are inserted using a statement 74# of the form: 75# 76# INSERT INTO <table> VALUE(<values>); 77# 78set tnum 1 79foreach val $values { 80 set lit [lindex $val 0] 81 execsql "DELETE FROM t1;" 82 execsql "INSERT INTO t1 VALUES($lit, $lit, $lit, $lit);" 83 do_test types-1.1.$tnum { 84 execsql { 85 SELECT typeof(i), typeof(n), typeof(t), typeof(o) FROM t1; 86 } 87 } [lrange $val 1 end] 88 incr tnum 89} 90 91# This code tests that the storage classes specified above (in the $values 92# table) are correctly assigned when values are inserted using a statement 93# of the form: 94# 95# INSERT INTO t1 SELECT .... 96# 97set tnum 1 98foreach val $values { 99 set lit [lindex $val 0] 100 execsql "DELETE FROM t1;" 101 execsql "INSERT INTO t1 SELECT $lit, $lit, $lit, $lit;" 102 do_test types-1.2.$tnum { 103 execsql { 104 SELECT typeof(i), typeof(n), typeof(t), typeof(o) FROM t1; 105 } 106 } [lrange $val 1 end] 107 incr tnum 108} 109 110# This code tests that the storage classes specified above (in the $values 111# table) are correctly assigned when values are inserted using a statement 112# of the form: 113# 114# UPDATE <table> SET <column> = <value>; 115# 116set tnum 1 117foreach val $values { 118 set lit [lindex $val 0] 119 execsql "UPDATE t1 SET i = $lit, n = $lit, t = $lit, o = $lit;" 120 do_test types-1.3.$tnum { 121 execsql { 122 SELECT typeof(i), typeof(n), typeof(t), typeof(o) FROM t1; 123 } 124 } [lrange $val 1 end] 125 incr tnum 126} 127 128execsql { 129 DROP TABLE t1; 130} 131 132# Open the table with root-page $rootpage at the btree 133# level. Return a list that is the length of each record 134# in the table, in the tables default scanning order. 135proc record_sizes {rootpage} { 136 set bt [btree_open test.db 10 0] 137 set c [btree_cursor $bt $rootpage 0] 138 btree_first $c 139 while 1 { 140 lappend res [btree_payload_size $c] 141 if {[btree_next $c]} break 142 } 143 btree_close_cursor $c 144 btree_close $bt 145 set res 146} 147 148 149# Create a table and insert some 1-byte integers. Make sure they 150# can be read back OK. These should be 3 byte records. 151do_test types-2.1.1 { 152 execsql { 153 CREATE TABLE t1(a integer); 154 INSERT INTO t1 VALUES(0); 155 INSERT INTO t1 VALUES(120); 156 INSERT INTO t1 VALUES(-120); 157 } 158} {} 159do_test types-2.1.2 { 160 execsql { 161 SELECT a FROM t1; 162 } 163} {0 120 -120} 164 165# Try some 2-byte integers (4 byte records) 166do_test types-2.1.3 { 167 execsql { 168 INSERT INTO t1 VALUES(30000); 169 INSERT INTO t1 VALUES(-30000); 170 } 171} {} 172do_test types-2.1.4 { 173 execsql { 174 SELECT a FROM t1; 175 } 176} {0 120 -120 30000 -30000} 177 178# 4-byte integers (6 byte records) 179do_test types-2.1.5 { 180 execsql { 181 INSERT INTO t1 VALUES(2100000000); 182 INSERT INTO t1 VALUES(-2100000000); 183 } 184} {} 185do_test types-2.1.6 { 186 execsql { 187 SELECT a FROM t1; 188 } 189} {0 120 -120 30000 -30000 2100000000 -2100000000} 190 191# 8-byte integers (10 byte records) 192do_test types-2.1.7 { 193 execsql { 194 INSERT INTO t1 VALUES(9000000*1000000*1000000); 195 INSERT INTO t1 VALUES(-9000000*1000000*1000000); 196 } 197} {} 198do_test types-2.1.8 { 199 execsql { 200 SELECT a FROM t1; 201 } 202} [list 0 120 -120 30000 -30000 2100000000 -2100000000 \ 203 9000000000000000000 -9000000000000000000] 204 205# Check that all the record sizes are as we expected. 206do_test types-2.1.9 { 207 set root [db eval {select rootpage from sqlite_master where name = 't1'}] 208 record_sizes $root 209} {3 3 3 4 4 6 6 10 10} 210 211# Insert some reals. These should be 10 byte records. 212do_test types-2.2.1 { 213 execsql { 214 CREATE TABLE t2(a float); 215 INSERT INTO t2 VALUES(0.0); 216 INSERT INTO t2 VALUES(12345.678); 217 INSERT INTO t2 VALUES(-12345.678); 218 } 219} {} 220do_test types-2.2.2 { 221 execsql { 222 SELECT a FROM t2; 223 } 224} {0.0 12345.678 -12345.678} 225 226# Check that all the record sizes are as we expected. 227do_test types-2.2.3 { 228 set root [db eval {select rootpage from sqlite_master where name = 't2'}] 229 record_sizes $root 230} {10 10 10} 231 232# Insert a NULL. This should be a two byte record. 233do_test types-2.3.1 { 234 execsql { 235 CREATE TABLE t3(a nullvalue); 236 INSERT INTO t3 VALUES(NULL); 237 } 238} {} 239do_test types-2.3.2 { 240 execsql { 241 SELECT a ISNULL FROM t3; 242 } 243} {1} 244 245# Check that all the record sizes are as we expected. 246do_test types-2.3.3 { 247 set root [db eval {select rootpage from sqlite_master where name = 't3'}] 248 record_sizes $root 249} {2} 250 251# Insert a couple of strings. 252do_test types-2.4.1 { 253 set string10 abcdefghij 254 set string500 [string repeat $string10 50] 255 set string500000 [string repeat $string10 50000] 256 257 execsql " 258 CREATE TABLE t4(a string); 259 INSERT INTO t4 VALUES('$string10'); 260 INSERT INTO t4 VALUES('$string500'); 261 INSERT INTO t4 VALUES('$string500000'); 262 " 263} {} 264do_test types-2.4.2 { 265 execsql { 266 SELECT a FROM t4; 267 } 268} [list $string10 $string500 $string500000] 269 270# Check that all the record sizes are as we expected. This is dependant on 271# the database encoding. 272if { $sqlite_options(utf16)==0 || [execsql {pragma encoding}] == "UTF-8" } { 273 do_test types-2.4.3 { 274 set root [db eval {select rootpage from sqlite_master where name = 't4'}] 275 record_sizes $root 276 } {12 503 500004} 277} else { 278 do_test types-2.4.3 { 279 set root [db eval {select rootpage from sqlite_master where name = 't4'}] 280 record_sizes $root 281 } {22 1003 1000004} 282} 283 284do_test types-2.5.1 { 285 execsql { 286 DROP TABLE t1; 287 DROP TABLE t2; 288 DROP TABLE t3; 289 DROP TABLE t4; 290 CREATE TABLE t1(a, b, c); 291 } 292} {} 293do_test types-2.5.2 { 294 set string10 abcdefghij 295 set string500 [string repeat $string10 50] 296 set string500000 [string repeat $string10 50000] 297 298 execsql "INSERT INTO t1 VALUES(NULL, '$string10', 4000);" 299 execsql "INSERT INTO t1 VALUES('$string500', 4000, NULL);" 300 execsql "INSERT INTO t1 VALUES(4000, NULL, '$string500000');" 301} {} 302do_test types-2.5.3 { 303 execsql { 304 SELECT * FROM t1; 305 } 306} [list {} $string10 4000 $string500 4000 {} 4000 {} $string500000] 307 308finish_test 309