OLD | NEW |
| (Empty) |
1 /* | |
2 ** 2001 September 15 | |
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 ** Code for testing the btree.c module in SQLite. This code | |
13 ** is not included in the SQLite library. It is used for automated | |
14 ** testing of the SQLite library. | |
15 */ | |
16 #include "sqliteInt.h" | |
17 #include "btreeInt.h" | |
18 #include "tcl.h" | |
19 #include <stdlib.h> | |
20 #include <string.h> | |
21 | |
22 extern const char *sqlite3ErrName(int); | |
23 | |
24 /* | |
25 ** A bogus sqlite3 connection structure for use in the btree | |
26 ** tests. | |
27 */ | |
28 static sqlite3 sDb; | |
29 static int nRefSqlite3 = 0; | |
30 | |
31 /* | |
32 ** Usage: btree_open FILENAME NCACHE | |
33 ** | |
34 ** Open a new database | |
35 */ | |
36 static int btree_open( | |
37 void *NotUsed, | |
38 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
39 int argc, /* Number of arguments */ | |
40 const char **argv /* Text of each argument */ | |
41 ){ | |
42 Btree *pBt; | |
43 int rc, nCache; | |
44 char zBuf[100]; | |
45 int n; | |
46 char *zFilename; | |
47 if( argc!=3 ){ | |
48 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
49 " FILENAME NCACHE FLAGS\"", 0); | |
50 return TCL_ERROR; | |
51 } | |
52 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; | |
53 nRefSqlite3++; | |
54 if( nRefSqlite3==1 ){ | |
55 sDb.pVfs = sqlite3_vfs_find(0); | |
56 sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE); | |
57 sqlite3_mutex_enter(sDb.mutex); | |
58 } | |
59 n = (int)strlen(argv[1]); | |
60 zFilename = sqlite3_malloc( n+2 ); | |
61 if( zFilename==0 ) return TCL_ERROR; | |
62 memcpy(zFilename, argv[1], n+1); | |
63 zFilename[n+1] = 0; | |
64 rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0, | |
65 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB); | |
66 sqlite3_free(zFilename); | |
67 if( rc!=SQLITE_OK ){ | |
68 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
69 return TCL_ERROR; | |
70 } | |
71 sqlite3BtreeSetCacheSize(pBt, nCache); | |
72 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt); | |
73 Tcl_AppendResult(interp, zBuf, 0); | |
74 return TCL_OK; | |
75 } | |
76 | |
77 /* | |
78 ** Usage: btree_close ID | |
79 ** | |
80 ** Close the given database. | |
81 */ | |
82 static int btree_close( | |
83 void *NotUsed, | |
84 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
85 int argc, /* Number of arguments */ | |
86 const char **argv /* Text of each argument */ | |
87 ){ | |
88 Btree *pBt; | |
89 int rc; | |
90 if( argc!=2 ){ | |
91 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
92 " ID\"", 0); | |
93 return TCL_ERROR; | |
94 } | |
95 pBt = sqlite3TestTextToPtr(argv[1]); | |
96 rc = sqlite3BtreeClose(pBt); | |
97 if( rc!=SQLITE_OK ){ | |
98 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
99 return TCL_ERROR; | |
100 } | |
101 nRefSqlite3--; | |
102 if( nRefSqlite3==0 ){ | |
103 sqlite3_mutex_leave(sDb.mutex); | |
104 sqlite3_mutex_free(sDb.mutex); | |
105 sDb.mutex = 0; | |
106 sDb.pVfs = 0; | |
107 } | |
108 return TCL_OK; | |
109 } | |
110 | |
111 | |
112 /* | |
113 ** Usage: btree_begin_transaction ID | |
114 ** | |
115 ** Start a new transaction | |
116 */ | |
117 static int btree_begin_transaction( | |
118 void *NotUsed, | |
119 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
120 int argc, /* Number of arguments */ | |
121 const char **argv /* Text of each argument */ | |
122 ){ | |
123 Btree *pBt; | |
124 int rc; | |
125 if( argc!=2 ){ | |
126 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
127 " ID\"", 0); | |
128 return TCL_ERROR; | |
129 } | |
130 pBt = sqlite3TestTextToPtr(argv[1]); | |
131 sqlite3BtreeEnter(pBt); | |
132 rc = sqlite3BtreeBeginTrans(pBt, 1); | |
133 sqlite3BtreeLeave(pBt); | |
134 if( rc!=SQLITE_OK ){ | |
135 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
136 return TCL_ERROR; | |
137 } | |
138 return TCL_OK; | |
139 } | |
140 | |
141 /* | |
142 ** Usage: btree_pager_stats ID | |
143 ** | |
144 ** Returns pager statistics | |
145 */ | |
146 static int btree_pager_stats( | |
147 void *NotUsed, | |
148 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
149 int argc, /* Number of arguments */ | |
150 const char **argv /* Text of each argument */ | |
151 ){ | |
152 Btree *pBt; | |
153 int i; | |
154 int *a; | |
155 | |
156 if( argc!=2 ){ | |
157 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
158 " ID\"", 0); | |
159 return TCL_ERROR; | |
160 } | |
161 pBt = sqlite3TestTextToPtr(argv[1]); | |
162 | |
163 /* Normally in this file, with a b-tree handle opened using the | |
164 ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly. | |
165 ** But this function is sometimes called with a btree handle obtained | |
166 ** from an open SQLite connection (using [btree_from_db]). In this case | |
167 ** we need to obtain the mutex for the controlling SQLite handle before | |
168 ** it is safe to call sqlite3BtreeEnter(). | |
169 */ | |
170 sqlite3_mutex_enter(pBt->db->mutex); | |
171 | |
172 sqlite3BtreeEnter(pBt); | |
173 a = sqlite3PagerStats(sqlite3BtreePager(pBt)); | |
174 for(i=0; i<11; i++){ | |
175 static char *zName[] = { | |
176 "ref", "page", "max", "size", "state", "err", | |
177 "hit", "miss", "ovfl", "read", "write" | |
178 }; | |
179 char zBuf[100]; | |
180 Tcl_AppendElement(interp, zName[i]); | |
181 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]); | |
182 Tcl_AppendElement(interp, zBuf); | |
183 } | |
184 sqlite3BtreeLeave(pBt); | |
185 | |
186 /* Release the mutex on the SQLite handle that controls this b-tree */ | |
187 sqlite3_mutex_leave(pBt->db->mutex); | |
188 return TCL_OK; | |
189 } | |
190 | |
191 /* | |
192 ** Usage: btree_cursor ID TABLENUM WRITEABLE | |
193 ** | |
194 ** Create a new cursor. Return the ID for the cursor. | |
195 */ | |
196 static int btree_cursor( | |
197 void *NotUsed, | |
198 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
199 int argc, /* Number of arguments */ | |
200 const char **argv /* Text of each argument */ | |
201 ){ | |
202 Btree *pBt; | |
203 int iTable; | |
204 BtCursor *pCur; | |
205 int rc = SQLITE_OK; | |
206 int wrFlag; | |
207 char zBuf[30]; | |
208 | |
209 if( argc!=4 ){ | |
210 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
211 " ID TABLENUM WRITEABLE\"", 0); | |
212 return TCL_ERROR; | |
213 } | |
214 pBt = sqlite3TestTextToPtr(argv[1]); | |
215 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; | |
216 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; | |
217 if( wrFlag ) wrFlag = BTREE_WRCSR; | |
218 pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize()); | |
219 memset(pCur, 0, sqlite3BtreeCursorSize()); | |
220 sqlite3_mutex_enter(pBt->db->mutex); | |
221 sqlite3BtreeEnter(pBt); | |
222 #ifndef SQLITE_OMIT_SHARED_CACHE | |
223 rc = sqlite3BtreeLockTable(pBt, iTable, !!wrFlag); | |
224 #endif | |
225 if( rc==SQLITE_OK ){ | |
226 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur); | |
227 } | |
228 sqlite3BtreeLeave(pBt); | |
229 sqlite3_mutex_leave(pBt->db->mutex); | |
230 if( rc ){ | |
231 ckfree((char *)pCur); | |
232 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
233 return TCL_ERROR; | |
234 } | |
235 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); | |
236 Tcl_AppendResult(interp, zBuf, 0); | |
237 return SQLITE_OK; | |
238 } | |
239 | |
240 /* | |
241 ** Usage: btree_close_cursor ID | |
242 ** | |
243 ** Close a cursor opened using btree_cursor. | |
244 */ | |
245 static int btree_close_cursor( | |
246 void *NotUsed, | |
247 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
248 int argc, /* Number of arguments */ | |
249 const char **argv /* Text of each argument */ | |
250 ){ | |
251 BtCursor *pCur; | |
252 Btree *pBt; | |
253 int rc; | |
254 | |
255 if( argc!=2 ){ | |
256 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
257 " ID\"", 0); | |
258 return TCL_ERROR; | |
259 } | |
260 pCur = sqlite3TestTextToPtr(argv[1]); | |
261 pBt = pCur->pBtree; | |
262 sqlite3_mutex_enter(pBt->db->mutex); | |
263 sqlite3BtreeEnter(pBt); | |
264 rc = sqlite3BtreeCloseCursor(pCur); | |
265 sqlite3BtreeLeave(pBt); | |
266 sqlite3_mutex_leave(pBt->db->mutex); | |
267 ckfree((char *)pCur); | |
268 if( rc ){ | |
269 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
270 return TCL_ERROR; | |
271 } | |
272 return SQLITE_OK; | |
273 } | |
274 | |
275 /* | |
276 ** Usage: btree_next ID | |
277 ** | |
278 ** Move the cursor to the next entry in the table. Return 0 on success | |
279 ** or 1 if the cursor was already on the last entry in the table or if | |
280 ** the table is empty. | |
281 */ | |
282 static int btree_next( | |
283 void *NotUsed, | |
284 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
285 int argc, /* Number of arguments */ | |
286 const char **argv /* Text of each argument */ | |
287 ){ | |
288 BtCursor *pCur; | |
289 int rc; | |
290 int res = 0; | |
291 char zBuf[100]; | |
292 | |
293 if( argc!=2 ){ | |
294 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
295 " ID\"", 0); | |
296 return TCL_ERROR; | |
297 } | |
298 pCur = sqlite3TestTextToPtr(argv[1]); | |
299 sqlite3BtreeEnter(pCur->pBtree); | |
300 rc = sqlite3BtreeNext(pCur, &res); | |
301 sqlite3BtreeLeave(pCur->pBtree); | |
302 if( rc ){ | |
303 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
304 return TCL_ERROR; | |
305 } | |
306 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); | |
307 Tcl_AppendResult(interp, zBuf, 0); | |
308 return SQLITE_OK; | |
309 } | |
310 | |
311 /* | |
312 ** Usage: btree_first ID | |
313 ** | |
314 ** Move the cursor to the first entry in the table. Return 0 if the | |
315 ** cursor was left point to something and 1 if the table is empty. | |
316 */ | |
317 static int btree_first( | |
318 void *NotUsed, | |
319 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
320 int argc, /* Number of arguments */ | |
321 const char **argv /* Text of each argument */ | |
322 ){ | |
323 BtCursor *pCur; | |
324 int rc; | |
325 int res = 0; | |
326 char zBuf[100]; | |
327 | |
328 if( argc!=2 ){ | |
329 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
330 " ID\"", 0); | |
331 return TCL_ERROR; | |
332 } | |
333 pCur = sqlite3TestTextToPtr(argv[1]); | |
334 sqlite3BtreeEnter(pCur->pBtree); | |
335 rc = sqlite3BtreeFirst(pCur, &res); | |
336 sqlite3BtreeLeave(pCur->pBtree); | |
337 if( rc ){ | |
338 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
339 return TCL_ERROR; | |
340 } | |
341 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); | |
342 Tcl_AppendResult(interp, zBuf, 0); | |
343 return SQLITE_OK; | |
344 } | |
345 | |
346 /* | |
347 ** Usage: btree_eof ID | |
348 ** | |
349 ** Return TRUE if the given cursor is not pointing at a valid entry. | |
350 ** Return FALSE if the cursor does point to a valid entry. | |
351 */ | |
352 static int btree_eof( | |
353 void *NotUsed, | |
354 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
355 int argc, /* Number of arguments */ | |
356 const char **argv /* Text of each argument */ | |
357 ){ | |
358 BtCursor *pCur; | |
359 int rc; | |
360 char zBuf[50]; | |
361 | |
362 if( argc!=2 ){ | |
363 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
364 " ID\"", 0); | |
365 return TCL_ERROR; | |
366 } | |
367 pCur = sqlite3TestTextToPtr(argv[1]); | |
368 sqlite3BtreeEnter(pCur->pBtree); | |
369 rc = sqlite3BtreeEof(pCur); | |
370 sqlite3BtreeLeave(pCur->pBtree); | |
371 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); | |
372 Tcl_AppendResult(interp, zBuf, 0); | |
373 return SQLITE_OK; | |
374 } | |
375 | |
376 /* | |
377 ** Usage: btree_payload_size ID | |
378 ** | |
379 ** Return the number of bytes of payload | |
380 */ | |
381 static int btree_payload_size( | |
382 void *NotUsed, | |
383 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
384 int argc, /* Number of arguments */ | |
385 const char **argv /* Text of each argument */ | |
386 ){ | |
387 BtCursor *pCur; | |
388 int n2; | |
389 u64 n1; | |
390 char zBuf[50]; | |
391 | |
392 if( argc!=2 ){ | |
393 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
394 " ID\"", 0); | |
395 return TCL_ERROR; | |
396 } | |
397 pCur = sqlite3TestTextToPtr(argv[1]); | |
398 sqlite3BtreeEnter(pCur->pBtree); | |
399 | |
400 /* The cursor may be in "require-seek" state. If this is the case, the | |
401 ** call to BtreeDataSize() will fix it. */ | |
402 sqlite3BtreeDataSize(pCur, (u32*)&n2); | |
403 if( pCur->apPage[pCur->iPage]->intKey ){ | |
404 n1 = 0; | |
405 }else{ | |
406 sqlite3BtreeKeySize(pCur, (i64*)&n1); | |
407 } | |
408 sqlite3BtreeLeave(pCur->pBtree); | |
409 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2)); | |
410 Tcl_AppendResult(interp, zBuf, 0); | |
411 return SQLITE_OK; | |
412 } | |
413 | |
414 /* | |
415 ** usage: varint_test START MULTIPLIER COUNT INCREMENT | |
416 ** | |
417 ** This command tests the putVarint() and getVarint() | |
418 ** routines, both for accuracy and for speed. | |
419 ** | |
420 ** An integer is written using putVarint() and read back with | |
421 ** getVarint() and varified to be unchanged. This repeats COUNT | |
422 ** times. The first integer is START*MULTIPLIER. Each iteration | |
423 ** increases the integer by INCREMENT. | |
424 ** | |
425 ** This command returns nothing if it works. It returns an error message | |
426 ** if something goes wrong. | |
427 */ | |
428 static int btree_varint_test( | |
429 void *NotUsed, | |
430 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
431 int argc, /* Number of arguments */ | |
432 const char **argv /* Text of each argument */ | |
433 ){ | |
434 u32 start, mult, count, incr; | |
435 u64 in, out; | |
436 int n1, n2, i, j; | |
437 unsigned char zBuf[100]; | |
438 if( argc!=5 ){ | |
439 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
440 " START MULTIPLIER COUNT INCREMENT\"", 0); | |
441 return TCL_ERROR; | |
442 } | |
443 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR; | |
444 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR; | |
445 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR; | |
446 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR; | |
447 in = start; | |
448 in *= mult; | |
449 for(i=0; i<(int)count; i++){ | |
450 char zErr[200]; | |
451 n1 = putVarint(zBuf, in); | |
452 if( n1>9 || n1<1 ){ | |
453 sqlite3_snprintf(sizeof(zErr), zErr, | |
454 "putVarint returned %d - should be between 1 and 9", n1); | |
455 Tcl_AppendResult(interp, zErr, 0); | |
456 return TCL_ERROR; | |
457 } | |
458 n2 = getVarint(zBuf, &out); | |
459 if( n1!=n2 ){ | |
460 sqlite3_snprintf(sizeof(zErr), zErr, | |
461 "putVarint returned %d and getVarint returned %d", n1, n2); | |
462 Tcl_AppendResult(interp, zErr, 0); | |
463 return TCL_ERROR; | |
464 } | |
465 if( in!=out ){ | |
466 sqlite3_snprintf(sizeof(zErr), zErr, | |
467 "Wrote 0x%016llx and got back 0x%016llx", in, out); | |
468 Tcl_AppendResult(interp, zErr, 0); | |
469 return TCL_ERROR; | |
470 } | |
471 if( (in & 0xffffffff)==in ){ | |
472 u32 out32; | |
473 n2 = getVarint32(zBuf, out32); | |
474 out = out32; | |
475 if( n1!=n2 ){ | |
476 sqlite3_snprintf(sizeof(zErr), zErr, | |
477 "putVarint returned %d and GetVarint32 returned %d", | |
478 n1, n2); | |
479 Tcl_AppendResult(interp, zErr, 0); | |
480 return TCL_ERROR; | |
481 } | |
482 if( in!=out ){ | |
483 sqlite3_snprintf(sizeof(zErr), zErr, | |
484 "Wrote 0x%016llx and got back 0x%016llx from GetVarint32", | |
485 in, out); | |
486 Tcl_AppendResult(interp, zErr, 0); | |
487 return TCL_ERROR; | |
488 } | |
489 } | |
490 | |
491 /* In order to get realistic timings, run getVarint 19 more times. | |
492 ** This is because getVarint is called about 20 times more often | |
493 ** than putVarint. | |
494 */ | |
495 for(j=0; j<19; j++){ | |
496 getVarint(zBuf, &out); | |
497 } | |
498 in += incr; | |
499 } | |
500 return TCL_OK; | |
501 } | |
502 | |
503 /* | |
504 ** usage: btree_from_db DB-HANDLE | |
505 ** | |
506 ** This command returns the btree handle for the main database associated | |
507 ** with the database-handle passed as the argument. Example usage: | |
508 ** | |
509 ** sqlite3 db test.db | |
510 ** set bt [btree_from_db db] | |
511 */ | |
512 static int btree_from_db( | |
513 void *NotUsed, | |
514 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
515 int argc, /* Number of arguments */ | |
516 const char **argv /* Text of each argument */ | |
517 ){ | |
518 char zBuf[100]; | |
519 Tcl_CmdInfo info; | |
520 sqlite3 *db; | |
521 Btree *pBt; | |
522 int iDb = 0; | |
523 | |
524 if( argc!=2 && argc!=3 ){ | |
525 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
526 " DB-HANDLE ?N?\"", 0); | |
527 return TCL_ERROR; | |
528 } | |
529 | |
530 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){ | |
531 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0); | |
532 return TCL_ERROR; | |
533 } | |
534 if( argc==3 ){ | |
535 iDb = atoi(argv[2]); | |
536 } | |
537 | |
538 db = *((sqlite3 **)info.objClientData); | |
539 assert( db ); | |
540 | |
541 pBt = db->aDb[iDb].pBt; | |
542 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); | |
543 Tcl_SetResult(interp, zBuf, TCL_VOLATILE); | |
544 return TCL_OK; | |
545 } | |
546 | |
547 /* | |
548 ** Usage: btree_ismemdb ID | |
549 ** | |
550 ** Return true if the B-Tree is in-memory. | |
551 */ | |
552 static int btree_ismemdb( | |
553 void *NotUsed, | |
554 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
555 int argc, /* Number of arguments */ | |
556 const char **argv /* Text of each argument */ | |
557 ){ | |
558 Btree *pBt; | |
559 int res; | |
560 | |
561 if( argc!=2 ){ | |
562 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | |
563 " ID\"", 0); | |
564 return TCL_ERROR; | |
565 } | |
566 pBt = sqlite3TestTextToPtr(argv[1]); | |
567 sqlite3_mutex_enter(pBt->db->mutex); | |
568 sqlite3BtreeEnter(pBt); | |
569 res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt)); | |
570 sqlite3BtreeLeave(pBt); | |
571 sqlite3_mutex_leave(pBt->db->mutex); | |
572 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res)); | |
573 return SQLITE_OK; | |
574 } | |
575 | |
576 /* | |
577 ** usage: btree_set_cache_size ID NCACHE | |
578 ** | |
579 ** Set the size of the cache used by btree $ID. | |
580 */ | |
581 static int btree_set_cache_size( | |
582 void *NotUsed, | |
583 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | |
584 int argc, /* Number of arguments */ | |
585 const char **argv /* Text of each argument */ | |
586 ){ | |
587 int nCache; | |
588 Btree *pBt; | |
589 | |
590 if( argc!=3 ){ | |
591 Tcl_AppendResult( | |
592 interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0); | |
593 return TCL_ERROR; | |
594 } | |
595 pBt = sqlite3TestTextToPtr(argv[1]); | |
596 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; | |
597 | |
598 sqlite3_mutex_enter(pBt->db->mutex); | |
599 sqlite3BtreeEnter(pBt); | |
600 sqlite3BtreeSetCacheSize(pBt, nCache); | |
601 sqlite3BtreeLeave(pBt); | |
602 sqlite3_mutex_leave(pBt->db->mutex); | |
603 return TCL_OK; | |
604 } | |
605 | |
606 /* | |
607 ** usage: btree_insert CSR ?KEY? VALUE | |
608 ** | |
609 ** Set the size of the cache used by btree $ID. | |
610 */ | |
611 static int btree_insert( | |
612 ClientData clientData, | |
613 Tcl_Interp *interp, | |
614 int objc, | |
615 Tcl_Obj *const objv[] | |
616 ){ | |
617 BtCursor *pCur; | |
618 int rc; | |
619 void *pKey = 0; | |
620 int nKey = 0; | |
621 void *pData = 0; | |
622 int nData = 0; | |
623 | |
624 if( objc!=4 && objc!=3 ){ | |
625 Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE"); | |
626 return TCL_ERROR; | |
627 } | |
628 | |
629 if( objc==4 ){ | |
630 if( Tcl_GetIntFromObj(interp, objv[2], &nKey) ) return TCL_ERROR; | |
631 pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &nData); | |
632 }else{ | |
633 pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &nKey); | |
634 } | |
635 pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); | |
636 | |
637 sqlite3_mutex_enter(pCur->pBtree->db->mutex); | |
638 sqlite3BtreeEnter(pCur->pBtree); | |
639 rc = sqlite3BtreeInsert(pCur, pKey, nKey, pData, nData, 0, 0, 0); | |
640 sqlite3BtreeLeave(pCur->pBtree); | |
641 sqlite3_mutex_leave(pCur->pBtree->db->mutex); | |
642 | |
643 Tcl_ResetResult(interp); | |
644 if( rc ){ | |
645 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); | |
646 return TCL_ERROR; | |
647 } | |
648 return TCL_OK; | |
649 } | |
650 | |
651 | |
652 /* | |
653 ** Register commands with the TCL interpreter. | |
654 */ | |
655 int Sqlitetest3_Init(Tcl_Interp *interp){ | |
656 static struct { | |
657 char *zName; | |
658 Tcl_CmdProc *xProc; | |
659 } aCmd[] = { | |
660 { "btree_open", (Tcl_CmdProc*)btree_open }, | |
661 { "btree_close", (Tcl_CmdProc*)btree_close }, | |
662 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction }, | |
663 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats }, | |
664 { "btree_cursor", (Tcl_CmdProc*)btree_cursor }, | |
665 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor }, | |
666 { "btree_next", (Tcl_CmdProc*)btree_next }, | |
667 { "btree_eof", (Tcl_CmdProc*)btree_eof }, | |
668 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size }, | |
669 { "btree_first", (Tcl_CmdProc*)btree_first }, | |
670 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test }, | |
671 { "btree_from_db", (Tcl_CmdProc*)btree_from_db }, | |
672 { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb }, | |
673 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size } | |
674 }; | |
675 int i; | |
676 | |
677 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ | |
678 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); | |
679 } | |
680 | |
681 Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0); | |
682 | |
683 return TCL_OK; | |
684 } | |
OLD | NEW |