OLD | NEW |
(Empty) | |
| 1 /* |
| 2 ** 2015 February 16 |
| 3 ** |
| 4 ** The author disclaims copyright to this source code. In place of |
| 5 ** a legal notice, here is a blessing: |
| 6 ** |
| 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. |
| 10 ** |
| 11 ************************************************************************* |
| 12 */ |
| 13 |
| 14 #include "sqlite3.h" |
| 15 |
| 16 #if defined(SQLITE_TEST) |
| 17 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) |
| 18 |
| 19 #include "sqlite3rbu.h" |
| 20 #if defined(INCLUDE_SQLITE_TCL_H) |
| 21 # include "sqlite_tcl.h" |
| 22 #else |
| 23 # include "tcl.h" |
| 24 # ifndef SQLITE_TCLAPI |
| 25 # define SQLITE_TCLAPI |
| 26 # endif |
| 27 #endif |
| 28 #include <assert.h> |
| 29 |
| 30 /* From main.c */ |
| 31 extern const char *sqlite3ErrName(int); |
| 32 extern int sqlite3TestMakePointerStr(Tcl_Interp*, char*, void*); |
| 33 |
| 34 void test_rbu_delta(sqlite3_context *pCtx, int nArg, sqlite3_value **apVal){ |
| 35 Tcl_Interp *interp = (Tcl_Interp*)sqlite3_user_data(pCtx); |
| 36 Tcl_Obj *pScript; |
| 37 int i; |
| 38 |
| 39 pScript = Tcl_NewObj(); |
| 40 Tcl_IncrRefCount(pScript); |
| 41 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj("rbu_delta", -1)); |
| 42 for(i=0; i<nArg; i++){ |
| 43 sqlite3_value *pIn = apVal[i]; |
| 44 const char *z = (const char*)sqlite3_value_text(pIn); |
| 45 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(z, -1)); |
| 46 } |
| 47 |
| 48 if( TCL_OK==Tcl_EvalObjEx(interp, pScript, TCL_GLOBAL_ONLY) ){ |
| 49 const char *z = Tcl_GetStringResult(interp); |
| 50 sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); |
| 51 }else{ |
| 52 Tcl_BackgroundError(interp); |
| 53 } |
| 54 |
| 55 Tcl_DecrRefCount(pScript); |
| 56 } |
| 57 |
| 58 |
| 59 static int SQLITE_TCLAPI test_sqlite3rbu_cmd( |
| 60 ClientData clientData, |
| 61 Tcl_Interp *interp, |
| 62 int objc, |
| 63 Tcl_Obj *CONST objv[] |
| 64 ){ |
| 65 int ret = TCL_OK; |
| 66 sqlite3rbu *pRbu = (sqlite3rbu*)clientData; |
| 67 struct RbuCmd { |
| 68 const char *zName; |
| 69 int nArg; |
| 70 const char *zUsage; |
| 71 } aCmd[] = { |
| 72 {"step", 2, ""}, /* 0 */ |
| 73 {"close", 2, ""}, /* 1 */ |
| 74 {"create_rbu_delta", 2, ""}, /* 2 */ |
| 75 {"savestate", 2, ""}, /* 3 */ |
| 76 {"dbMain_eval", 3, "SQL"}, /* 4 */ |
| 77 {"bp_progress", 2, ""}, /* 5 */ |
| 78 {"db", 3, "RBU"}, /* 6 */ |
| 79 {"state", 2, ""}, /* 7 */ |
| 80 {"progress", 2, ""}, /* 8 */ |
| 81 {0,0,0} |
| 82 }; |
| 83 int iCmd; |
| 84 |
| 85 if( objc<2 ){ |
| 86 Tcl_WrongNumArgs(interp, 1, objv, "METHOD"); |
| 87 return TCL_ERROR; |
| 88 } |
| 89 ret = Tcl_GetIndexFromObjStruct( |
| 90 interp, objv[1], aCmd, sizeof(aCmd[0]), "method", 0, &iCmd |
| 91 ); |
| 92 if( ret ) return TCL_ERROR; |
| 93 if( objc!=aCmd[iCmd].nArg ){ |
| 94 Tcl_WrongNumArgs(interp, 1, objv, aCmd[iCmd].zUsage); |
| 95 return TCL_ERROR; |
| 96 } |
| 97 |
| 98 switch( iCmd ){ |
| 99 case 0: /* step */ { |
| 100 int rc = sqlite3rbu_step(pRbu); |
| 101 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 102 break; |
| 103 } |
| 104 |
| 105 case 1: /* close */ { |
| 106 char *zErrmsg = 0; |
| 107 int rc; |
| 108 Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); |
| 109 rc = sqlite3rbu_close(pRbu, &zErrmsg); |
| 110 if( rc==SQLITE_OK || rc==SQLITE_DONE ){ |
| 111 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 112 assert( zErrmsg==0 ); |
| 113 }else{ |
| 114 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 115 if( zErrmsg ){ |
| 116 Tcl_AppendResult(interp, " - ", zErrmsg, 0); |
| 117 sqlite3_free(zErrmsg); |
| 118 } |
| 119 ret = TCL_ERROR; |
| 120 } |
| 121 break; |
| 122 } |
| 123 |
| 124 case 2: /* create_rbu_delta */ { |
| 125 sqlite3 *db = sqlite3rbu_db(pRbu, 0); |
| 126 int rc = sqlite3_create_function( |
| 127 db, "rbu_delta", -1, SQLITE_UTF8, (void*)interp, test_rbu_delta, 0, 0 |
| 128 ); |
| 129 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 130 ret = (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); |
| 131 break; |
| 132 } |
| 133 |
| 134 case 3: /* savestate */ { |
| 135 int rc = sqlite3rbu_savestate(pRbu); |
| 136 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 137 ret = (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); |
| 138 break; |
| 139 } |
| 140 |
| 141 case 4: /* dbMain_eval */ { |
| 142 sqlite3 *db = sqlite3rbu_db(pRbu, 0); |
| 143 int rc = sqlite3_exec(db, Tcl_GetString(objv[2]), 0, 0, 0); |
| 144 if( rc!=SQLITE_OK ){ |
| 145 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(db), -1)); |
| 146 ret = TCL_ERROR; |
| 147 } |
| 148 break; |
| 149 } |
| 150 |
| 151 case 5: /* bp_progress */ { |
| 152 int one, two; |
| 153 Tcl_Obj *pObj; |
| 154 sqlite3rbu_bp_progress(pRbu, &one, &two); |
| 155 |
| 156 pObj = Tcl_NewObj(); |
| 157 Tcl_ListObjAppendElement(interp, pObj, Tcl_NewIntObj(one)); |
| 158 Tcl_ListObjAppendElement(interp, pObj, Tcl_NewIntObj(two)); |
| 159 Tcl_SetObjResult(interp, pObj); |
| 160 break; |
| 161 } |
| 162 |
| 163 case 6: /* db */ { |
| 164 int bArg; |
| 165 if( Tcl_GetBooleanFromObj(interp, objv[2], &bArg) ){ |
| 166 ret = TCL_ERROR; |
| 167 }else{ |
| 168 char zBuf[50]; |
| 169 sqlite3 *db = sqlite3rbu_db(pRbu, bArg); |
| 170 if( sqlite3TestMakePointerStr(interp, zBuf, (void*)db) ){ |
| 171 ret = TCL_ERROR; |
| 172 }else{ |
| 173 Tcl_SetResult(interp, zBuf, TCL_VOLATILE); |
| 174 } |
| 175 } |
| 176 break; |
| 177 } |
| 178 case 7: /* state */ { |
| 179 const char *aRes[] = { 0, "oal", "move", "checkpoint", "done", "error" }; |
| 180 int eState = sqlite3rbu_state(pRbu); |
| 181 assert( eState>0 && eState<=5 ); |
| 182 Tcl_SetResult(interp, (char*)aRes[eState], TCL_STATIC); |
| 183 break; |
| 184 } |
| 185 case 8: /* progress */ { |
| 186 sqlite3_int64 nStep = sqlite3rbu_progress(pRbu); |
| 187 Tcl_SetObjResult(interp, Tcl_NewWideIntObj(nStep)); |
| 188 break; |
| 189 } |
| 190 |
| 191 default: /* seems unlikely */ |
| 192 assert( !"cannot happen" ); |
| 193 break; |
| 194 } |
| 195 |
| 196 return ret; |
| 197 } |
| 198 |
| 199 /* |
| 200 ** Tclcmd: sqlite3rbu CMD <target-db> <rbu-db> ?<state-db>? |
| 201 */ |
| 202 static int SQLITE_TCLAPI test_sqlite3rbu( |
| 203 ClientData clientData, |
| 204 Tcl_Interp *interp, |
| 205 int objc, |
| 206 Tcl_Obj *CONST objv[] |
| 207 ){ |
| 208 sqlite3rbu *pRbu = 0; |
| 209 const char *zCmd; |
| 210 const char *zTarget; |
| 211 const char *zRbu; |
| 212 const char *zStateDb = 0; |
| 213 |
| 214 if( objc!=4 && objc!=5 ){ |
| 215 Tcl_WrongNumArgs(interp, 1, objv, "NAME TARGET-DB RBU-DB ?STATE-DB?"); |
| 216 return TCL_ERROR; |
| 217 } |
| 218 zCmd = Tcl_GetString(objv[1]); |
| 219 zTarget = Tcl_GetString(objv[2]); |
| 220 zRbu = Tcl_GetString(objv[3]); |
| 221 if( objc==5 ) zStateDb = Tcl_GetString(objv[4]); |
| 222 |
| 223 pRbu = sqlite3rbu_open(zTarget, zRbu, zStateDb); |
| 224 Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0); |
| 225 Tcl_SetObjResult(interp, objv[1]); |
| 226 return TCL_OK; |
| 227 } |
| 228 |
| 229 /* |
| 230 ** Tclcmd: sqlite3rbu_vacuum CMD <target-db> <state-db> |
| 231 */ |
| 232 static int SQLITE_TCLAPI test_sqlite3rbu_vacuum( |
| 233 ClientData clientData, |
| 234 Tcl_Interp *interp, |
| 235 int objc, |
| 236 Tcl_Obj *CONST objv[] |
| 237 ){ |
| 238 sqlite3rbu *pRbu = 0; |
| 239 const char *zCmd; |
| 240 const char *zTarget; |
| 241 const char *zStateDb = 0; |
| 242 |
| 243 if( objc!=3 && objc!=4 ){ |
| 244 Tcl_WrongNumArgs(interp, 1, objv, "NAME TARGET-DB ?STATE-DB?"); |
| 245 return TCL_ERROR; |
| 246 } |
| 247 zCmd = Tcl_GetString(objv[1]); |
| 248 zTarget = Tcl_GetString(objv[2]); |
| 249 if( objc==4 ) zStateDb = Tcl_GetString(objv[3]); |
| 250 |
| 251 pRbu = sqlite3rbu_vacuum(zTarget, zStateDb); |
| 252 Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0); |
| 253 Tcl_SetObjResult(interp, objv[1]); |
| 254 return TCL_OK; |
| 255 } |
| 256 |
| 257 /* |
| 258 ** Tclcmd: sqlite3rbu_create_vfs ?-default? NAME PARENT |
| 259 */ |
| 260 static int SQLITE_TCLAPI test_sqlite3rbu_create_vfs( |
| 261 ClientData clientData, |
| 262 Tcl_Interp *interp, |
| 263 int objc, |
| 264 Tcl_Obj *CONST objv[] |
| 265 ){ |
| 266 const char *zName; |
| 267 const char *zParent; |
| 268 int rc; |
| 269 |
| 270 if( objc!=3 && objc!=4 ){ |
| 271 Tcl_WrongNumArgs(interp, 1, objv, "?-default? NAME PARENT"); |
| 272 return TCL_ERROR; |
| 273 } |
| 274 |
| 275 zName = Tcl_GetString(objv[objc-2]); |
| 276 zParent = Tcl_GetString(objv[objc-1]); |
| 277 if( zParent[0]=='\0' ) zParent = 0; |
| 278 |
| 279 rc = sqlite3rbu_create_vfs(zName, zParent); |
| 280 if( rc!=SQLITE_OK ){ |
| 281 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 282 return TCL_ERROR; |
| 283 }else if( objc==4 ){ |
| 284 sqlite3_vfs *pVfs = sqlite3_vfs_find(zName); |
| 285 sqlite3_vfs_register(pVfs, 1); |
| 286 } |
| 287 |
| 288 Tcl_ResetResult(interp); |
| 289 return TCL_OK; |
| 290 } |
| 291 |
| 292 /* |
| 293 ** Tclcmd: sqlite3rbu_destroy_vfs NAME |
| 294 */ |
| 295 static int SQLITE_TCLAPI test_sqlite3rbu_destroy_vfs( |
| 296 ClientData clientData, |
| 297 Tcl_Interp *interp, |
| 298 int objc, |
| 299 Tcl_Obj *CONST objv[] |
| 300 ){ |
| 301 const char *zName; |
| 302 |
| 303 if( objc!=2 ){ |
| 304 Tcl_WrongNumArgs(interp, 1, objv, "NAME"); |
| 305 return TCL_ERROR; |
| 306 } |
| 307 |
| 308 zName = Tcl_GetString(objv[1]); |
| 309 sqlite3rbu_destroy_vfs(zName); |
| 310 return TCL_OK; |
| 311 } |
| 312 |
| 313 /* |
| 314 ** Tclcmd: sqlite3rbu_internal_test |
| 315 */ |
| 316 static int SQLITE_TCLAPI test_sqlite3rbu_internal_test( |
| 317 ClientData clientData, |
| 318 Tcl_Interp *interp, |
| 319 int objc, |
| 320 Tcl_Obj *CONST objv[] |
| 321 ){ |
| 322 sqlite3 *db; |
| 323 |
| 324 if( objc!=1 ){ |
| 325 Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 326 return TCL_ERROR; |
| 327 } |
| 328 |
| 329 db = sqlite3rbu_db(0, 0); |
| 330 if( db!=0 ){ |
| 331 Tcl_AppendResult(interp, "sqlite3rbu_db(0, 0)!=0", 0); |
| 332 return TCL_ERROR; |
| 333 } |
| 334 |
| 335 return TCL_OK; |
| 336 } |
| 337 |
| 338 int SqliteRbu_Init(Tcl_Interp *interp){ |
| 339 static struct { |
| 340 char *zName; |
| 341 Tcl_ObjCmdProc *xProc; |
| 342 } aObjCmd[] = { |
| 343 { "sqlite3rbu", test_sqlite3rbu }, |
| 344 { "sqlite3rbu_vacuum", test_sqlite3rbu_vacuum }, |
| 345 { "sqlite3rbu_create_vfs", test_sqlite3rbu_create_vfs }, |
| 346 { "sqlite3rbu_destroy_vfs", test_sqlite3rbu_destroy_vfs }, |
| 347 { "sqlite3rbu_internal_test", test_sqlite3rbu_internal_test }, |
| 348 }; |
| 349 int i; |
| 350 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ |
| 351 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); |
| 352 } |
| 353 return TCL_OK; |
| 354 } |
| 355 |
| 356 #else |
| 357 #if defined(INCLUDE_SQLITE_TCL_H) |
| 358 # include "sqlite_tcl.h" |
| 359 #else |
| 360 # include "tcl.h" |
| 361 #endif |
| 362 int SqliteRbu_Init(Tcl_Interp *interp){ return TCL_OK; } |
| 363 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) */ |
| 364 #endif /* defined(SQLITE_TEST) */ |
OLD | NEW |