1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-04 04:42:17 +03:00

Test case for writing to a WITHOUT ROWID virtual table. The TCLVAR virtual

table is modified to add a "fullname" column which is the primary key, and
to accept update operations against the primary key.

FossilOrigin-Name: 6997e00c3221f266f4d9187501d8a9e5bafb85551e88a744cdc8ffe3b75ec2a4
This commit is contained in:
drh
2017-08-10 17:53:11 +00:00
parent e3740f272b
commit 4dd176eaab
7 changed files with 207 additions and 19 deletions

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 */