Allow WITHOUT ROWID virtual tables to be writable as long as they have

exactly one column as their PRIMARY KEY.

FossilOrigin-Name: c601d128ff1f1dd6d221ee9f55595a95b58ba07d043e1d530743ea913731560e
This commit is contained in:
drh 2017-08-10 20:43:07 +00:00
commit 21f6b626f5
11 changed files with 301 additions and 32 deletions

View File

@ -1,5 +1,5 @@
C Add\sthe\s"instance"\stype\sto\sthe\sfts5vocab\svirtual\stable\smodule.\sFor\sdirect\naccess\sto\sthe\scontents\sof\sthe\sfts5\sterm\sindex.
D 2017-08-10T20:36:56.419
C Allow\sWITHOUT\sROWID\svirtual\stables\sto\sbe\swritable\sas\slong\sas\sthey\shave\nexactly\sone\scolumn\sas\stheir\sPRIMARY\sKEY.
D 2017-08-10T20:43:07.509
F Makefile.in d9873c9925917cca9990ee24be17eb9613a668012c85a343aef7e5536ae266e8
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 02b469e9dcd5b7ee63fc1fb05babc174260ee4cfa4e0ef2e48c3c6801567a016
@ -405,7 +405,7 @@ F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
F src/delete.c 939bd15e6b54b82b951e1c0ffc2ff2b4ab579196780a1f6d394e47bd6f799b6c
F src/delete.c 21a5f1812fdb599e9f7afb9f650bdabab60a3afd51d7e94e539c982f647b0023
F src/expr.c fdb2fc465cabbf372fecad1fc2b291758bec74150b4db0fb945332e09df28a0e
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 5ff2c895fe087756d8085dc1a9bc229b5670e2a65c3929dd87c71e43649af333
@ -506,7 +506,7 @@ F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe
F src/test_sqllog.c 11e6ce7575f489155c604ac4b439f2ac1d3d5aef
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
F src/test_tclvar.c df9fe1213c2634687a9ca0b0bec0d2119d359ae3
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
F src/test_vfs.c f0186261a24de2671d080bcd8050732f0cb64f6e
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
@ -517,7 +517,7 @@ F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
F src/treeview.c 2ee4a5dada213d5ab08a742af5c876cee6f1aaae65f10a61923f3fb63846afef
F src/trigger.c 48e0f7ed6749ce4d50a695e09e20ce9cf84ecabf2691852c965a51e0b620eccc
F src/update.c c443935c652af9365e033f756550b5032d02e1b06eb2cb890ed7511ae0c051dc
F src/update.c 5404be9e840717323a69209190cdbc9d0d34adaedaaf1d1a1069babf2c4171c0
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
F src/util.c fc081ec6f63448dcd80d3dfad35baecfa104823254a815b081a4d9fe76e1db23
F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
@ -530,7 +530,7 @@ F src/vdbeblob.c db3cf91060f6f4b2f1358a4200e844697990752177784c7c95da00b7ac9f1c7
F src/vdbemem.c b7fac20534c79b7554dab2e8a180c585a8bc1b9c85149d1b2d9746cf314d06ed
F src/vdbesort.c fea2bea25f5e9ccd91e0760d7359f0365f9fba1aaeac7216c71cad78765f58e3
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
F src/vtab.c 45d2aab3374d53f6d24490fe14a5c531c34f78d6fd8579ef90548a0f2d9642ab
F src/vtab.c f1d5c23132fb0247af3e86146404112283ddedb6c518de0d4edc91cfb36970ef
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344
F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
@ -695,7 +695,7 @@ F test/crashM.test d95f59046fa749b0d0822edf18a717788c8f318d
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/createtab.test b5de160630b209c4b8925bdcbbaf48cc90b67fe8
F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
F test/csv01.test e0ba3caaa57e4c667a0b45977689fb8082f14348
F test/csv01.test 526fc6aefd052badd5a0283f86b4b395c3df76bfe98d96c801f494f5e2c7836c
F test/ctime.test 78749e6c9a5f0010d67985be80788f841e3cd2da18114e2ed6010399a7d807f3
F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
F test/cursorhint2.test 8457e93d97f665f23f97cdbc8477d16e3480331b
@ -1462,7 +1462,7 @@ F test/varint.test ab7b110089a08b9926ed7390e7e97bdefeb74102
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
F test/view.test 765802c7a66d37fabd5ac8e2f2dbe572b43eb9ab
F test/vtab1.test 8f91b9538d1404c3932293a588c4344218a0c94792d4289bb55e41020e7b3fff
F test/vtab2.test f8cd1bb9aba7143eba97812d9617880a36d247ad
F test/vtab2.test 14d4ab26cee13ba6cf5c5601b158e4f57552d3b055cdd9406cf7f711e9c84082
F test/vtab3.test b45f47d20f225ccc9c28dc915d92740c2dee311e
F test/vtab4.test 8e73ed268f3d596bc3590f45fc948fb40f28e9c3
F test/vtab5.test 889f444970393c73f1e077e2bdc5d845e157a391
@ -1474,10 +1474,11 @@ F test/vtabA.test 1317f06a03597eee29f40a49b6c21e1aaba4285f
F test/vtabB.test 04df5dc531b9f44d9ca65b9c1b79f12b5922a796
F test/vtabC.test 4528f459a13136f982e75614d120aef165f17292
F test/vtabD.test 05b3f1d77117271671089e48719524b676842e96
F test/vtabE.test d5024aa42754962f6bb0afd261681686488e7afe
F test/vtabE.test 2a143fe75a11275781d1fd1988d86b66a3f69cb98f4add62e3da8fd0f637b45f
F test/vtabF.test 1918844c7c902f6a16c8dacf1ec8f84886d6e78b
F test/vtabH.test 26d54e8b5407f797638b787a55f9c88323850a58dd142de02d06b9a1159bd283
F test/vtabH.test 3cf9aa1c1c4381b3b3ac33f933376f06fbb99d2294a83c79b7562d3ed87be450
F test/vtabI.test 751b07636700dbdea328e4265b6077ccd6811a3f
F test/vtabJ.test d7b73675708cf63cfcb9d443bb451fc01a028347275b7311e51f9fdf3ca6757f
F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c3784c6783
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
@ -1645,7 +1646,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P e49279e65169a939b6058a0960dc1fe09ce4ee2d78992a1969773cbc7ce1043b
R 51c4219f1ac2413928699169835fef62
U dan
Z c67de475a6759cd5bb3ba77ac9b27176
P 34a7bd7121a478e14982d59be95ad891fab8050ad5e006638f826c57c392b93e f38ff718278c8ff477d1c6379ced32167063de15f0666c8eac2e4dd30cbd975c
R 2bbcd61e6b49ae99642d400578e0c457
T +closed f38ff718278c8ff477d1c6379ced32167063de15f0666c8eac2e4dd30cbd975c
U drh
Z 8e6962897e49436cc593ee413e7d03cc

View File

@ -1 +1 @@
34a7bd7121a478e14982d59be95ad891fab8050ad5e006638f826c57c392b93e
c601d128ff1f1dd6d221ee9f55595a95b58ba07d043e1d530743ea913731560e

View File

@ -502,7 +502,11 @@ void sqlite3DeleteFrom(
}
}else if( pPk ){
addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur); VdbeCoverage(v);
sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
if( IsVirtual(pTab) ){
sqlite3VdbeAddOp3(v, OP_Column, iEphCur, 0, iKey);
}else{
sqlite3VdbeAddOp2(v, OP_RowData, iEphCur, iKey);
}
assert( nKey==0 ); /* OP_Found will use a composite key */
}else{
addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);

View File

@ -15,6 +15,25 @@
**
** The emphasis of this file is a virtual table that provides
** access to TCL variables.
**
** The TCLVAR eponymous virtual table has a schema like this:
**
** CREATE TABLE tclvar(
** name TEXT, -- base name of the variable: "x" in "$x(y)"
** arrayname TEXT, -- array index name: "y" in "$x(y)"
** value TEXT, -- the value of the variable
** fullname TEXT, -- the full name of the variable
** PRIMARY KEY(fullname)
** ) WITHOUT ROWID;
**
** DELETE, INSERT, and UPDATE operations use the "fullname" field to
** determine the variable to be modified. Changing "value" to NULL
** deletes the variable.
**
** For SELECT operations, the "name" and "arrayname" fields will always
** match the "fullname" field. For DELETE, INSERT, and UPDATE, the
** "name" and "arrayname" fields are ignored and the variable is modified
** according to "fullname" and "value" only.
*/
#include "sqliteInt.h"
#if defined(INCLUDE_SQLITE_TCL_H)
@ -67,7 +86,12 @@ static int tclvarConnect(
){
tclvar_vtab *pVtab;
static const char zSchema[] =
"CREATE TABLE whatever(name TEXT, arrayname TEXT, value TEXT)";
"CREATE TABLE x("
" name TEXT," /* Base name */
" arrayname TEXT," /* Array index */
" value TEXT," /* Value */
" fullname TEXT PRIMARY KEY" /* base(index) name */
") WITHOUT ROWID";
pVtab = sqlite3MallocZero( sizeof(*pVtab) );
if( pVtab==0 ) return SQLITE_NOMEM;
*ppVtab = &pVtab->base;
@ -251,6 +275,16 @@ static int tclvarColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
sqlite3_result_text(ctx, Tcl_GetString(pVal), -1, SQLITE_TRANSIENT);
break;
}
case 3: {
char *z3;
if( p2 ){
z3 = sqlite3_mprintf("%s(%s)", z1, z2);
sqlite3_result_text(ctx, z3, -1, sqlite3_free);
}else{
sqlite3_result_text(ctx, z1, -1, SQLITE_TRANSIENT);
}
break;
}
}
return SQLITE_OK;
}
@ -376,6 +410,58 @@ static int tclvarBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
return SQLITE_OK;
}
/*
** Invoked for any UPDATE, INSERT, or DELETE against a tclvar table
*/
static int tclvarUpdate(
sqlite3_vtab *tab,
int argc,
sqlite3_value **argv,
sqlite_int64 *pRowid
){
tclvar_vtab *pTab = (tclvar_vtab*)tab;
if( argc==1 ){
/* A DELETE operation. The variable to be deleted is stored in argv[0] */
const char *zVar = (const char*)sqlite3_value_text(argv[0]);
Tcl_UnsetVar(pTab->interp, zVar, TCL_GLOBAL_ONLY);
return SQLITE_OK;
}
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
/* An INSERT operation */
const char *zValue = (const char*)sqlite3_value_text(argv[4]);
const char *zName;
if( sqlite3_value_type(argv[5])!=SQLITE_TEXT ){
tab->zErrMsg = sqlite3_mprintf("the 'fullname' column must be TEXT");
return SQLITE_ERROR;
}
zName = (const char*)sqlite3_value_text(argv[5]);
if( zValue ){
Tcl_SetVar(pTab->interp, zName, zValue, TCL_GLOBAL_ONLY);
}else{
Tcl_UnsetVar(pTab->interp, zName, TCL_GLOBAL_ONLY);
}
return SQLITE_OK;
}
if( sqlite3_value_type(argv[0])==SQLITE_TEXT
&& sqlite3_value_type(argv[1])==SQLITE_TEXT
){
/* An UPDATE operation */
const char *zOldName = (const char*)sqlite3_value_text(argv[0]);
const char *zNewName = (const char*)sqlite3_value_text(argv[1]);
const char *zValue = (const char*)sqlite3_value_text(argv[4]);
if( strcmp(zOldName, zNewName)!=0 || zValue==0 ){
Tcl_UnsetVar(pTab->interp, zOldName, TCL_GLOBAL_ONLY);
}
if( zValue!=0 ){
Tcl_SetVar(pTab->interp, zNewName, zValue, TCL_GLOBAL_ONLY);
}
return SQLITE_OK;
}
tab->zErrMsg = sqlite3_mprintf("prohibited TCL variable change");
return SQLITE_ERROR;
}
/*
** A virtual table module that provides read-only access to a
** Tcl global variable namespace.
@ -394,7 +480,7 @@ static sqlite3_module tclvarModule = {
tclvarEof, /* xEof - check for end of scan */
tclvarColumn, /* xColumn - read data */
tclvarRowid, /* xRowid - read data */
0, /* xUpdate */
tclvarUpdate, /* xUpdate */
0, /* xBegin */
0, /* xSync */
0, /* xCommit */

View File

@ -803,12 +803,6 @@ static void updateVirtualTable(
if( pWInfo==0 ) return;
/* Populate the argument registers. */
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
if( pRowid ){
sqlite3ExprCode(pParse, pRowid, regArg+1);
}else{
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
}
for(i=0; i<pTab->nCol; i++){
if( aXRef[i]>=0 ){
sqlite3ExprCode(pParse, pChanges->a[aXRef[i]].pExpr, regArg+2+i);
@ -816,6 +810,23 @@ static void updateVirtualTable(
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, i, regArg+2+i);
}
}
if( HasRowid(pTab) ){
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg);
if( pRowid ){
sqlite3ExprCode(pParse, pRowid, regArg+1);
}else{
sqlite3VdbeAddOp2(v, OP_Rowid, iCsr, regArg+1);
}
}else{
Index *pPk; /* PRIMARY KEY index */
i16 iPk; /* PRIMARY KEY column */
pPk = sqlite3PrimaryKeyIndex(pTab);
assert( pPk!=0 );
assert( pPk->nKeyCol==1 );
iPk = pPk->aiColumn[0];
sqlite3VdbeAddOp3(v, OP_VColumn, iCsr, iPk, regArg);
sqlite3VdbeAddOp2(v, OP_SCopy, regArg+2+iPk, regArg+1);
}
bOnePass = sqlite3WhereOkOnePass(pWInfo, aDummy);

View File

@ -773,7 +773,13 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
pNew->nCol = 0;
pNew->aCol = 0;
assert( pTab->pIndex==0 );
if( !HasRowid(pNew) && pCtx->pVTable->pMod->pModule->xUpdate!=0 ){
assert( HasRowid(pNew) || sqlite3PrimaryKeyIndex(pNew)!=0 );
if( !HasRowid(pNew)
&& pCtx->pVTable->pMod->pModule->xUpdate!=0
&& sqlite3PrimaryKeyIndex(pNew)->nKeyCol!=1
){
/* WITHOUT ROWID virtual tables must either be read-only (xUpdate==0)
** or else must have a single-column PRIMARY KEY */
rc = SQLITE_ERROR;
}
pIdx = pNew->pIndex;

View File

@ -93,6 +93,7 @@ do_catchsql_test 3.2 {
SELECT rowid, a FROM t3;
} {1 {no such column: rowid}}
# Multi-column WITHOUT ROWID virtual tables may not be writable.
do_catchsql_test 4.0 {
DROP TABLE t3;
CREATE VIRTUAL TABLE temp.t4 USING csv_wr(
@ -100,13 +101,44 @@ do_catchsql_test 4.0 {
'1,2,3,4
5,6,7,8
9,10,11,12
13,14,15,16
',
13,14,15,16',
columns=4,
schema=
'CREATE TABLE t3(a PRIMARY KEY,b TEXT,c TEXT,d TEXT) WITHOUT ROWID',
'CREATE TABLE t3(a,b,c,d,PRIMARY KEY(a,b)) WITHOUT ROWID',
testflags=1
);
} {1 {vtable constructor failed: t4}}
# WITHOUT ROWID tables with a single-column PRIMARY KEY may be writable.
do_catchsql_test 4.1 {
DROP TABLE IF EXISTS t4;
CREATE VIRTUAL TABLE temp.t4 USING csv_wr(
data=
'1,2,3,4
5,6,7,8
9,10,11,12
13,14,15,16',
columns=4,
schema=
'CREATE TABLE t3(a,b,c,d,PRIMARY KEY(b)) WITHOUT ROWID',
testflags=1
);
} {0 {}}
do_catchsql_test 4.2 {
DROP TABLE IF EXISTS t5;
CREATE VIRTUAL TABLE temp.t5 USING csv_wr(
data=
'1,2,3,4
5,6,7,8
9,10,11,12
13,14,15,16',
columns=4,
schema=
'CREATE TABLE t3(a,b,c,d) WITHOUT ROWID',
testflags=1
);
} {1 {vtable constructor failed: t5}}
finish_test

View File

@ -60,7 +60,7 @@ do_test vtab2-2.1 {
set ::abc 123
execsql {
CREATE VIRTUAL TABLE vars USING tclvar;
SELECT * FROM vars WHERE name='abc';
SELECT name, arrayname, value FROM vars WHERE name='abc';
}
} [list abc "" 123]
do_test vtab2-2.2 {
@ -68,7 +68,7 @@ do_test vtab2-2.2 {
set A(2) 4
set A(3) 9
execsql {
SELECT * FROM vars WHERE name='A';
SELECT name, arrayname, value FROM vars WHERE name='A';
}
} [list A 1 1 A 2 4 A 3 9]
unset -nocomplain result

View File

@ -39,7 +39,9 @@ do_test vtabE-1 {
CREATE VIRTUAL TABLE t1 USING tclvar;
CREATE VIRTUAL TABLE t2 USING tclvar;
CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
SELECT t1.*, t2.*, abs(t3.b + abs(t2.value + abs(t1.value)))
SELECT t1.name, t1.arrayname, t1.value,
t2.name, t2.arrayname, t2.value,
abs(t3.b + abs(t2.value + abs(t1.value)))
FROM t1 LEFT JOIN t2 ON t2.name = t1.arrayname
LEFT JOIN t3 ON t3.a=t2.value
WHERE t1.name = 'vtabE'

View File

@ -55,7 +55,7 @@ register_tclvar_module db
set ::xyz 10
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE vars USING tclvar;
SELECT * FROM vars WHERE name = 'xyz';
SELECT name, arrayname, value FROM vars WHERE name = 'xyz';
} {xyz {} 10}
set x1 aback

126
test/vtabJ.test Normal file
View File

@ -0,0 +1,126 @@
# 2017-08-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 tests of writing to WITHOUT ROWID virtual tables
# using the tclvar eponymous virtual table.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix vtabJ
ifcapable !vtab {
finish_test
return
}
register_tclvar_module db
unset -nocomplain vtabJ
do_test 100 {
set vtabJ(1) this
set vtabJ(two) is
set vtabJ(3) {a test}
db eval {
SELECT fullname, value FROM tclvar WHERE name='vtabJ' ORDER BY fullname;
}
} {vtabJ(1) this vtabJ(3) {a test} vtabJ(two) is}
do_execsql_test 110 {
INSERT INTO tclvar(fullname, value)
VALUES('vtabJ(4)',4),('vtabJ(five)',555);
SELECT fullname, value FROM tclvar WHERE name='vtabJ' ORDER BY fullname;
} {vtabJ(1) this vtabJ(3) {a test} vtabJ(4) 4 vtabJ(five) 555 vtabJ(two) is}
do_test 111 {
set res {}
foreach vname [lsort [array names vtabJ]] {
lappend res vtabJ($vname) $vtabJ($vname)
}
set res
} {vtabJ(1) this vtabJ(3) {a test} vtabJ(4) 4 vtabJ(five) 555 vtabJ(two) is}
do_test 120 {
db eval {
INSERT INTO tclvar(fullname, value) VALUES('vtabJ(4)',444);
}
set vtabJ(4)
} {444}
do_test 130 {
db eval {
INSERT INTO tclvar(fullname, value) VALUES('vtabJ(4)',NULL);
}
info exists vtabJ(4)
} {0}
do_test 140 {
db eval {
UPDATE tclvar SET value=55 WHERE fullname='vtabJ(five)';
}
set vtabJ(five)
} {55}
do_test 150 {
db eval {
UPDATE tclvar SET fullname='vtabJ(5)' WHERE fullname='vtabJ(five)';
}
set vtabJ(5)
} {55}
do_test 151 {
info exists vtabJ(five)
} {0}
do_test 152 {
set res {}
foreach vname [lsort [array names vtabJ]] {
lappend res vtabJ($vname) $vtabJ($vname)
}
set res
} {vtabJ(1) this vtabJ(3) {a test} vtabJ(5) 55 vtabJ(two) is}
do_execsql_test 160 {
SELECT fullname FROM tclvar WHERE arrayname='two'
} {vtabJ(two)}
do_execsql_test 161 {
DELETE FROM tclvar WHERE arrayname='two';
SELECT fullname, value FROM tclvar WHERE name='vtabJ' ORDER BY fullname;
} {vtabJ(1) this vtabJ(3) {a test} vtabJ(5) 55}
do_test 162 {
set res {}
foreach vname [lsort [array names vtabJ]] {
lappend res vtabJ($vname) $vtabJ($vname)
}
set res
} {vtabJ(1) this vtabJ(3) {a test} vtabJ(5) 55}
# Try to trick the module into updating the same variable twice for a
# single UPDATE statement.
#
do_execsql_test 171 {
INSERT INTO tclvar(fullname, value) VALUES('xx', 'a');
SELECT name, value FROM tclvar where name = 'xx';
} {xx a}
do_execsql_test 172 {
UPDATE tclvar SET value = value || 't'
WHERE name = 'xx' OR name = 'x'||'x';
SELECT name, value FROM tclvar where name = 'xx';
} {xx at}
do_execsql_test 173 {
UPDATE tclvar SET value = value || 't'
WHERE name = 'xx' OR name BETWEEN 'xx' AND 'xx';
SELECT name, value FROM tclvar where name = 'xx';
} {xx att}
do_execsql_test 181 {
DELETE FROM tclvar WHERE name BETWEEN 'xx' AND 'xx' OR name='xx';
SELECT name, value FROM tclvar where name = 'xx';
} {}
finish_test