1# 2006 July 25 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. The focus 12# of this test is reading and writing to the database from within a 13# virtual table xSync() callback. 14# 15# $Id: vtab7.test,v 1.4 2007/12/04 16:54:53 drh Exp $ 16 17set testdir [file dirname $argv0] 18source $testdir/tester.tcl 19 20ifcapable !vtab { 21 finish_test 22 return 23} 24 25# Register the echo module. Code inside the echo module appends elements 26# to the global tcl list variable ::echo_module whenever SQLite invokes 27# certain module callbacks. This includes the xSync(), xCommit() and 28# xRollback() callbacks. For each of these callback, two elements are 29# appended to ::echo_module, as follows: 30# 31# Module method Elements appended to ::echo_module 32# ------------------------------------------------------- 33# xSync() xSync echo($tablename) 34# xCommit() xCommit echo($tablename) 35# xRollback() xRollback echo($tablename) 36# ------------------------------------------------------- 37# 38# In each case, $tablename is replaced by the name of the real table (not 39# the echo table). By setting up a tcl trace on the ::echo_module variable, 40# code in this file arranges for a Tcl script to be executed from within 41# the echo module xSync() callback. 42# 43register_echo_module [sqlite3_connection_pointer db] 44trace add variable ::echo_module write echo_module_trace 45 46# This Tcl proc is invoked whenever the ::echo_module variable is written. 47# 48proc echo_module_trace {args} { 49 # Filter out writes to ::echo_module that are not xSync, xCommit or 50 # xRollback callbacks. 51 if {[llength $::echo_module] < 2} return 52 set x [lindex $::echo_module end-1] 53 if {$x ne "xSync" && $x ne "xCommit" && $x ne "xRollback"} return 54 55 regexp {^echo.(.*).$} [lindex $::echo_module end] dummy tablename 56 # puts "Ladies and gentlemen, an $x on $tablename!" 57 58 if {[info exists ::callbacks($x,$tablename)]} { 59 eval $::callbacks($x,$tablename) 60 } 61} 62 63# The following tests, vtab7-1.*, test that the trace callback on 64# ::echo_module is providing the expected tcl callbacks. 65do_test vtab7-1.1 { 66 execsql { 67 CREATE TABLE abc(a, b, c); 68 CREATE VIRTUAL TABLE abc2 USING echo(abc); 69 } 70} {} 71 72do_test vtab7-1.2 { 73 set ::callbacks(xSync,abc) {incr ::counter} 74 set ::counter 0 75 execsql { 76 INSERT INTO abc2 VALUES(1, 2, 3); 77 } 78 set ::counter 79} {1} 80 81# Write to an existing database table from within an xSync callback. 82do_test vtab7-2.1 { 83 set ::callbacks(xSync,abc) { 84 execsql {INSERT INTO log VALUES('xSync');} 85 } 86 execsql { 87 CREATE TABLE log(msg); 88 INSERT INTO abc2 VALUES(4, 5, 6); 89 SELECT * FROM log; 90 } 91} {xSync} 92do_test vtab7-2.3 { 93 execsql { 94 INSERT INTO abc2 VALUES(4, 5, 6); 95 SELECT * FROM log; 96 } 97} {xSync xSync} 98do_test vtab7-2.4 { 99 execsql { 100 INSERT INTO abc2 VALUES(4, 5, 6); 101 SELECT * FROM log; 102 } 103} {xSync xSync xSync} 104 105# Create a database table from within xSync callback. 106do_test vtab7-2.5 { 107 set ::callbacks(xSync,abc) { 108 execsql { CREATE TABLE newtab(d, e, f); } 109 } 110 execsql { 111 INSERT INTO abc2 VALUES(1, 2, 3); 112 SELECT name FROM sqlite_master ORDER BY name; 113 } 114} {abc abc2 log newtab} 115 116# Drop a database table from within xSync callback. 117# This is not allowed. Tables cannot be dropped while 118# any other statement is active. 119# 120do_test vtab7-2.6 { 121 set ::callbacks(xSync,abc) { 122 set ::rc [catchsql { DROP TABLE newtab }] 123 } 124 execsql { 125 INSERT INTO abc2 VALUES(1, 2, 3); 126 SELECT name FROM sqlite_master ORDER BY name; 127 } 128} {abc abc2 log newtab} 129do_test vtab7-2.6.1 { 130 set ::rc 131} {1 {database table is locked}} 132execsql {DROP TABLE newtab} 133 134# Write to an attached database from xSync(). 135ifcapable attach { 136 do_test vtab7-3.1 { 137 file delete -force test2.db 138 file delete -force test2.db-journal 139 execsql { 140 ATTACH 'test2.db' AS db2; 141 CREATE TABLE db2.stuff(description, shape, color); 142 } 143 set ::callbacks(xSync,abc) { 144 execsql { INSERT INTO db2.stuff VALUES('abc', 'square', 'green'); } 145 } 146 execsql { 147 INSERT INTO abc2 VALUES(1, 2, 3); 148 SELECT * from stuff; 149 } 150 } {abc square green} 151} 152 153# UPDATE: The next test passes, but leaks memory. So leave it out. 154# 155# The following tests test that writing to the database from within 156# the xCommit callback causes a misuse error. 157# do_test vtab7-4.1 { 158# unset -nocomplain ::callbacks(xSync,abc) 159# set ::callbacks(xCommit,abc) { 160# execsql { INSERT INTO log VALUES('hello') } 161# } 162# catchsql { 163# INSERT INTO abc2 VALUES(1, 2, 3); 164# } 165# } {1 {library routine called out of sequence}} 166 167# These tests, vtab7-4.*, test that an SQLITE_LOCKED error is returned 168# if an attempt to write to a virtual module table or create a new 169# virtual table from within an xSync() callback. 170do_test vtab7-4.1 { 171 execsql { 172 CREATE TABLE def(d, e, f); 173 CREATE VIRTUAL TABLE def2 USING echo(def); 174 } 175 set ::callbacks(xSync,abc) { 176 set ::error [catchsql { INSERT INTO def2 VALUES(1, 2, 3) }] 177 } 178 execsql { 179 INSERT INTO abc2 VALUES(1, 2, 3); 180 } 181 set ::error 182} {1 {database table is locked}} 183do_test vtab7-4.2 { 184 set ::callbacks(xSync,abc) { 185 set ::error [catchsql { CREATE VIRTUAL TABLE def3 USING echo(def) }] 186 } 187 execsql { 188 INSERT INTO abc2 VALUES(1, 2, 3); 189 } 190 set ::error 191} {1 {database table is locked}} 192 193do_test vtab7-4.3 { 194 set ::callbacks(xSync,abc) { 195 set ::error [catchsql { DROP TABLE def2 }] 196 } 197 execsql { 198 INSERT INTO abc2 VALUES(1, 2, 3); 199 SELECT name FROM sqlite_master ORDER BY name; 200 } 201 set ::error 202} {1 {database table is locked}} 203 204trace remove variable ::echo_module write echo_module_trace 205unset -nocomplain ::callbacks 206 207finish_test 208