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 #include <tcl.h> |
| 21 #include <assert.h> |
| 22 |
| 23 /* From main.c (apparently...) */ |
| 24 extern const char *sqlite3ErrName(int); |
| 25 |
| 26 void test_rbu_delta(sqlite3_context *pCtx, int nArg, sqlite3_value **apVal){ |
| 27 Tcl_Interp *interp = (Tcl_Interp*)sqlite3_user_data(pCtx); |
| 28 Tcl_Obj *pScript; |
| 29 int i; |
| 30 |
| 31 pScript = Tcl_NewObj(); |
| 32 Tcl_IncrRefCount(pScript); |
| 33 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj("rbu_delta", -1)); |
| 34 for(i=0; i<nArg; i++){ |
| 35 sqlite3_value *pIn = apVal[i]; |
| 36 const char *z = (const char*)sqlite3_value_text(pIn); |
| 37 Tcl_ListObjAppendElement(0, pScript, Tcl_NewStringObj(z, -1)); |
| 38 } |
| 39 |
| 40 if( TCL_OK==Tcl_EvalObjEx(interp, pScript, TCL_GLOBAL_ONLY) ){ |
| 41 const char *z = Tcl_GetStringResult(interp); |
| 42 sqlite3_result_text(pCtx, z, -1, SQLITE_TRANSIENT); |
| 43 }else{ |
| 44 Tcl_BackgroundError(interp); |
| 45 } |
| 46 |
| 47 Tcl_DecrRefCount(pScript); |
| 48 } |
| 49 |
| 50 |
| 51 static int test_sqlite3rbu_cmd( |
| 52 ClientData clientData, |
| 53 Tcl_Interp *interp, |
| 54 int objc, |
| 55 Tcl_Obj *CONST objv[] |
| 56 ){ |
| 57 int ret = TCL_OK; |
| 58 sqlite3rbu *pRbu = (sqlite3rbu*)clientData; |
| 59 struct RbuCmd { |
| 60 const char *zName; |
| 61 int nArg; |
| 62 const char *zUsage; |
| 63 } aCmd[] = { |
| 64 {"step", 2, ""}, /* 0 */ |
| 65 {"close", 2, ""}, /* 1 */ |
| 66 {"create_rbu_delta", 2, ""}, /* 2 */ |
| 67 {"savestate", 2, ""}, /* 3 */ |
| 68 {"dbMain_eval", 3, "SQL"}, /* 4 */ |
| 69 {0,0,0} |
| 70 }; |
| 71 int iCmd; |
| 72 |
| 73 if( objc<2 ){ |
| 74 Tcl_WrongNumArgs(interp, 1, objv, "METHOD"); |
| 75 return TCL_ERROR; |
| 76 } |
| 77 ret = Tcl_GetIndexFromObjStruct( |
| 78 interp, objv[1], aCmd, sizeof(aCmd[0]), "method", 0, &iCmd |
| 79 ); |
| 80 if( ret ) return TCL_ERROR; |
| 81 if( objc!=aCmd[iCmd].nArg ){ |
| 82 Tcl_WrongNumArgs(interp, 1, objv, aCmd[iCmd].zUsage); |
| 83 return TCL_ERROR; |
| 84 } |
| 85 |
| 86 switch( iCmd ){ |
| 87 case 0: /* step */ { |
| 88 int rc = sqlite3rbu_step(pRbu); |
| 89 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 90 break; |
| 91 } |
| 92 |
| 93 case 1: /* close */ { |
| 94 char *zErrmsg = 0; |
| 95 int rc; |
| 96 Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); |
| 97 rc = sqlite3rbu_close(pRbu, &zErrmsg); |
| 98 if( rc==SQLITE_OK || rc==SQLITE_DONE ){ |
| 99 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 100 assert( zErrmsg==0 ); |
| 101 }else{ |
| 102 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 103 if( zErrmsg ){ |
| 104 Tcl_AppendResult(interp, " - ", zErrmsg, 0); |
| 105 sqlite3_free(zErrmsg); |
| 106 } |
| 107 ret = TCL_ERROR; |
| 108 } |
| 109 break; |
| 110 } |
| 111 |
| 112 case 2: /* create_rbu_delta */ { |
| 113 sqlite3 *db = sqlite3rbu_db(pRbu, 0); |
| 114 int rc = sqlite3_create_function( |
| 115 db, "rbu_delta", -1, SQLITE_UTF8, (void*)interp, test_rbu_delta, 0, 0 |
| 116 ); |
| 117 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 118 ret = (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); |
| 119 break; |
| 120 } |
| 121 |
| 122 case 3: /* savestate */ { |
| 123 int rc = sqlite3rbu_savestate(pRbu); |
| 124 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 125 ret = (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); |
| 126 break; |
| 127 } |
| 128 |
| 129 case 4: /* dbMain_eval */ { |
| 130 sqlite3 *db = sqlite3rbu_db(pRbu, 0); |
| 131 int rc = sqlite3_exec(db, Tcl_GetString(objv[2]), 0, 0, 0); |
| 132 if( rc!=SQLITE_OK ){ |
| 133 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3_errmsg(db), -1)); |
| 134 ret = TCL_ERROR; |
| 135 } |
| 136 break; |
| 137 } |
| 138 |
| 139 default: /* seems unlikely */ |
| 140 assert( !"cannot happen" ); |
| 141 break; |
| 142 } |
| 143 |
| 144 return ret; |
| 145 } |
| 146 |
| 147 /* |
| 148 ** Tclcmd: sqlite3rbu CMD <target-db> <rbu-db> ?<state-db>? |
| 149 */ |
| 150 static int test_sqlite3rbu( |
| 151 ClientData clientData, |
| 152 Tcl_Interp *interp, |
| 153 int objc, |
| 154 Tcl_Obj *CONST objv[] |
| 155 ){ |
| 156 sqlite3rbu *pRbu = 0; |
| 157 const char *zCmd; |
| 158 const char *zTarget; |
| 159 const char *zRbu; |
| 160 const char *zStateDb = 0; |
| 161 |
| 162 if( objc!=4 && objc!=5 ){ |
| 163 Tcl_WrongNumArgs(interp, 1, objv, "NAME TARGET-DB RBU-DB ?STATE-DB?"); |
| 164 return TCL_ERROR; |
| 165 } |
| 166 zCmd = Tcl_GetString(objv[1]); |
| 167 zTarget = Tcl_GetString(objv[2]); |
| 168 zRbu = Tcl_GetString(objv[3]); |
| 169 if( objc==5 ) zStateDb = Tcl_GetString(objv[4]); |
| 170 |
| 171 pRbu = sqlite3rbu_open(zTarget, zRbu, zStateDb); |
| 172 Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0); |
| 173 Tcl_SetObjResult(interp, objv[1]); |
| 174 return TCL_OK; |
| 175 } |
| 176 |
| 177 /* |
| 178 ** Tclcmd: sqlite3rbu_create_vfs ?-default? NAME PARENT |
| 179 */ |
| 180 static int test_sqlite3rbu_create_vfs( |
| 181 ClientData clientData, |
| 182 Tcl_Interp *interp, |
| 183 int objc, |
| 184 Tcl_Obj *CONST objv[] |
| 185 ){ |
| 186 const char *zName; |
| 187 const char *zParent; |
| 188 int rc; |
| 189 |
| 190 if( objc!=3 && objc!=4 ){ |
| 191 Tcl_WrongNumArgs(interp, 1, objv, "?-default? NAME PARENT"); |
| 192 return TCL_ERROR; |
| 193 } |
| 194 |
| 195 zName = Tcl_GetString(objv[objc-2]); |
| 196 zParent = Tcl_GetString(objv[objc-1]); |
| 197 if( zParent[0]=='\0' ) zParent = 0; |
| 198 |
| 199 rc = sqlite3rbu_create_vfs(zName, zParent); |
| 200 if( rc!=SQLITE_OK ){ |
| 201 Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1)); |
| 202 return TCL_ERROR; |
| 203 }else if( objc==4 ){ |
| 204 sqlite3_vfs *pVfs = sqlite3_vfs_find(zName); |
| 205 sqlite3_vfs_register(pVfs, 1); |
| 206 } |
| 207 |
| 208 Tcl_ResetResult(interp); |
| 209 return TCL_OK; |
| 210 } |
| 211 |
| 212 /* |
| 213 ** Tclcmd: sqlite3rbu_destroy_vfs NAME |
| 214 */ |
| 215 static int test_sqlite3rbu_destroy_vfs( |
| 216 ClientData clientData, |
| 217 Tcl_Interp *interp, |
| 218 int objc, |
| 219 Tcl_Obj *CONST objv[] |
| 220 ){ |
| 221 const char *zName; |
| 222 |
| 223 if( objc!=2 ){ |
| 224 Tcl_WrongNumArgs(interp, 1, objv, "NAME"); |
| 225 return TCL_ERROR; |
| 226 } |
| 227 |
| 228 zName = Tcl_GetString(objv[1]); |
| 229 sqlite3rbu_destroy_vfs(zName); |
| 230 return TCL_OK; |
| 231 } |
| 232 |
| 233 /* |
| 234 ** Tclcmd: sqlite3rbu_internal_test |
| 235 */ |
| 236 static int test_sqlite3rbu_internal_test( |
| 237 ClientData clientData, |
| 238 Tcl_Interp *interp, |
| 239 int objc, |
| 240 Tcl_Obj *CONST objv[] |
| 241 ){ |
| 242 sqlite3 *db; |
| 243 |
| 244 if( objc!=1 ){ |
| 245 Tcl_WrongNumArgs(interp, 1, objv, ""); |
| 246 return TCL_ERROR; |
| 247 } |
| 248 |
| 249 db = sqlite3rbu_db(0, 0); |
| 250 if( db!=0 ){ |
| 251 Tcl_AppendResult(interp, "sqlite3rbu_db(0, 0)!=0", 0); |
| 252 return TCL_ERROR; |
| 253 } |
| 254 |
| 255 return TCL_OK; |
| 256 } |
| 257 |
| 258 int SqliteRbu_Init(Tcl_Interp *interp){ |
| 259 static struct { |
| 260 char *zName; |
| 261 Tcl_ObjCmdProc *xProc; |
| 262 } aObjCmd[] = { |
| 263 { "sqlite3rbu", test_sqlite3rbu }, |
| 264 { "sqlite3rbu_create_vfs", test_sqlite3rbu_create_vfs }, |
| 265 { "sqlite3rbu_destroy_vfs", test_sqlite3rbu_destroy_vfs }, |
| 266 { "sqlite3rbu_internal_test", test_sqlite3rbu_internal_test }, |
| 267 }; |
| 268 int i; |
| 269 for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ |
| 270 Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); |
| 271 } |
| 272 return TCL_OK; |
| 273 } |
| 274 |
| 275 #else |
| 276 #include <tcl.h> |
| 277 int SqliteRbu_Init(Tcl_Interp *interp){ return TCL_OK; } |
| 278 #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_RBU) */ |
| 279 #endif /* defined(SQLITE_TEST) */ |
OLD | NEW |