xref: /sqlite-3.40.0/test/vtab7.test (revision ff4fa772)
15bd270b2Sdanielk1977# 2006 July 25
25bd270b2Sdanielk1977#
35bd270b2Sdanielk1977# The author disclaims copyright to this source code.  In place of
45bd270b2Sdanielk1977# a legal notice, here is a blessing:
55bd270b2Sdanielk1977#
65bd270b2Sdanielk1977#    May you do good and not evil.
75bd270b2Sdanielk1977#    May you find forgiveness for yourself and forgive others.
85bd270b2Sdanielk1977#    May you share freely, never taking more than you give.
95bd270b2Sdanielk1977#
105bd270b2Sdanielk1977#***********************************************************************
115bd270b2Sdanielk1977# This file implements regression tests for SQLite library. The focus
125bd270b2Sdanielk1977# of this test is reading and writing to the database from within a
135bd270b2Sdanielk1977# virtual table xSync() callback.
145bd270b2Sdanielk1977#
1577658e2fSdrh# $Id: vtab7.test,v 1.4 2007/12/04 16:54:53 drh Exp $
165bd270b2Sdanielk1977
175bd270b2Sdanielk1977set testdir [file dirname $argv0]
185bd270b2Sdanielk1977source $testdir/tester.tcl
195bd270b2Sdanielk1977
205bd270b2Sdanielk1977ifcapable !vtab {
215bd270b2Sdanielk1977  finish_test
225bd270b2Sdanielk1977  return
235bd270b2Sdanielk1977}
245bd270b2Sdanielk1977
255bd270b2Sdanielk1977# Register the echo module. Code inside the echo module appends elements
265bd270b2Sdanielk1977# to the global tcl list variable ::echo_module whenever SQLite invokes
275bd270b2Sdanielk1977# certain module callbacks. This includes the xSync(), xCommit() and
285bd270b2Sdanielk1977# xRollback() callbacks. For each of these callback, two elements are
295bd270b2Sdanielk1977# appended to ::echo_module, as follows:
305bd270b2Sdanielk1977#
315bd270b2Sdanielk1977#     Module method        Elements appended to ::echo_module
325bd270b2Sdanielk1977#     -------------------------------------------------------
335bd270b2Sdanielk1977#     xSync()              xSync echo($tablename)
345bd270b2Sdanielk1977#     xCommit()            xCommit echo($tablename)
355bd270b2Sdanielk1977#     xRollback()          xRollback echo($tablename)
365bd270b2Sdanielk1977#     -------------------------------------------------------
375bd270b2Sdanielk1977#
385bd270b2Sdanielk1977# In each case, $tablename is replaced by the name of the real table (not
395bd270b2Sdanielk1977# the echo table). By setting up a tcl trace on the ::echo_module variable,
405bd270b2Sdanielk1977# code in this file arranges for a Tcl script to be executed from within
415bd270b2Sdanielk1977# the echo module xSync() callback.
425bd270b2Sdanielk1977#
435bd270b2Sdanielk1977register_echo_module [sqlite3_connection_pointer db]
445bd270b2Sdanielk1977trace add variable ::echo_module write echo_module_trace
455bd270b2Sdanielk1977
465bd270b2Sdanielk1977# This Tcl proc is invoked whenever the ::echo_module variable is written.
475bd270b2Sdanielk1977#
485bd270b2Sdanielk1977proc echo_module_trace {args} {
495bd270b2Sdanielk1977  # Filter out writes to ::echo_module that are not xSync, xCommit or
505bd270b2Sdanielk1977  # xRollback callbacks.
515bd270b2Sdanielk1977  if {[llength $::echo_module] < 2} return
525bd270b2Sdanielk1977  set x [lindex $::echo_module end-1]
535bd270b2Sdanielk1977  if {$x ne "xSync" && $x ne "xCommit" && $x ne "xRollback"} return
545bd270b2Sdanielk1977
555bd270b2Sdanielk1977  regexp {^echo.(.*).$} [lindex $::echo_module end] dummy tablename
565bd270b2Sdanielk1977  # puts "Ladies and gentlemen, an $x on $tablename!"
575bd270b2Sdanielk1977
585bd270b2Sdanielk1977  if {[info exists ::callbacks($x,$tablename)]} {
595bd270b2Sdanielk1977    eval $::callbacks($x,$tablename)
605bd270b2Sdanielk1977  }
615bd270b2Sdanielk1977}
625bd270b2Sdanielk1977
635bd270b2Sdanielk1977# The following tests, vtab7-1.*, test that the trace callback on
645bd270b2Sdanielk1977# ::echo_module is providing the expected tcl callbacks.
655bd270b2Sdanielk1977do_test vtab7-1.1 {
665bd270b2Sdanielk1977  execsql {
675bd270b2Sdanielk1977    CREATE TABLE abc(a, b, c);
685bd270b2Sdanielk1977    CREATE VIRTUAL TABLE abc2 USING echo(abc);
695bd270b2Sdanielk1977  }
705bd270b2Sdanielk1977} {}
715bd270b2Sdanielk1977
725bd270b2Sdanielk1977do_test vtab7-1.2 {
735bd270b2Sdanielk1977  set ::callbacks(xSync,abc) {incr ::counter}
745bd270b2Sdanielk1977  set ::counter 0
755bd270b2Sdanielk1977  execsql {
765bd270b2Sdanielk1977    INSERT INTO abc2 VALUES(1, 2, 3);
775bd270b2Sdanielk1977  }
785bd270b2Sdanielk1977  set ::counter
795bd270b2Sdanielk1977} {1}
805bd270b2Sdanielk1977
815bd270b2Sdanielk1977# Write to an existing database table from within an xSync callback.
825bd270b2Sdanielk1977do_test vtab7-2.1 {
835bd270b2Sdanielk1977  set ::callbacks(xSync,abc) {
845bd270b2Sdanielk1977    execsql {INSERT INTO log VALUES('xSync');}
855bd270b2Sdanielk1977  }
865bd270b2Sdanielk1977  execsql {
875bd270b2Sdanielk1977    CREATE TABLE log(msg);
885bd270b2Sdanielk1977    INSERT INTO abc2 VALUES(4, 5, 6);
895bd270b2Sdanielk1977    SELECT * FROM log;
905bd270b2Sdanielk1977  }
915bd270b2Sdanielk1977} {xSync}
925bd270b2Sdanielk1977do_test vtab7-2.3 {
935bd270b2Sdanielk1977  execsql {
945bd270b2Sdanielk1977    INSERT INTO abc2 VALUES(4, 5, 6);
955bd270b2Sdanielk1977    SELECT * FROM log;
965bd270b2Sdanielk1977  }
975bd270b2Sdanielk1977} {xSync xSync}
985bd270b2Sdanielk1977do_test vtab7-2.4 {
995bd270b2Sdanielk1977  execsql {
1005bd270b2Sdanielk1977    INSERT INTO abc2 VALUES(4, 5, 6);
1015bd270b2Sdanielk1977    SELECT * FROM log;
1025bd270b2Sdanielk1977  }
1035bd270b2Sdanielk1977} {xSync xSync xSync}
1045bd270b2Sdanielk1977
1055bd270b2Sdanielk1977# Create a database table from within xSync callback.
1065bd270b2Sdanielk1977do_test vtab7-2.5 {
1075bd270b2Sdanielk1977  set ::callbacks(xSync,abc) {
1085bd270b2Sdanielk1977    execsql { CREATE TABLE newtab(d, e, f); }
1095bd270b2Sdanielk1977  }
1105bd270b2Sdanielk1977  execsql {
1115bd270b2Sdanielk1977    INSERT INTO abc2 VALUES(1, 2, 3);
1125bd270b2Sdanielk1977    SELECT name FROM sqlite_master ORDER BY name;
1135bd270b2Sdanielk1977  }
1145bd270b2Sdanielk1977} {abc abc2 log newtab}
1155bd270b2Sdanielk1977
1165bd270b2Sdanielk1977# Drop a database table from within xSync callback.
11777658e2fSdrh# This is not allowed.  Tables cannot be dropped while
11877658e2fSdrh# any other statement is active.
11977658e2fSdrh#
1205bd270b2Sdanielk1977do_test vtab7-2.6 {
1215bd270b2Sdanielk1977  set ::callbacks(xSync,abc) {
12277658e2fSdrh    set ::rc [catchsql { DROP TABLE newtab }]
1235bd270b2Sdanielk1977  }
1245bd270b2Sdanielk1977  execsql {
1255bd270b2Sdanielk1977    INSERT INTO abc2 VALUES(1, 2, 3);
1265bd270b2Sdanielk1977    SELECT name FROM sqlite_master ORDER BY name;
1275bd270b2Sdanielk1977  }
12877658e2fSdrh} {abc abc2 log newtab}
12977658e2fSdrhdo_test vtab7-2.6.1 {
13077658e2fSdrh  set ::rc
13177658e2fSdrh} {1 {database table is locked}}
13277658e2fSdrhexecsql {DROP TABLE newtab}
1335bd270b2Sdanielk1977
1345bd270b2Sdanielk1977# Write to an attached database from xSync().
1355a8f9374Sdanielk1977ifcapable attach {
1365bd270b2Sdanielk1977  do_test vtab7-3.1 {
137fda06befSmistachkin    forcedelete test2.db
138fda06befSmistachkin    forcedelete test2.db-journal
1395bd270b2Sdanielk1977    execsql {
1405bd270b2Sdanielk1977      ATTACH 'test2.db' AS db2;
1415bd270b2Sdanielk1977      CREATE TABLE db2.stuff(description, shape, color);
1425bd270b2Sdanielk1977    }
1435bd270b2Sdanielk1977    set ::callbacks(xSync,abc) {
1445bd270b2Sdanielk1977      execsql { INSERT INTO db2.stuff VALUES('abc', 'square', 'green'); }
1455bd270b2Sdanielk1977    }
1465bd270b2Sdanielk1977    execsql {
1475bd270b2Sdanielk1977      INSERT INTO abc2 VALUES(1, 2, 3);
1485bd270b2Sdanielk1977      SELECT * from stuff;
1495bd270b2Sdanielk1977    }
1505bd270b2Sdanielk1977  } {abc square green}
1515a8f9374Sdanielk1977}
1525bd270b2Sdanielk1977
1535bd270b2Sdanielk1977# UPDATE: The next test passes, but leaks memory. So leave it out.
1545bd270b2Sdanielk1977#
1555bd270b2Sdanielk1977# The following tests test that writing to the database from within
1565bd270b2Sdanielk1977# the xCommit callback causes a misuse error.
1575bd270b2Sdanielk1977# do_test vtab7-4.1 {
1585bd270b2Sdanielk1977#   unset -nocomplain ::callbacks(xSync,abc)
1595bd270b2Sdanielk1977#   set ::callbacks(xCommit,abc) {
1605bd270b2Sdanielk1977#     execsql { INSERT INTO log VALUES('hello') }
1615bd270b2Sdanielk1977#   }
1625bd270b2Sdanielk1977#   catchsql {
1635bd270b2Sdanielk1977#     INSERT INTO abc2 VALUES(1, 2, 3);
1645bd270b2Sdanielk1977#   }
165*ff4fa772Sdrh# } {1 {bad parameter or other API misuse}}
1665bd270b2Sdanielk1977
16720b1eaffSdanielk1977# These tests, vtab7-4.*, test that an SQLITE_LOCKED error is returned
16820b1eaffSdanielk1977# if an attempt to write to a virtual module table or create a new
16920b1eaffSdanielk1977# virtual table from within an xSync() callback.
17020b1eaffSdanielk1977do_test vtab7-4.1 {
17120b1eaffSdanielk1977  execsql {
17220b1eaffSdanielk1977    CREATE TABLE def(d, e, f);
17320b1eaffSdanielk1977    CREATE VIRTUAL TABLE def2 USING echo(def);
17420b1eaffSdanielk1977  }
17520b1eaffSdanielk1977  set ::callbacks(xSync,abc) {
17620b1eaffSdanielk1977    set ::error [catchsql { INSERT INTO def2 VALUES(1, 2, 3) }]
17720b1eaffSdanielk1977  }
17820b1eaffSdanielk1977  execsql {
17920b1eaffSdanielk1977    INSERT INTO abc2 VALUES(1, 2, 3);
18020b1eaffSdanielk1977  }
18120b1eaffSdanielk1977  set ::error
18220b1eaffSdanielk1977} {1 {database table is locked}}
18320b1eaffSdanielk1977do_test vtab7-4.2 {
18420b1eaffSdanielk1977  set ::callbacks(xSync,abc) {
18520b1eaffSdanielk1977    set ::error [catchsql { CREATE VIRTUAL TABLE def3 USING echo(def) }]
18620b1eaffSdanielk1977  }
18720b1eaffSdanielk1977  execsql {
18820b1eaffSdanielk1977    INSERT INTO abc2 VALUES(1, 2, 3);
18920b1eaffSdanielk1977  }
19020b1eaffSdanielk1977  set ::error
19120b1eaffSdanielk1977} {1 {database table is locked}}
19220b1eaffSdanielk1977
19320b1eaffSdanielk1977do_test vtab7-4.3 {
19420b1eaffSdanielk1977  set ::callbacks(xSync,abc) {
19520b1eaffSdanielk1977    set ::error [catchsql { DROP TABLE def2 }]
19620b1eaffSdanielk1977  }
19720b1eaffSdanielk1977  execsql {
19820b1eaffSdanielk1977    INSERT INTO abc2 VALUES(1, 2, 3);
19920b1eaffSdanielk1977    SELECT name FROM sqlite_master ORDER BY name;
20020b1eaffSdanielk1977  }
20120b1eaffSdanielk1977  set ::error
20220b1eaffSdanielk1977} {1 {database table is locked}}
2035bd270b2Sdanielk1977
2045bd270b2Sdanielk1977trace remove variable ::echo_module write echo_module_trace
2055bd270b2Sdanielk1977unset -nocomplain ::callbacks
2065bd270b2Sdanielk1977
2075bd270b2Sdanielk1977finish_test
208