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 |