4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
16 #if defined(SQLITE_TEST)
17 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU)
19 #include "sqlite3rbu.h"
20 #if defined(INCLUDE_SQLITE_TCL_H)
21 # include "sqlite_tcl.h"
24 # ifndef SQLITE_TCLAPI
25 # define SQLITE_TCLAPI
31 typedef struct TestRbu TestRbu
;
39 extern const char *sqlite3ErrName(int);
40 extern int sqlite3TestMakePointerStr(Tcl_Interp
*, char*, void*);
42 void test_rbu_delta(sqlite3_context
*pCtx
, int nArg
, sqlite3_value
**apVal
){
43 Tcl_Interp
*interp
= (Tcl_Interp
*)sqlite3_user_data(pCtx
);
47 pScript
= Tcl_NewObj();
48 Tcl_IncrRefCount(pScript
);
49 Tcl_ListObjAppendElement(0, pScript
, Tcl_NewStringObj("rbu_delta", -1));
50 for(i
=0; i
<nArg
; i
++){
51 sqlite3_value
*pIn
= apVal
[i
];
52 const char *z
= (const char*)sqlite3_value_text(pIn
);
53 Tcl_ListObjAppendElement(0, pScript
, Tcl_NewStringObj(z
, -1));
56 if( TCL_OK
==Tcl_EvalObjEx(interp
, pScript
, TCL_GLOBAL_ONLY
) ){
57 const char *z
= Tcl_GetStringResult(interp
);
58 sqlite3_result_text(pCtx
, z
, -1, SQLITE_TRANSIENT
);
60 Tcl_BackgroundError(interp
);
63 Tcl_DecrRefCount(pScript
);
66 static int xRenameCallback(void *pArg
, const char *zOld
, const char *zNew
){
68 TestRbu
*pTest
= (TestRbu
*)pArg
;
69 Tcl_Obj
*pEval
= Tcl_DuplicateObj(pTest
->xRename
);
71 Tcl_IncrRefCount(pEval
);
72 Tcl_ListObjAppendElement(pTest
->interp
, pEval
, Tcl_NewStringObj(zOld
, -1));
73 Tcl_ListObjAppendElement(pTest
->interp
, pEval
, Tcl_NewStringObj(zNew
, -1));
75 rc
= Tcl_EvalObjEx(pTest
->interp
, pEval
, TCL_GLOBAL_ONLY
);
76 Tcl_DecrRefCount(pEval
);
78 return rc
? SQLITE_IOERR
: SQLITE_OK
;
81 static int SQLITE_TCLAPI
test_sqlite3rbu_cmd(
82 ClientData clientData
,
88 TestRbu
*pTest
= (TestRbu
*)clientData
;
89 sqlite3rbu
*pRbu
= pTest
->pRbu
;
95 {"step", 2, ""}, /* 0 */
96 {"close", 2, ""}, /* 1 */
97 {"create_rbu_delta", 2, ""}, /* 2 */
98 {"savestate", 2, ""}, /* 3 */
99 {"dbMain_eval", 3, "SQL"}, /* 4 */
100 {"bp_progress", 2, ""}, /* 5 */
101 {"db", 3, "RBU"}, /* 6 */
102 {"state", 2, ""}, /* 7 */
103 {"progress", 2, ""}, /* 8 */
104 {"close_no_error", 2, ""}, /* 9 */
105 {"temp_size_limit", 3, "LIMIT"}, /* 10 */
106 {"temp_size", 2, ""}, /* 11 */
107 {"dbRbu_eval", 3, "SQL"}, /* 12 */
108 {"rename_handler", 3, "SCRIPT"},/* 13 */
114 Tcl_WrongNumArgs(interp
, 1, objv
, "METHOD");
117 ret
= Tcl_GetIndexFromObjStruct(
118 interp
, objv
[1], aCmd
, sizeof(aCmd
[0]), "method", 0, &iCmd
120 if( ret
) return TCL_ERROR
;
121 if( objc
!=aCmd
[iCmd
].nArg
){
122 Tcl_WrongNumArgs(interp
, 1, objv
, aCmd
[iCmd
].zUsage
);
128 int rc
= sqlite3rbu_step(pRbu
);
129 Tcl_SetObjResult(interp
, Tcl_NewStringObj(sqlite3ErrName(rc
), -1));
133 case 9: /* close_no_error */
134 case 1: /* close */ {
137 Tcl_DeleteCommand(interp
, Tcl_GetString(objv
[0]));
139 rc
= sqlite3rbu_close(pRbu
, &zErrmsg
);
141 rc
= sqlite3rbu_close(pRbu
, 0);
143 if( rc
==SQLITE_OK
|| rc
==SQLITE_DONE
){
144 Tcl_SetObjResult(interp
, Tcl_NewStringObj(sqlite3ErrName(rc
), -1));
145 assert( zErrmsg
==0 );
147 Tcl_SetObjResult(interp
, Tcl_NewStringObj(sqlite3ErrName(rc
), -1));
149 Tcl_AppendResult(interp
, " - ", zErrmsg
, 0);
150 sqlite3_free(zErrmsg
);
154 if( pTest
->xRename
) Tcl_DecrRefCount(pTest
->xRename
);
159 case 2: /* create_rbu_delta */ {
160 sqlite3
*db
= sqlite3rbu_db(pRbu
, 0);
161 int rc
= sqlite3_create_function(
162 db
, "rbu_delta", -1, SQLITE_UTF8
, (void*)interp
, test_rbu_delta
, 0, 0
164 Tcl_SetObjResult(interp
, Tcl_NewStringObj(sqlite3ErrName(rc
), -1));
165 ret
= (rc
==SQLITE_OK
? TCL_OK
: TCL_ERROR
);
169 case 3: /* savestate */ {
170 int rc
= sqlite3rbu_savestate(pRbu
);
171 Tcl_SetObjResult(interp
, Tcl_NewStringObj(sqlite3ErrName(rc
), -1));
172 ret
= (rc
==SQLITE_OK
? TCL_OK
: TCL_ERROR
);
176 case 12: /* dbRbu_eval */
177 case 4: /* dbMain_eval */ {
178 sqlite3
*db
= sqlite3rbu_db(pRbu
, (iCmd
==12));
179 int rc
= sqlite3_exec(db
, Tcl_GetString(objv
[2]), 0, 0, 0);
181 Tcl_SetObjResult(interp
, Tcl_NewStringObj(sqlite3_errmsg(db
), -1));
187 case 5: /* bp_progress */ {
190 sqlite3rbu_bp_progress(pRbu
, &one
, &two
);
193 Tcl_ListObjAppendElement(interp
, pObj
, Tcl_NewIntObj(one
));
194 Tcl_ListObjAppendElement(interp
, pObj
, Tcl_NewIntObj(two
));
195 Tcl_SetObjResult(interp
, pObj
);
201 if( Tcl_GetBooleanFromObj(interp
, objv
[2], &bArg
) ){
205 sqlite3
*db
= sqlite3rbu_db(pRbu
, bArg
);
206 if( sqlite3TestMakePointerStr(interp
, zBuf
, (void*)db
) ){
209 Tcl_SetResult(interp
, zBuf
, TCL_VOLATILE
);
214 case 7: /* state */ {
215 const char *aRes
[] = { 0, "oal", "move", "checkpoint", "done", "error" };
216 int eState
= sqlite3rbu_state(pRbu
);
217 assert( eState
>0 && eState
<=5 );
218 Tcl_SetResult(interp
, (char*)aRes
[eState
], TCL_STATIC
);
221 case 8: /* progress */ {
222 sqlite3_int64 nStep
= sqlite3rbu_progress(pRbu
);
223 Tcl_SetObjResult(interp
, Tcl_NewWideIntObj(nStep
));
227 case 10: /* temp_size_limit */ {
228 sqlite3_int64 nLimit
;
229 if( Tcl_GetWideIntFromObj(interp
, objv
[2], &nLimit
) ){
232 nLimit
= sqlite3rbu_temp_size_limit(pRbu
, nLimit
);
233 Tcl_SetObjResult(interp
, Tcl_NewWideIntObj(nLimit
));
237 case 11: /* temp_size */ {
238 sqlite3_int64 sz
= sqlite3rbu_temp_size(pRbu
);
239 Tcl_SetObjResult(interp
, Tcl_NewWideIntObj(sz
));
243 case 13: /* rename_handler */ {
244 Tcl_Obj
*pScript
= objv
[2];
245 assert( !sqlite3_stricmp(aCmd
[13].zName
, "rename_handler") );
246 if( Tcl_GetCharLength(pScript
)==0 ){
247 sqlite3rbu_rename_handler(pRbu
, 0, 0);
249 pTest
->xRename
= Tcl_DuplicateObj(pScript
);
250 Tcl_IncrRefCount(pTest
->xRename
);
251 sqlite3rbu_rename_handler(pRbu
, pTest
, xRenameCallback
);
256 default: /* seems unlikely */
257 assert( !"cannot happen" );
264 static void createRbuWrapper(
269 TestRbu
*pTest
= (TestRbu
*)ckalloc(sizeof(TestRbu
));
270 memset(pTest
, 0, sizeof(TestRbu
));
272 pTest
->interp
= interp
;
273 Tcl_CreateObjCommand(interp
, zCmd
, test_sqlite3rbu_cmd
, (ClientData
)pTest
, 0);
277 ** Tclcmd: sqlite3rbu CMD <target-db> <rbu-db> ?<state-db>?
279 static int SQLITE_TCLAPI
test_sqlite3rbu(
280 ClientData clientData
,
283 Tcl_Obj
*CONST objv
[]
285 sqlite3rbu
*pRbu
= 0;
289 const char *zStateDb
= 0;
291 if( objc
!=4 && objc
!=5 ){
292 Tcl_WrongNumArgs(interp
, 1, objv
, "NAME TARGET-DB RBU-DB ?STATE-DB?");
295 zCmd
= Tcl_GetString(objv
[1]);
296 zTarget
= Tcl_GetString(objv
[2]);
297 zRbu
= Tcl_GetString(objv
[3]);
298 if( objc
==5 ) zStateDb
= Tcl_GetString(objv
[4]);
300 pRbu
= sqlite3rbu_open(zTarget
, zRbu
, zStateDb
);
301 createRbuWrapper(interp
, zCmd
, pRbu
);
302 Tcl_SetObjResult(interp
, objv
[1]);
307 ** Tclcmd: sqlite3rbu_vacuum CMD <target-db> <state-db>
309 static int SQLITE_TCLAPI
test_sqlite3rbu_vacuum(
310 ClientData clientData
,
313 Tcl_Obj
*CONST objv
[]
315 sqlite3rbu
*pRbu
= 0;
318 const char *zStateDb
= 0;
320 if( objc
!=3 && objc
!=4 ){
321 Tcl_WrongNumArgs(interp
, 1, objv
, "NAME TARGET-DB ?STATE-DB?");
324 zCmd
= Tcl_GetString(objv
[1]);
325 zTarget
= Tcl_GetString(objv
[2]);
326 if( objc
==4 ) zStateDb
= Tcl_GetString(objv
[3]);
327 if( zStateDb
&& zStateDb
[0]=='\0' ) zStateDb
= 0;
329 pRbu
= sqlite3rbu_vacuum(zTarget
, zStateDb
);
330 createRbuWrapper(interp
, zCmd
, pRbu
);
331 Tcl_SetObjResult(interp
, objv
[1]);
336 ** Tclcmd: sqlite3rbu_create_vfs ?-default? NAME PARENT
338 static int SQLITE_TCLAPI
test_sqlite3rbu_create_vfs(
339 ClientData clientData
,
342 Tcl_Obj
*CONST objv
[]
348 if( objc
!=3 && objc
!=4 ){
349 Tcl_WrongNumArgs(interp
, 1, objv
, "?-default? NAME PARENT");
353 zName
= Tcl_GetString(objv
[objc
-2]);
354 zParent
= Tcl_GetString(objv
[objc
-1]);
355 if( zParent
[0]=='\0' ) zParent
= 0;
357 rc
= sqlite3rbu_create_vfs(zName
, zParent
);
359 Tcl_SetObjResult(interp
, Tcl_NewStringObj(sqlite3ErrName(rc
), -1));
362 sqlite3_vfs
*pVfs
= sqlite3_vfs_find(zName
);
363 sqlite3_vfs_register(pVfs
, 1);
366 Tcl_ResetResult(interp
);
371 ** Tclcmd: sqlite3rbu_destroy_vfs NAME
373 static int SQLITE_TCLAPI
test_sqlite3rbu_destroy_vfs(
374 ClientData clientData
,
377 Tcl_Obj
*CONST objv
[]
382 Tcl_WrongNumArgs(interp
, 1, objv
, "NAME");
386 zName
= Tcl_GetString(objv
[1]);
387 sqlite3rbu_destroy_vfs(zName
);
392 ** Tclcmd: sqlite3rbu_internal_test
394 static int SQLITE_TCLAPI
test_sqlite3rbu_internal_test(
395 ClientData clientData
,
398 Tcl_Obj
*CONST objv
[]
403 Tcl_WrongNumArgs(interp
, 1, objv
, "");
407 db
= sqlite3rbu_db(0, 0);
409 Tcl_AppendResult(interp
, "sqlite3rbu_db(0, 0)!=0", 0);
416 int SqliteRbu_Init(Tcl_Interp
*interp
){
419 Tcl_ObjCmdProc
*xProc
;
421 { "sqlite3rbu", test_sqlite3rbu
},
422 { "sqlite3rbu_vacuum", test_sqlite3rbu_vacuum
},
423 { "sqlite3rbu_create_vfs", test_sqlite3rbu_create_vfs
},
424 { "sqlite3rbu_destroy_vfs", test_sqlite3rbu_destroy_vfs
},
425 { "sqlite3rbu_internal_test", test_sqlite3rbu_internal_test
},
428 for(i
=0; i
<sizeof(aObjCmd
)/sizeof(aObjCmd
[0]); i
++){
429 Tcl_CreateObjCommand(interp
, aObjCmd
[i
].zName
, aObjCmd
[i
].xProc
, 0, 0);
435 #if defined(INCLUDE_SQLITE_TCL_H)
436 # include "sqlite_tcl.h"
440 int SqliteRbu_Init(Tcl_Interp
*interp
){ return TCL_OK
; }
441 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) */
442 #endif /* defined(SQLITE_TEST) */