Make sure statement journals are initiated when doing DROP operations
(since the DROP might fail after sqlite_master changes). Also make sure statement journals are initiated if there are pending SELECT statements. Ticket #2820. (CVS 4591) FossilOrigin-Name: bf34284ff0c60ae6e735e09bb29cd48b158e8dce
This commit is contained in:
parent
0349688fbc
commit
77658e2f0d
19
manifest
19
manifest
@ -1,5 +1,5 @@
|
|||||||
C Fix\sa\sbug\sin\sthe\sTCL\scode\sfor\ssqlite3_analyzer.\s(CVS\s4590)
|
C Make\ssure\sstatement\sjournals\sare\sinitiated\swhen\sdoing\sDROP\soperations\n(since\sthe\sDROP\smight\sfail\safter\ssqlite_master\schanges).\s\sAlso\smake\nsure\sstatement\sjournals\sare\sinitiated\sif\sthere\sare\spending\sSELECT\nstatements.\s\sTicket\s#2820.\s(CVS\s4591)
|
||||||
D 2007-12-04T13:41:51
|
D 2007-12-04T16:54:53
|
||||||
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7
|
||||||
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9
|
||||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||||
@ -86,7 +86,7 @@ F src/btmutex.c 442be6f068d77ca9ffd69899cf0a3943c244548c
|
|||||||
F src/btree.c c5844bb4bbe997a7c8400a714fcf304d91855383
|
F src/btree.c c5844bb4bbe997a7c8400a714fcf304d91855383
|
||||||
F src/btree.h d0736ebca4b6eafbdd823c46a8de574cea078211
|
F src/btree.h d0736ebca4b6eafbdd823c46a8de574cea078211
|
||||||
F src/btreeInt.h 4330c19b8314545fdb209cc77e2a57f6a5290e9c
|
F src/btreeInt.h 4330c19b8314545fdb209cc77e2a57f6a5290e9c
|
||||||
F src/build.c 04e0783a105d4d65c1850815adfdfe7403dcb592
|
F src/build.c 580561a0d9e070ff2741f3b115cae51c1ef08260
|
||||||
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
F src/callback.c 77b302b0d41468dcda78c70e706e5b84577f0fa0
|
||||||
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131
|
||||||
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
|
F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6
|
||||||
@ -168,11 +168,11 @@ F src/update.c 2add92a6159fa73128653706574afbcd8fd1dd80
|
|||||||
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736
|
||||||
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624
|
||||||
F src/vacuum.c a5e51c77370c1a6445e86d42abfc43867cdd482d
|
F src/vacuum.c a5e51c77370c1a6445e86d42abfc43867cdd482d
|
||||||
F src/vdbe.c 9859467b3762a1c05f956b5f556fb922e139ff9f
|
F src/vdbe.c a99beac1162fa490c4b75ac36ed97146ab181837
|
||||||
F src/vdbe.h 79e09ff13b85457abe437d9814454534ebbc1fe3
|
F src/vdbe.h 79e09ff13b85457abe437d9814454534ebbc1fe3
|
||||||
F src/vdbeInt.h 630145b9bfaa19190ab491f52658a7db550f2247
|
F src/vdbeInt.h 630145b9bfaa19190ab491f52658a7db550f2247
|
||||||
F src/vdbeapi.c dd2c43317294e0a013e9f634ee4209a3ea459b43
|
F src/vdbeapi.c dd2c43317294e0a013e9f634ee4209a3ea459b43
|
||||||
F src/vdbeaux.c 285f113364134f7c1571456723dcb84be89e6c3f
|
F src/vdbeaux.c 5bc14ff3da6c6b3b7f643cbc3d50a344e9b599f8
|
||||||
F src/vdbeblob.c 82f51cdf9b0c0af729732fde48c824e498c0a1ca
|
F src/vdbeblob.c 82f51cdf9b0c0af729732fde48c824e498c0a1ca
|
||||||
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
|
F src/vdbefifo.c 334c838c8f42d61a94813d136019ee566b5dc2f6
|
||||||
F src/vdbemem.c 123994fcd344993d2fb050a83b91b341bbbd08b4
|
F src/vdbemem.c 123994fcd344993d2fb050a83b91b341bbbd08b4
|
||||||
@ -477,6 +477,7 @@ F test/tkt2643.test 3f3ebb743da00d4fed4fcf6daed92a0e18e57813
|
|||||||
F test/tkt2686.test 8815c3eeae7c8363bd7c2889349ec39e8bc8000d
|
F test/tkt2686.test 8815c3eeae7c8363bd7c2889349ec39e8bc8000d
|
||||||
F test/tkt2767.test 6b02308d553d194f329a469bf5c157fe724738d4
|
F test/tkt2767.test 6b02308d553d194f329a469bf5c157fe724738d4
|
||||||
F test/tkt2817.test 709a2201a5590bf56cb97f6fb168a62282203fd1
|
F test/tkt2817.test 709a2201a5590bf56cb97f6fb168a62282203fd1
|
||||||
|
F test/tkt2820.test 017fdee33aaef7abc092beab6088816f1942304b
|
||||||
F test/trace.test 75ffc1b992c780d054748a656e3e7fd674f18567
|
F test/trace.test 75ffc1b992c780d054748a656e3e7fd674f18567
|
||||||
F test/trans.test b73289992b46d38d9479ecc4fdc03d8edb2413dc
|
F test/trans.test b73289992b46d38d9479ecc4fdc03d8edb2413dc
|
||||||
F test/trigger1.test 7c13f39ca36f529bf856e05c7d004fc0531d48b4
|
F test/trigger1.test 7c13f39ca36f529bf856e05c7d004fc0531d48b4
|
||||||
@ -504,7 +505,7 @@ F test/vtab3.test f38d6d7d19f08bffdadce4d5b8cba078f8118587
|
|||||||
F test/vtab4.test a9d7104d41a787754a734740d7aa61c807a69f87
|
F test/vtab4.test a9d7104d41a787754a734740d7aa61c807a69f87
|
||||||
F test/vtab5.test 26bc7a0a52c5c2bcfa849ba327f8a0d4abccdb23
|
F test/vtab5.test 26bc7a0a52c5c2bcfa849ba327f8a0d4abccdb23
|
||||||
F test/vtab6.test ec0036f29f8a803da9935206f2d9d1b6a8026392
|
F test/vtab6.test ec0036f29f8a803da9935206f2d9d1b6a8026392
|
||||||
F test/vtab7.test 9249e8e31f4f1a44f07984b402d12ce3e63be4f3
|
F test/vtab7.test a8c3c3cb3eb60be364991bd714e4927e26c4cd85
|
||||||
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
|
F test/vtab8.test e19fa4a538fcd1bb66c22825fa8f71618fb13583
|
||||||
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
|
F test/vtab9.test ea58d2b95d61955f87226381716b2d0b1d4e4f9b
|
||||||
F test/vtabA.test 9cb6b1afead6fdd91bbdf1ca65c44ccfd9b10936
|
F test/vtabA.test 9cb6b1afead6fdd91bbdf1ca65c44ccfd9b10936
|
||||||
@ -596,7 +597,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||||
P 78f359dffa6f4af4d5b7e4523f451e0e405350c0
|
P 7c2cf4542852a81daf29a930ab103c52bb678326
|
||||||
R cfc28c51a4620cec082dc386c8465836
|
R c111fb18ebb6378f510e950ea7f7ef09
|
||||||
U drh
|
U drh
|
||||||
Z c95254d1012df22f0a03f3a42376bc6c
|
Z 60a6d3adb97dfb253eaa60aa3a1f2c5c
|
||||||
|
@ -1 +1 @@
|
|||||||
7c2cf4542852a81daf29a930ab103c52bb678326
|
bf34284ff0c60ae6e735e09bb29cd48b158e8dce
|
@ -22,7 +22,7 @@
|
|||||||
** COMMIT
|
** COMMIT
|
||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.449 2007/12/02 11:46:35 danielk1977 Exp $
|
** $Id: build.c,v 1.450 2007/12/04 16:54:53 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -1994,7 +1994,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
|||||||
if( v ){
|
if( v ){
|
||||||
Trigger *pTrigger;
|
Trigger *pTrigger;
|
||||||
Db *pDb = &db->aDb[iDb];
|
Db *pDb = &db->aDb[iDb];
|
||||||
sqlite3BeginWriteOperation(pParse, 0, iDb);
|
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
if( IsVirtual(pTab) ){
|
if( IsVirtual(pTab) ){
|
||||||
@ -2808,6 +2808,7 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){
|
|||||||
/* Generate code to remove the index and from the master table */
|
/* Generate code to remove the index and from the master table */
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
if( v ){
|
if( v ){
|
||||||
|
sqlite3BeginWriteOperation(pParse, 1, iDb);
|
||||||
sqlite3NestedParse(pParse,
|
sqlite3NestedParse(pParse,
|
||||||
"DELETE FROM %Q.%s WHERE name=%Q",
|
"DELETE FROM %Q.%s WHERE name=%Q",
|
||||||
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
|
db->aDb[iDb].zName, SCHEMA_TABLE(iDb),
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** commenting and indentation practices when changing or adding code.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.655 2007/11/29 17:05:18 danielk1977 Exp $
|
** $Id: vdbe.c,v 1.656 2007/12/04 16:54:53 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -2410,7 +2410,8 @@ case OP_MakeRecord: {
|
|||||||
case OP_Statement: { /* no-push */
|
case OP_Statement: { /* no-push */
|
||||||
int i = pOp->p1;
|
int i = pOp->p1;
|
||||||
Btree *pBt;
|
Btree *pBt;
|
||||||
if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt)!=0 && !(db->autoCommit) ){
|
if( i>=0 && i<db->nDb && (pBt = db->aDb[i].pBt)!=0
|
||||||
|
&& (db->autoCommit==0 || db->activeVdbeCnt>1) ){
|
||||||
assert( sqlite3BtreeIsInTrans(pBt) );
|
assert( sqlite3BtreeIsInTrans(pBt) );
|
||||||
assert( (p->btreeMask & (1<<i))!=0 );
|
assert( (p->btreeMask & (1<<i))!=0 );
|
||||||
if( !sqlite3BtreeIsInStmt(pBt) ){
|
if( !sqlite3BtreeIsInStmt(pBt) ){
|
||||||
@ -4088,6 +4089,7 @@ case OP_Destroy: {
|
|||||||
#endif
|
#endif
|
||||||
if( iCnt>1 ){
|
if( iCnt>1 ){
|
||||||
rc = SQLITE_LOCKED;
|
rc = SQLITE_LOCKED;
|
||||||
|
p->errorAction = OE_Abort;
|
||||||
}else{
|
}else{
|
||||||
assert( iCnt==1 );
|
assert( iCnt==1 );
|
||||||
assert( (p->btreeMask & (1<<pOp->p2))!=0 );
|
assert( (p->btreeMask & (1<<pOp->p2))!=0 );
|
||||||
|
@ -270,10 +270,17 @@ int sqlite3VdbeOpcodeNoPush(u8 op){
|
|||||||
** entries that static analysis reveals this program might need.
|
** entries that static analysis reveals this program might need.
|
||||||
**
|
**
|
||||||
** This routine also does the following optimization: It scans for
|
** This routine also does the following optimization: It scans for
|
||||||
** Halt instructions where P1==SQLITE_CONSTRAINT or P2==OE_Abort or for
|
** instructions that might cause a statement rollback. Such instructions
|
||||||
** IdxInsert instructions where P2!=0. If no such instruction is
|
** are:
|
||||||
** found, then every Statement instruction is changed to a Noop. In
|
**
|
||||||
** this way, we avoid creating the statement journal file unnecessarily.
|
** * OP_Halt with P1=SQLITE_CONSTRAINT and P2=OE_Abort.
|
||||||
|
** * OP_Destroy
|
||||||
|
** * OP_VUpdate
|
||||||
|
** * OP_VRename
|
||||||
|
**
|
||||||
|
** If no such instruction is found, then every Statement instruction
|
||||||
|
** is changed to a Noop. In this way, we avoid creating the statement
|
||||||
|
** journal file unnecessarily.
|
||||||
*/
|
*/
|
||||||
static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
|
static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
|
||||||
int i;
|
int i;
|
||||||
@ -299,6 +306,8 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
|
|||||||
}
|
}
|
||||||
}else if( opcode==OP_Statement ){
|
}else if( opcode==OP_Statement ){
|
||||||
hasStatementBegin = 1;
|
hasStatementBegin = 1;
|
||||||
|
}else if( opcode==OP_Destroy ){
|
||||||
|
doesStatementRollback = 1;
|
||||||
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
#ifndef SQLITE_OMIT_VIRTUALTABLE
|
||||||
}else if( opcode==OP_VUpdate || opcode==OP_VRename ){
|
}else if( opcode==OP_VUpdate || opcode==OP_VRename ){
|
||||||
doesStatementRollback = 1;
|
doesStatementRollback = 1;
|
||||||
@ -1387,7 +1396,7 @@ int sqlite3VdbeHalt(Vdbe *p){
|
|||||||
/* Check for one of the special errors */
|
/* Check for one of the special errors */
|
||||||
mrc = p->rc & 0xff;
|
mrc = p->rc & 0xff;
|
||||||
isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
|
isSpecialError = mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR
|
||||||
|| mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL ;
|
|| mrc==SQLITE_INTERRUPT || mrc==SQLITE_FULL;
|
||||||
if( isSpecialError ){
|
if( isSpecialError ){
|
||||||
/* This loop does static analysis of the query to see which of the
|
/* This loop does static analysis of the query to see which of the
|
||||||
** following three categories it falls into:
|
** following three categories it falls into:
|
||||||
|
94
test/tkt2820.test
Normal file
94
test/tkt2820.test
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
# 2007 Dec 4
|
||||||
|
#
|
||||||
|
# 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 is to test that ticket #2820 has been fixed.
|
||||||
|
# Ticket #2820 observes that a DROP TABLE statement that
|
||||||
|
# occurs while a query is in process will fail with a
|
||||||
|
# "database is locked" error, but the entry in the sqlite_master
|
||||||
|
# table will still be removed. This is incorrect. The
|
||||||
|
# entry in the sqlite_master table should persist when
|
||||||
|
# the DROP fails due to an error.
|
||||||
|
#
|
||||||
|
# $Id: tkt2820.test,v 1.1 2007/12/04 16:54:53 drh Exp $
|
||||||
|
#
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
proc test_schema_change {testid init ddl res} {
|
||||||
|
db close
|
||||||
|
file delete -force test.db test.db-journal
|
||||||
|
sqlite3 db test.db
|
||||||
|
execsql $init
|
||||||
|
do_test tkt2820-$testid.1 {
|
||||||
|
set STMT [sqlite3_prepare db {SELECT * FROM sqlite_master} -1 DUMMY]
|
||||||
|
sqlite3_step $STMT
|
||||||
|
} {SQLITE_ROW}
|
||||||
|
#if {$testid==3} {execsql {PRAGMA vdbe_trace=ON}}
|
||||||
|
do_test tkt2820-$testid.2 "catchsql [list $ddl]" \
|
||||||
|
{1 {database table is locked}}
|
||||||
|
do_test tkt2820-$testid.3 {
|
||||||
|
sqlite3_finalize $STMT
|
||||||
|
execsql {SELECT name FROM sqlite_master ORDER BY 1}
|
||||||
|
} $res
|
||||||
|
integrity_check tkt2820-$testid.4
|
||||||
|
db close
|
||||||
|
sqlite3 db test.db
|
||||||
|
integrity_check tkt2820-$testid.5
|
||||||
|
}
|
||||||
|
|
||||||
|
test_schema_change 1 {
|
||||||
|
CREATE TABLE t1(a);
|
||||||
|
} {
|
||||||
|
DROP TABLE t1
|
||||||
|
} {t1}
|
||||||
|
test_schema_change 2 {
|
||||||
|
CREATE TABLE t1(a);
|
||||||
|
CREATE TABLE t2(b);
|
||||||
|
} {
|
||||||
|
DROP TABLE t2
|
||||||
|
} {t1 t2}
|
||||||
|
test_schema_change 3 {
|
||||||
|
CREATE TABLE t1(a);
|
||||||
|
CREATE INDEX i1 ON t1(a);
|
||||||
|
} {
|
||||||
|
DROP INDEX i1
|
||||||
|
} {i1 t1}
|
||||||
|
|
||||||
|
# We further observe that prior to the fix associated with ticket #2820,
|
||||||
|
# no statement journal would be created on an SQL statement that was run
|
||||||
|
# while a second statement was active, as long as we are in autocommit
|
||||||
|
# mode. This is incorrect.
|
||||||
|
#
|
||||||
|
do_test tkt2820-4.1 {
|
||||||
|
db close
|
||||||
|
file delete -force test.db test.db-journal
|
||||||
|
sqlite3 db test.db
|
||||||
|
db eval {
|
||||||
|
CREATE TABLE t1(a INTEGER PRIMARY KEY);
|
||||||
|
INSERT INTO t1 VALUES(1);
|
||||||
|
INSERT INTO t1 VALUES(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
# The INSERT statement within the loop should fail on a
|
||||||
|
# constraint violation on the second inserted row. This
|
||||||
|
# should cause the entire INSERT to rollback using a statement
|
||||||
|
# journal.
|
||||||
|
#
|
||||||
|
db eval {SELECT name FROM sqlite_master} {
|
||||||
|
catch {db eval {
|
||||||
|
INSERT INTO t1 SELECT a+1 FROM t1 ORDER BY a DESC
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
db eval {SELECT a FROM t1 ORDER BY a}
|
||||||
|
} {1 2}
|
||||||
|
|
||||||
|
finish_test
|
@ -12,7 +12,7 @@
|
|||||||
# of this test is reading and writing to the database from within a
|
# of this test is reading and writing to the database from within a
|
||||||
# virtual table xSync() callback.
|
# virtual table xSync() callback.
|
||||||
#
|
#
|
||||||
# $Id: vtab7.test,v 1.3 2007/10/09 08:29:33 danielk1977 Exp $
|
# $Id: vtab7.test,v 1.4 2007/12/04 16:54:53 drh Exp $
|
||||||
|
|
||||||
set testdir [file dirname $argv0]
|
set testdir [file dirname $argv0]
|
||||||
source $testdir/tester.tcl
|
source $testdir/tester.tcl
|
||||||
@ -114,15 +114,22 @@ do_test vtab7-2.5 {
|
|||||||
} {abc abc2 log newtab}
|
} {abc abc2 log newtab}
|
||||||
|
|
||||||
# Drop a database table from within xSync callback.
|
# Drop a database table from within xSync callback.
|
||||||
|
# This is not allowed. Tables cannot be dropped while
|
||||||
|
# any other statement is active.
|
||||||
|
#
|
||||||
do_test vtab7-2.6 {
|
do_test vtab7-2.6 {
|
||||||
set ::callbacks(xSync,abc) {
|
set ::callbacks(xSync,abc) {
|
||||||
execsql { DROP TABLE newtab }
|
set ::rc [catchsql { DROP TABLE newtab }]
|
||||||
}
|
}
|
||||||
execsql {
|
execsql {
|
||||||
INSERT INTO abc2 VALUES(1, 2, 3);
|
INSERT INTO abc2 VALUES(1, 2, 3);
|
||||||
SELECT name FROM sqlite_master ORDER BY name;
|
SELECT name FROM sqlite_master ORDER BY name;
|
||||||
}
|
}
|
||||||
} {abc abc2 log}
|
} {abc abc2 log newtab}
|
||||||
|
do_test vtab7-2.6.1 {
|
||||||
|
set ::rc
|
||||||
|
} {1 {database table is locked}}
|
||||||
|
execsql {DROP TABLE newtab}
|
||||||
|
|
||||||
# Write to an attached database from xSync().
|
# Write to an attached database from xSync().
|
||||||
ifcapable attach {
|
ifcapable attach {
|
||||||
@ -198,4 +205,3 @@ trace remove variable ::echo_module write echo_module_trace
|
|||||||
unset -nocomplain ::callbacks
|
unset -nocomplain ::callbacks
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user