# 2011 March 10 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the SQLITE_OMIT_UNIQUE_ENFORCEMENT # compiler option. # set testdir [file dirname $argv0] source $testdir/tester.tcl set uniq_enforced 1 ifcapable !unique_enforcement { set uniq_enforced 0 } # table with UNIQUE keyword on column do_test omitunique-1.1 { catchsql { CREATE TABLE t1(a TEXT UNIQUE); } } {0 {}} # table with UNIQUE clause on column do_test omitunique-1.2 { catchsql { CREATE TABLE t2(a TEXT, UNIQUE(a)); } } {0 {}} # table with UNIQUE index on column do_test omitunique-1.3 { catchsql { CREATE TABLE t3(a TEXT); CREATE UNIQUE INDEX t3a ON t3(a); } } {0 {}} # table with regular index on column do_test omitunique-1.4 { catchsql { CREATE TABLE t4(a TEXT); CREATE INDEX t4a ON t4(a); } } {0 {}} # table with no index on column do_test omitunique-1.5 { catchsql { CREATE TABLE t5(a TEXT); } } {0 {}} # run our tests using several table/index forms foreach {j tbl uniq cnt qp_est stat_enforce stat_omit } { 1 {t1} 1 1 1 {2 1} {9 9} 2 {t2} 1 1 1 {2 1} {9 9} 3 {t3} 1 1 1 {2 1} {9 9} 4 {t4} 0 9 10 {9 9} {9 9} 5 {t5} 0 9 100000 9 9 } { do_test omitunique-2.0.$j.1 { catchsql [ subst {INSERT INTO $tbl (a) VALUES('abc'); }] } {0 {}} do_test omitunique-2.0.$j.2 { catchsql [ subst {INSERT INTO $tbl (a) VALUES('123'); }] } {0 {}} # check various INSERT commands foreach {i cmd err} { 1 {INSERT} 1 2 {INSERT OR IGNORE} 0 3 {INSERT OR REPLACE} 0 4 {REPLACE} 0 5 {INSERT OR FAIL} 1 6 {INSERT OR ABORT} 1 7 {INSERT OR ROLLBACK} 1 } { ifcapable explain { set x [execsql [ subst { EXPLAIN $cmd INTO $tbl (a) VALUES('abc'); }]] ifcapable unique_enforcement { do_test omitunique-2.1.$j.$i.1 { regexp { IsUnique } $x } $uniq } ifcapable !unique_enforcement { do_test omitunique-2.1.$j.$i.1 { regexp { IsUnique } $x } {0} } } if { $uniq_enforced==0 || $uniq==0 || $err==0 } { set msg {0 {}} } { set msg {1 {column a is not unique}} } do_test omitunique-2.1.$j.$i.3 { catchsql [ subst {$cmd INTO $tbl (a) VALUES('abc'); }] } $msg } # end foreach cmd # check UPDATE command ifcapable explain { set x [execsql [ subst { EXPLAIN UPDATE $tbl SET a='abc'; }]] ifcapable unique_enforcement { do_test omitunique-2.2.$j.1 { regexp { IsUnique } $x } $uniq } ifcapable !unique_enforcement { do_test omitunique-2.2.$j.1 { regexp { IsUnique } $x } {0} } } if { $uniq_enforced==0 || $uniq==0 } { set msg {0 {}} } { set msg {1 {column a is not unique}} } do_test omitunique-2.2.$j.3 { catchsql [ subst { UPDATE $tbl SET a='abc'; }] } $msg # check record counts do_test omitunique-2.3.$j { execsql [ subst { SELECT count(*) FROM $tbl WHERE a='abc'; }] } $cnt # make sure the query planner row estimate not affected because of omit enforcement ifcapable explain { do_test omitunique-2.4.$j { set x [ execsql [ subst { EXPLAIN QUERY PLAN SELECT count(*) FROM $tbl WHERE a='abc'; }]] set y [ subst {~$qp_est row} ] regexp $y $x } {1} } # make sure we omit extra OP_Next opcodes when the UNIQUE constraints # mean there will only be a single pass through the code ifcapable explain { set x [execsql [ subst { EXPLAIN SELECT * FROM $tbl WHERE a='abc'; }]] do_test omitunique-2.5.$j { if { [ regexp { Next } $x ] } { expr { 0 } } { expr { 1 } } } $uniq } # make sure analyze index stats correct ifcapable analyze { if { $uniq_enforced==0 } { set msg [ list $stat_omit ] } { set msg [ list $stat_enforce ] } do_test omitunique-2.6.$j { execsql [ subst { ANALYZE $tbl; } ] execsql [ subst { SELECT stat FROM sqlite_stat1 WHERE tbl='$tbl'; } ] } $msg } } # end foreach tbl finish_test