4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
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.
16 #include "sqliteInt.h"
18 #if defined(INCLUDE_SQLITE_TCL_H)
19 # include "sqlite_tcl.h"
26 extern const char *sqlite3ErrName(int);
29 ** A bogus sqlite3 connection structure for use in the btree
33 static int nRefSqlite3
= 0;
36 ** Usage: btree_open FILENAME NCACHE
38 ** Open a new database
40 static int SQLITE_TCLAPI
btree_open(
42 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
43 int argc
, /* Number of arguments */
44 const char **argv
/* Text of each argument */
52 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
53 " FILENAME NCACHE FLAGS\"", 0);
56 if( Tcl_GetInt(interp
, argv
[2], &nCache
) ) return TCL_ERROR
;
59 sDb
.pVfs
= sqlite3_vfs_find(0);
60 sDb
.mutex
= sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE
);
61 sqlite3_mutex_enter(sDb
.mutex
);
63 n
= (int)strlen(argv
[1]);
64 zFilename
= sqlite3_malloc( n
+2 );
65 if( zFilename
==0 ) return TCL_ERROR
;
66 memcpy(zFilename
, argv
[1], n
+1);
68 rc
= sqlite3BtreeOpen(sDb
.pVfs
, zFilename
, &sDb
, &pBt
, 0,
69 SQLITE_OPEN_READWRITE
| SQLITE_OPEN_CREATE
| SQLITE_OPEN_MAIN_DB
);
70 sqlite3_free(zFilename
);
72 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
75 sqlite3BtreeSetCacheSize(pBt
, nCache
);
76 sqlite3_snprintf(sizeof(zBuf
), zBuf
,"%p", pBt
);
77 Tcl_AppendResult(interp
, zBuf
, 0);
82 ** Usage: btree_close ID
84 ** Close the given database.
86 static int SQLITE_TCLAPI
btree_close(
88 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
89 int argc
, /* Number of arguments */
90 const char **argv
/* Text of each argument */
95 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
99 pBt
= sqlite3TestTextToPtr(argv
[1]);
100 rc
= sqlite3BtreeClose(pBt
);
102 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
106 if( nRefSqlite3
==0 ){
107 sqlite3_mutex_leave(sDb
.mutex
);
108 sqlite3_mutex_free(sDb
.mutex
);
117 ** Usage: btree_begin_transaction ID
119 ** Start a new transaction
121 static int SQLITE_TCLAPI
btree_begin_transaction(
123 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
124 int argc
, /* Number of arguments */
125 const char **argv
/* Text of each argument */
130 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
134 pBt
= sqlite3TestTextToPtr(argv
[1]);
135 sqlite3BtreeEnter(pBt
);
136 rc
= sqlite3BtreeBeginTrans(pBt
, 1, 0);
137 sqlite3BtreeLeave(pBt
);
139 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
146 ** Usage: btree_pager_stats ID
148 ** Returns pager statistics
150 static int SQLITE_TCLAPI
btree_pager_stats(
152 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
153 int argc
, /* Number of arguments */
154 const char **argv
/* Text of each argument */
161 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
165 pBt
= sqlite3TestTextToPtr(argv
[1]);
167 /* Normally in this file, with a b-tree handle opened using the
168 ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
169 ** But this function is sometimes called with a btree handle obtained
170 ** from an open SQLite connection (using [btree_from_db]). In this case
171 ** we need to obtain the mutex for the controlling SQLite handle before
172 ** it is safe to call sqlite3BtreeEnter().
174 sqlite3_mutex_enter(pBt
->db
->mutex
);
176 sqlite3BtreeEnter(pBt
);
177 a
= sqlite3PagerStats(sqlite3BtreePager(pBt
));
179 static char *zName
[] = {
180 "ref", "page", "max", "size", "state", "err",
181 "hit", "miss", "ovfl", "read", "write"
184 Tcl_AppendElement(interp
, zName
[i
]);
185 sqlite3_snprintf(sizeof(zBuf
), zBuf
,"%d",a
[i
]);
186 Tcl_AppendElement(interp
, zBuf
);
188 sqlite3BtreeLeave(pBt
);
190 /* Release the mutex on the SQLite handle that controls this b-tree */
191 sqlite3_mutex_leave(pBt
->db
->mutex
);
196 ** Usage: btree_cursor ID TABLENUM WRITEABLE
198 ** Create a new cursor. Return the ID for the cursor.
200 static int SQLITE_TCLAPI
btree_cursor(
202 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
203 int argc
, /* Number of arguments */
204 const char **argv
/* Text of each argument */
214 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
215 " ID TABLENUM WRITEABLE\"", 0);
218 pBt
= sqlite3TestTextToPtr(argv
[1]);
219 if( Tcl_GetInt(interp
, argv
[2], &iTable
) ) return TCL_ERROR
;
220 if( Tcl_GetBoolean(interp
, argv
[3], &wrFlag
) ) return TCL_ERROR
;
221 if( wrFlag
) wrFlag
= BTREE_WRCSR
;
222 pCur
= (BtCursor
*)ckalloc(sqlite3BtreeCursorSize());
223 memset(pCur
, 0, sqlite3BtreeCursorSize());
224 sqlite3_mutex_enter(pBt
->db
->mutex
);
225 sqlite3BtreeEnter(pBt
);
226 #ifndef SQLITE_OMIT_SHARED_CACHE
227 rc
= sqlite3BtreeLockTable(pBt
, iTable
, !!wrFlag
);
230 rc
= sqlite3BtreeCursor(pBt
, iTable
, wrFlag
, 0, pCur
);
232 sqlite3BtreeLeave(pBt
);
233 sqlite3_mutex_leave(pBt
->db
->mutex
);
235 ckfree((char *)pCur
);
236 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
239 sqlite3_snprintf(sizeof(zBuf
), zBuf
,"%p", pCur
);
240 Tcl_AppendResult(interp
, zBuf
, 0);
245 ** Usage: btree_close_cursor ID
247 ** Close a cursor opened using btree_cursor.
249 static int SQLITE_TCLAPI
btree_close_cursor(
251 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
252 int argc
, /* Number of arguments */
253 const char **argv
/* Text of each argument */
259 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
263 pCur
= sqlite3TestTextToPtr(argv
[1]);
264 #if SQLITE_THREADSAFE>0
266 Btree
*pBt
= pCur
->pBtree
;
267 sqlite3_mutex_enter(pBt
->db
->mutex
);
268 sqlite3BtreeEnter(pBt
);
269 rc
= sqlite3BtreeCloseCursor(pCur
);
270 sqlite3BtreeLeave(pBt
);
271 sqlite3_mutex_leave(pBt
->db
->mutex
);
274 rc
= sqlite3BtreeCloseCursor(pCur
);
276 ckfree((char *)pCur
);
278 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
285 ** Usage: btree_next ID
287 ** Move the cursor to the next entry in the table. Return 0 on success
288 ** or 1 if the cursor was already on the last entry in the table or if
289 ** the table is empty.
291 static int SQLITE_TCLAPI
btree_next(
293 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
294 int argc
, /* Number of arguments */
295 const char **argv
/* Text of each argument */
303 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
307 pCur
= sqlite3TestTextToPtr(argv
[1]);
308 sqlite3BtreeEnter(pCur
->pBtree
);
309 rc
= sqlite3BtreeNext(pCur
, 0);
310 if( rc
==SQLITE_DONE
){
314 sqlite3BtreeLeave(pCur
->pBtree
);
316 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
319 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%d",res
);
320 Tcl_AppendResult(interp
, zBuf
, 0);
325 ** Usage: btree_first ID
327 ** Move the cursor to the first entry in the table. Return 0 if the
328 ** cursor was left point to something and 1 if the table is empty.
330 static int SQLITE_TCLAPI
btree_first(
332 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
333 int argc
, /* Number of arguments */
334 const char **argv
/* Text of each argument */
342 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
346 pCur
= sqlite3TestTextToPtr(argv
[1]);
347 sqlite3BtreeEnter(pCur
->pBtree
);
348 rc
= sqlite3BtreeFirst(pCur
, &res
);
349 sqlite3BtreeLeave(pCur
->pBtree
);
351 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
354 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%d",res
);
355 Tcl_AppendResult(interp
, zBuf
, 0);
360 ** Usage: btree_eof ID
362 ** Return TRUE if the given cursor is not pointing at a valid entry.
363 ** Return FALSE if the cursor does point to a valid entry.
365 static int SQLITE_TCLAPI
btree_eof(
367 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
368 int argc
, /* Number of arguments */
369 const char **argv
/* Text of each argument */
376 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
380 pCur
= sqlite3TestTextToPtr(argv
[1]);
381 sqlite3BtreeEnter(pCur
->pBtree
);
382 rc
= sqlite3BtreeEof(pCur
);
383 sqlite3BtreeLeave(pCur
->pBtree
);
384 sqlite3_snprintf(sizeof(zBuf
),zBuf
, "%d", rc
);
385 Tcl_AppendResult(interp
, zBuf
, 0);
390 ** Usage: btree_payload_size ID
392 ** Return the number of bytes of payload
394 static int SQLITE_TCLAPI
btree_payload_size(
396 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
397 int argc
, /* Number of arguments */
398 const char **argv
/* Text of each argument */
405 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
409 pCur
= sqlite3TestTextToPtr(argv
[1]);
410 sqlite3BtreeEnter(pCur
->pBtree
);
411 n
= sqlite3BtreePayloadSize(pCur
);
412 sqlite3BtreeLeave(pCur
->pBtree
);
413 sqlite3_snprintf(sizeof(zBuf
),zBuf
, "%u", n
);
414 Tcl_AppendResult(interp
, zBuf
, 0);
419 ** usage: varint_test START MULTIPLIER COUNT INCREMENT
421 ** This command tests the putVarint() and getVarint()
422 ** routines, both for accuracy and for speed.
424 ** An integer is written using putVarint() and read back with
425 ** getVarint() and verified to be unchanged. This repeats COUNT
426 ** times. The first integer is START*MULTIPLIER. Each iteration
427 ** increases the integer by INCREMENT.
429 ** This command returns nothing if it works. It returns an error message
430 ** if something goes wrong.
432 static int SQLITE_TCLAPI
btree_varint_test(
434 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
435 int argc
, /* Number of arguments */
436 const char **argv
/* Text of each argument */
438 u32 start
, mult
, count
, incr
;
441 unsigned char zBuf
[100];
443 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
444 " START MULTIPLIER COUNT INCREMENT\"", 0);
447 if( Tcl_GetInt(interp
, argv
[1], (int*)&start
) ) return TCL_ERROR
;
448 if( Tcl_GetInt(interp
, argv
[2], (int*)&mult
) ) return TCL_ERROR
;
449 if( Tcl_GetInt(interp
, argv
[3], (int*)&count
) ) return TCL_ERROR
;
450 if( Tcl_GetInt(interp
, argv
[4], (int*)&incr
) ) return TCL_ERROR
;
453 for(i
=0; i
<(int)count
; i
++){
455 n1
= putVarint(zBuf
, in
);
457 sqlite3_snprintf(sizeof(zErr
), zErr
,
458 "putVarint returned %d - should be between 1 and 9", n1
);
459 Tcl_AppendResult(interp
, zErr
, 0);
462 n2
= getVarint(zBuf
, &out
);
464 sqlite3_snprintf(sizeof(zErr
), zErr
,
465 "putVarint returned %d and getVarint returned %d", n1
, n2
);
466 Tcl_AppendResult(interp
, zErr
, 0);
470 sqlite3_snprintf(sizeof(zErr
), zErr
,
471 "Wrote 0x%016llx and got back 0x%016llx", in
, out
);
472 Tcl_AppendResult(interp
, zErr
, 0);
475 if( (in
& 0xffffffff)==in
){
477 n2
= getVarint32(zBuf
, out32
);
480 sqlite3_snprintf(sizeof(zErr
), zErr
,
481 "putVarint returned %d and GetVarint32 returned %d",
483 Tcl_AppendResult(interp
, zErr
, 0);
487 sqlite3_snprintf(sizeof(zErr
), zErr
,
488 "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
490 Tcl_AppendResult(interp
, zErr
, 0);
495 /* In order to get realistic timings, run getVarint 19 more times.
496 ** This is because getVarint is called about 20 times more often
500 getVarint(zBuf
, &out
);
508 ** usage: btree_from_db DB-HANDLE
510 ** This command returns the btree handle for the main database associated
511 ** with the database-handle passed as the argument. Example usage:
513 ** sqlite3 db test.db
514 ** set bt [btree_from_db db]
516 static int SQLITE_TCLAPI
btree_from_db(
518 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
519 int argc
, /* Number of arguments */
520 const char **argv
/* Text of each argument */
528 if( argc
!=2 && argc
!=3 ){
529 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
530 " DB-HANDLE ?N?\"", 0);
534 if( 1!=Tcl_GetCommandInfo(interp
, argv
[1], &info
) ){
535 Tcl_AppendResult(interp
, "No such db-handle: \"", argv
[1], "\"", 0);
542 db
= *((sqlite3
**)info
.objClientData
);
545 pBt
= db
->aDb
[iDb
].pBt
;
546 sqlite3_snprintf(sizeof(zBuf
), zBuf
, "%p", pBt
);
547 Tcl_SetResult(interp
, zBuf
, TCL_VOLATILE
);
552 ** Usage: btree_ismemdb ID
554 ** Return true if the B-Tree is currently stored entirely in memory.
556 static int SQLITE_TCLAPI
btree_ismemdb(
558 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
559 int argc
, /* Number of arguments */
560 const char **argv
/* Text of each argument */
567 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
571 pBt
= sqlite3TestTextToPtr(argv
[1]);
572 sqlite3_mutex_enter(pBt
->db
->mutex
);
573 sqlite3BtreeEnter(pBt
);
574 pFile
= sqlite3PagerFile(sqlite3BtreePager(pBt
));
575 res
= (pFile
->pMethods
==0);
576 sqlite3BtreeLeave(pBt
);
577 sqlite3_mutex_leave(pBt
->db
->mutex
);
578 Tcl_SetObjResult(interp
, Tcl_NewBooleanObj(res
));
583 ** usage: btree_set_cache_size ID NCACHE
585 ** Set the size of the cache used by btree $ID.
587 static int SQLITE_TCLAPI
btree_set_cache_size(
589 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
590 int argc
, /* Number of arguments */
591 const char **argv
/* Text of each argument */
598 interp
, "wrong # args: should be \"", argv
[0], " BT NCACHE\"", 0);
601 pBt
= sqlite3TestTextToPtr(argv
[1]);
602 if( Tcl_GetInt(interp
, argv
[2], &nCache
) ) return TCL_ERROR
;
604 sqlite3_mutex_enter(pBt
->db
->mutex
);
605 sqlite3BtreeEnter(pBt
);
606 sqlite3BtreeSetCacheSize(pBt
, nCache
);
607 sqlite3BtreeLeave(pBt
);
608 sqlite3_mutex_leave(pBt
->db
->mutex
);
613 ** usage: btree_insert CSR ?KEY? VALUE
615 ** Set the size of the cache used by btree $ID.
617 static int SQLITE_TCLAPI
btree_insert(
618 ClientData clientData
,
621 Tcl_Obj
*const objv
[]
627 if( objc
!=4 && objc
!=3 ){
628 Tcl_WrongNumArgs(interp
, 1, objv
, "?-intkey? CSR KEY VALUE");
632 memset(&x
, 0, sizeof(x
));
634 if( Tcl_GetIntFromObj(interp
, objv
[2], &rc
) ) return TCL_ERROR
;
636 x
.pData
= (void*)Tcl_GetByteArrayFromObj(objv
[3], &x
.nData
);
638 x
.pKey
= (void*)Tcl_GetByteArrayFromObj(objv
[2], &rc
);
641 pCur
= (BtCursor
*)sqlite3TestTextToPtr(Tcl_GetString(objv
[1]));
643 sqlite3_mutex_enter(pCur
->pBtree
->db
->mutex
);
644 sqlite3BtreeEnter(pCur
->pBtree
);
645 rc
= sqlite3BtreeInsert(pCur
, &x
, 0, 0);
646 sqlite3BtreeLeave(pCur
->pBtree
);
647 sqlite3_mutex_leave(pCur
->pBtree
->db
->mutex
);
649 Tcl_ResetResult(interp
);
651 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
659 ** Register commands with the TCL interpreter.
661 int Sqlitetest3_Init(Tcl_Interp
*interp
){
666 { "btree_open", (Tcl_CmdProc
*)btree_open
},
667 { "btree_close", (Tcl_CmdProc
*)btree_close
},
668 { "btree_begin_transaction", (Tcl_CmdProc
*)btree_begin_transaction
},
669 { "btree_pager_stats", (Tcl_CmdProc
*)btree_pager_stats
},
670 { "btree_cursor", (Tcl_CmdProc
*)btree_cursor
},
671 { "btree_close_cursor", (Tcl_CmdProc
*)btree_close_cursor
},
672 { "btree_next", (Tcl_CmdProc
*)btree_next
},
673 { "btree_eof", (Tcl_CmdProc
*)btree_eof
},
674 { "btree_payload_size", (Tcl_CmdProc
*)btree_payload_size
},
675 { "btree_first", (Tcl_CmdProc
*)btree_first
},
676 { "btree_varint_test", (Tcl_CmdProc
*)btree_varint_test
},
677 { "btree_from_db", (Tcl_CmdProc
*)btree_from_db
},
678 { "btree_ismemdb", (Tcl_CmdProc
*)btree_ismemdb
},
679 { "btree_set_cache_size", (Tcl_CmdProc
*)btree_set_cache_size
}
683 for(i
=0; i
<sizeof(aCmd
)/sizeof(aCmd
[0]); i
++){
684 Tcl_CreateCommand(interp
, aCmd
[i
].zName
, aCmd
[i
].xProc
, 0, 0);
687 Tcl_CreateObjCommand(interp
, "btree_insert", btree_insert
, 0, 0);