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