test_rbu.c 10 KB

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