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