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"
22 extern const char *sqlite3ErrName(int);
25 ** A bogus sqlite3 connection structure for use in the btree
29 static int nRefSqlite3
= 0;
32 ** Usage: btree_open FILENAME NCACHE
34 ** Open a new database
36 static int btree_open(
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 */
48 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
49 " FILENAME NCACHE FLAGS\"", 0);
52 if( Tcl_GetInt(interp
, argv
[2], &nCache
) ) return TCL_ERROR
;
55 sDb
.pVfs
= sqlite3_vfs_find(0);
56 sDb
.mutex
= sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE
);
57 sqlite3_mutex_enter(sDb
.mutex
);
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);
64 rc
= sqlite3BtreeOpen(sDb
.pVfs
, zFilename
, &sDb
, &pBt
, 0,
65 SQLITE_OPEN_READWRITE
| SQLITE_OPEN_CREATE
| SQLITE_OPEN_MAIN_DB
);
66 sqlite3_free(zFilename
);
68 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
71 sqlite3BtreeSetCacheSize(pBt
, nCache
);
72 sqlite3_snprintf(sizeof(zBuf
), zBuf
,"%p", pBt
);
73 Tcl_AppendResult(interp
, zBuf
, 0);
78 ** Usage: btree_close ID
80 ** Close the given database.
82 static int btree_close(
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 */
91 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
95 pBt
= sqlite3TestTextToPtr(argv
[1]);
96 rc
= sqlite3BtreeClose(pBt
);
98 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
102 if( nRefSqlite3
==0 ){
103 sqlite3_mutex_leave(sDb
.mutex
);
104 sqlite3_mutex_free(sDb
.mutex
);
113 ** Usage: btree_begin_transaction ID
115 ** Start a new transaction
117 static int btree_begin_transaction(
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 */
126 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
130 pBt
= sqlite3TestTextToPtr(argv
[1]);
131 sqlite3BtreeEnter(pBt
);
132 rc
= sqlite3BtreeBeginTrans(pBt
, 1);
133 sqlite3BtreeLeave(pBt
);
135 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
142 ** Usage: btree_pager_stats ID
144 ** Returns pager statistics
146 static int btree_pager_stats(
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 */
157 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
161 pBt
= sqlite3TestTextToPtr(argv
[1]);
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().
170 sqlite3_mutex_enter(pBt
->db
->mutex
);
172 sqlite3BtreeEnter(pBt
);
173 a
= sqlite3PagerStats(sqlite3BtreePager(pBt
));
175 static char *zName
[] = {
176 "ref", "page", "max", "size", "state", "err",
177 "hit", "miss", "ovfl", "read", "write"
180 Tcl_AppendElement(interp
, zName
[i
]);
181 sqlite3_snprintf(sizeof(zBuf
), zBuf
,"%d",a
[i
]);
182 Tcl_AppendElement(interp
, zBuf
);
184 sqlite3BtreeLeave(pBt
);
186 /* Release the mutex on the SQLite handle that controls this b-tree */
187 sqlite3_mutex_leave(pBt
->db
->mutex
);
192 ** Usage: btree_cursor ID TABLENUM WRITEABLE
194 ** Create a new cursor. Return the ID for the cursor.
196 static int btree_cursor(
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 */
210 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
211 " ID TABLENUM WRITEABLE\"", 0);
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 pCur
= (BtCursor
*)ckalloc(sqlite3BtreeCursorSize());
218 memset(pCur
, 0, sqlite3BtreeCursorSize());
219 sqlite3BtreeEnter(pBt
);
220 #ifndef SQLITE_OMIT_SHARED_CACHE
221 rc
= sqlite3BtreeLockTable(pBt
, iTable
, wrFlag
);
224 rc
= sqlite3BtreeCursor(pBt
, iTable
, wrFlag
, 0, pCur
);
226 sqlite3BtreeLeave(pBt
);
228 ckfree((char *)pCur
);
229 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
232 sqlite3_snprintf(sizeof(zBuf
), zBuf
,"%p", pCur
);
233 Tcl_AppendResult(interp
, zBuf
, 0);
238 ** Usage: btree_close_cursor ID
240 ** Close a cursor opened using btree_cursor.
242 static int btree_close_cursor(
244 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
245 int argc
, /* Number of arguments */
246 const char **argv
/* Text of each argument */
253 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
257 pCur
= sqlite3TestTextToPtr(argv
[1]);
259 sqlite3BtreeEnter(pBt
);
260 rc
= sqlite3BtreeCloseCursor(pCur
);
261 sqlite3BtreeLeave(pBt
);
262 ckfree((char *)pCur
);
264 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
271 ** Usage: btree_next ID
273 ** Move the cursor to the next entry in the table. Return 0 on success
274 ** or 1 if the cursor was already on the last entry in the table or if
275 ** the table is empty.
277 static int btree_next(
279 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
280 int argc
, /* Number of arguments */
281 const char **argv
/* Text of each argument */
289 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
293 pCur
= sqlite3TestTextToPtr(argv
[1]);
294 sqlite3BtreeEnter(pCur
->pBtree
);
295 rc
= sqlite3BtreeNext(pCur
, &res
);
296 sqlite3BtreeLeave(pCur
->pBtree
);
298 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
301 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%d",res
);
302 Tcl_AppendResult(interp
, zBuf
, 0);
307 ** Usage: btree_first ID
309 ** Move the cursor to the first entry in the table. Return 0 if the
310 ** cursor was left point to something and 1 if the table is empty.
312 static int btree_first(
314 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
315 int argc
, /* Number of arguments */
316 const char **argv
/* Text of each argument */
324 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
328 pCur
= sqlite3TestTextToPtr(argv
[1]);
329 sqlite3BtreeEnter(pCur
->pBtree
);
330 rc
= sqlite3BtreeFirst(pCur
, &res
);
331 sqlite3BtreeLeave(pCur
->pBtree
);
333 Tcl_AppendResult(interp
, sqlite3ErrName(rc
), 0);
336 sqlite3_snprintf(sizeof(zBuf
),zBuf
,"%d",res
);
337 Tcl_AppendResult(interp
, zBuf
, 0);
342 ** Usage: btree_eof ID
344 ** Return TRUE if the given cursor is not pointing at a valid entry.
345 ** Return FALSE if the cursor does point to a valid entry.
347 static int btree_eof(
349 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
350 int argc
, /* Number of arguments */
351 const char **argv
/* Text of each argument */
358 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
362 pCur
= sqlite3TestTextToPtr(argv
[1]);
363 sqlite3BtreeEnter(pCur
->pBtree
);
364 rc
= sqlite3BtreeEof(pCur
);
365 sqlite3BtreeLeave(pCur
->pBtree
);
366 sqlite3_snprintf(sizeof(zBuf
),zBuf
, "%d", rc
);
367 Tcl_AppendResult(interp
, zBuf
, 0);
372 ** Usage: btree_payload_size ID
374 ** Return the number of bytes of payload
376 static int btree_payload_size(
378 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
379 int argc
, /* Number of arguments */
380 const char **argv
/* Text of each argument */
388 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
392 pCur
= sqlite3TestTextToPtr(argv
[1]);
393 sqlite3BtreeEnter(pCur
->pBtree
);
395 /* The cursor may be in "require-seek" state. If this is the case, the
396 ** call to BtreeDataSize() will fix it. */
397 sqlite3BtreeDataSize(pCur
, (u32
*)&n2
);
398 if( pCur
->apPage
[pCur
->iPage
]->intKey
){
401 sqlite3BtreeKeySize(pCur
, (i64
*)&n1
);
403 sqlite3BtreeLeave(pCur
->pBtree
);
404 sqlite3_snprintf(sizeof(zBuf
),zBuf
, "%d", (int)(n1
+n2
));
405 Tcl_AppendResult(interp
, zBuf
, 0);
410 ** usage: varint_test START MULTIPLIER COUNT INCREMENT
412 ** This command tests the putVarint() and getVarint()
413 ** routines, both for accuracy and for speed.
415 ** An integer is written using putVarint() and read back with
416 ** getVarint() and varified to be unchanged. This repeats COUNT
417 ** times. The first integer is START*MULTIPLIER. Each iteration
418 ** increases the integer by INCREMENT.
420 ** This command returns nothing if it works. It returns an error message
421 ** if something goes wrong.
423 static int btree_varint_test(
425 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
426 int argc
, /* Number of arguments */
427 const char **argv
/* Text of each argument */
429 u32 start
, mult
, count
, incr
;
432 unsigned char zBuf
[100];
434 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
435 " START MULTIPLIER COUNT INCREMENT\"", 0);
438 if( Tcl_GetInt(interp
, argv
[1], (int*)&start
) ) return TCL_ERROR
;
439 if( Tcl_GetInt(interp
, argv
[2], (int*)&mult
) ) return TCL_ERROR
;
440 if( Tcl_GetInt(interp
, argv
[3], (int*)&count
) ) return TCL_ERROR
;
441 if( Tcl_GetInt(interp
, argv
[4], (int*)&incr
) ) return TCL_ERROR
;
444 for(i
=0; i
<(int)count
; i
++){
446 n1
= putVarint(zBuf
, in
);
448 sprintf(zErr
, "putVarint returned %d - should be between 1 and 9", n1
);
449 Tcl_AppendResult(interp
, zErr
, 0);
452 n2
= getVarint(zBuf
, &out
);
454 sprintf(zErr
, "putVarint returned %d and getVarint returned %d", n1
, n2
);
455 Tcl_AppendResult(interp
, zErr
, 0);
459 sprintf(zErr
, "Wrote 0x%016llx and got back 0x%016llx", in
, out
);
460 Tcl_AppendResult(interp
, zErr
, 0);
463 if( (in
& 0xffffffff)==in
){
465 n2
= getVarint32(zBuf
, out32
);
468 sprintf(zErr
, "putVarint returned %d and GetVarint32 returned %d",
470 Tcl_AppendResult(interp
, zErr
, 0);
474 sprintf(zErr
, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
476 Tcl_AppendResult(interp
, zErr
, 0);
481 /* In order to get realistic timings, run getVarint 19 more times.
482 ** This is because getVarint is called about 20 times more often
486 getVarint(zBuf
, &out
);
494 ** usage: btree_from_db DB-HANDLE
496 ** This command returns the btree handle for the main database associated
497 ** with the database-handle passed as the argument. Example usage:
499 ** sqlite3 db test.db
500 ** set bt [btree_from_db db]
502 static int btree_from_db(
504 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
505 int argc
, /* Number of arguments */
506 const char **argv
/* Text of each argument */
514 if( argc
!=2 && argc
!=3 ){
515 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
516 " DB-HANDLE ?N?\"", 0);
520 if( 1!=Tcl_GetCommandInfo(interp
, argv
[1], &info
) ){
521 Tcl_AppendResult(interp
, "No such db-handle: \"", argv
[1], "\"", 0);
528 db
= *((sqlite3
**)info
.objClientData
);
531 pBt
= db
->aDb
[iDb
].pBt
;
532 sqlite3_snprintf(sizeof(zBuf
), zBuf
, "%p", pBt
);
533 Tcl_SetResult(interp
, zBuf
, TCL_VOLATILE
);
538 ** Usage: btree_ismemdb ID
540 ** Return true if the B-Tree is in-memory.
542 static int btree_ismemdb(
544 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
545 int argc
, /* Number of arguments */
546 const char **argv
/* Text of each argument */
552 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
556 pBt
= sqlite3TestTextToPtr(argv
[1]);
557 sqlite3_mutex_enter(pBt
->db
->mutex
);
558 sqlite3BtreeEnter(pBt
);
559 res
= sqlite3PagerIsMemdb(sqlite3BtreePager(pBt
));
560 sqlite3BtreeLeave(pBt
);
561 sqlite3_mutex_leave(pBt
->db
->mutex
);
562 Tcl_SetObjResult(interp
, Tcl_NewBooleanObj(res
));
567 ** usage: btree_set_cache_size ID NCACHE
569 ** Set the size of the cache used by btree $ID.
571 static int btree_set_cache_size(
573 Tcl_Interp
*interp
, /* The TCL interpreter that invoked this command */
574 int argc
, /* Number of arguments */
575 const char **argv
/* Text of each argument */
582 interp
, "wrong # args: should be \"", argv
[0], " BT NCACHE\"", 0);
585 pBt
= sqlite3TestTextToPtr(argv
[1]);
586 if( Tcl_GetInt(interp
, argv
[2], &nCache
) ) return TCL_ERROR
;
588 sqlite3_mutex_enter(pBt
->db
->mutex
);
589 sqlite3BtreeEnter(pBt
);
590 sqlite3BtreeSetCacheSize(pBt
, nCache
);
591 sqlite3BtreeLeave(pBt
);
592 sqlite3_mutex_leave(pBt
->db
->mutex
);
599 ** Register commands with the TCL interpreter.
601 int Sqlitetest3_Init(Tcl_Interp
*interp
){
606 { "btree_open", (Tcl_CmdProc
*)btree_open
},
607 { "btree_close", (Tcl_CmdProc
*)btree_close
},
608 { "btree_begin_transaction", (Tcl_CmdProc
*)btree_begin_transaction
},
609 { "btree_pager_stats", (Tcl_CmdProc
*)btree_pager_stats
},
610 { "btree_cursor", (Tcl_CmdProc
*)btree_cursor
},
611 { "btree_close_cursor", (Tcl_CmdProc
*)btree_close_cursor
},
612 { "btree_next", (Tcl_CmdProc
*)btree_next
},
613 { "btree_eof", (Tcl_CmdProc
*)btree_eof
},
614 { "btree_payload_size", (Tcl_CmdProc
*)btree_payload_size
},
615 { "btree_first", (Tcl_CmdProc
*)btree_first
},
616 { "btree_varint_test", (Tcl_CmdProc
*)btree_varint_test
},
617 { "btree_from_db", (Tcl_CmdProc
*)btree_from_db
},
618 { "btree_ismemdb", (Tcl_CmdProc
*)btree_ismemdb
},
619 { "btree_set_cache_size", (Tcl_CmdProc
*)btree_set_cache_size
}
623 for(i
=0; i
<sizeof(aCmd
)/sizeof(aCmd
[0]); i
++){
624 Tcl_CreateCommand(interp
, aCmd
[i
].zName
, aCmd
[i
].xProc
, 0, 0);