Add contributions section to README
[sqlcipher.git] / src / test3.c
blobe3ed310c8104fe3621cebb0f51d10145018d4fac
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.
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"
17 #include "btreeInt.h"
18 #include "tcl.h"
19 #include <stdlib.h>
20 #include <string.h>
22 extern const char *sqlite3ErrName(int);
25 ** A bogus sqlite3 connection structure for use in the btree
26 ** tests.
28 static sqlite3 sDb;
29 static int nRefSqlite3 = 0;
32 ** Usage: btree_open FILENAME NCACHE
34 ** Open a new database
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 */
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;
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);
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;
71 sqlite3BtreeSetCacheSize(pBt, nCache);
72 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
73 Tcl_AppendResult(interp, zBuf, 0);
74 return TCL_OK;
78 ** Usage: btree_close ID
80 ** Close the given database.
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 */
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;
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;
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;
108 return TCL_OK;
113 ** Usage: btree_begin_transaction ID
115 ** Start a new transaction
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 */
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;
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;
138 return TCL_OK;
142 ** Usage: btree_pager_stats ID
144 ** Returns pager statistics
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 */
152 Btree *pBt;
153 int i;
154 int *a;
156 if( argc!=2 ){
157 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
158 " ID\"", 0);
159 return TCL_ERROR;
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));
174 for(i=0; i<11; i++){
175 static char *zName[] = {
176 "ref", "page", "max", "size", "state", "err",
177 "hit", "miss", "ovfl", "read", "write"
179 char zBuf[100];
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);
188 return TCL_OK;
192 ** Usage: btree_cursor ID TABLENUM WRITEABLE
194 ** Create a new cursor. Return the ID for the cursor.
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 */
202 Btree *pBt;
203 int iTable;
204 BtCursor *pCur;
205 int rc = SQLITE_OK;
206 int wrFlag;
207 char zBuf[30];
209 if( argc!=4 ){
210 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
211 " ID TABLENUM WRITEABLE\"", 0);
212 return TCL_ERROR;
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);
222 #endif
223 if( rc==SQLITE_OK ){
224 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
226 sqlite3BtreeLeave(pBt);
227 if( rc ){
228 ckfree((char *)pCur);
229 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
230 return TCL_ERROR;
232 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
233 Tcl_AppendResult(interp, zBuf, 0);
234 return SQLITE_OK;
238 ** Usage: btree_close_cursor ID
240 ** Close a cursor opened using btree_cursor.
242 static int btree_close_cursor(
243 void *NotUsed,
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 */
248 BtCursor *pCur;
249 Btree *pBt;
250 int rc;
252 if( argc!=2 ){
253 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
254 " ID\"", 0);
255 return TCL_ERROR;
257 pCur = sqlite3TestTextToPtr(argv[1]);
258 pBt = pCur->pBtree;
259 sqlite3BtreeEnter(pBt);
260 rc = sqlite3BtreeCloseCursor(pCur);
261 sqlite3BtreeLeave(pBt);
262 ckfree((char *)pCur);
263 if( rc ){
264 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
265 return TCL_ERROR;
267 return SQLITE_OK;
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(
278 void *NotUsed,
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 */
283 BtCursor *pCur;
284 int rc;
285 int res = 0;
286 char zBuf[100];
288 if( argc!=2 ){
289 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
290 " ID\"", 0);
291 return TCL_ERROR;
293 pCur = sqlite3TestTextToPtr(argv[1]);
294 sqlite3BtreeEnter(pCur->pBtree);
295 rc = sqlite3BtreeNext(pCur, &res);
296 sqlite3BtreeLeave(pCur->pBtree);
297 if( rc ){
298 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
299 return TCL_ERROR;
301 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
302 Tcl_AppendResult(interp, zBuf, 0);
303 return SQLITE_OK;
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(
313 void *NotUsed,
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 */
318 BtCursor *pCur;
319 int rc;
320 int res = 0;
321 char zBuf[100];
323 if( argc!=2 ){
324 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
325 " ID\"", 0);
326 return TCL_ERROR;
328 pCur = sqlite3TestTextToPtr(argv[1]);
329 sqlite3BtreeEnter(pCur->pBtree);
330 rc = sqlite3BtreeFirst(pCur, &res);
331 sqlite3BtreeLeave(pCur->pBtree);
332 if( rc ){
333 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
334 return TCL_ERROR;
336 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
337 Tcl_AppendResult(interp, zBuf, 0);
338 return SQLITE_OK;
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(
348 void *NotUsed,
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 */
353 BtCursor *pCur;
354 int rc;
355 char zBuf[50];
357 if( argc!=2 ){
358 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
359 " ID\"", 0);
360 return TCL_ERROR;
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);
368 return SQLITE_OK;
372 ** Usage: btree_payload_size ID
374 ** Return the number of bytes of payload
376 static int btree_payload_size(
377 void *NotUsed,
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 */
382 BtCursor *pCur;
383 int n2;
384 u64 n1;
385 char zBuf[50];
387 if( argc!=2 ){
388 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
389 " ID\"", 0);
390 return TCL_ERROR;
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 ){
399 n1 = 0;
400 }else{
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);
406 return SQLITE_OK;
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(
424 void *NotUsed,
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;
430 u64 in, out;
431 int n1, n2, i, j;
432 unsigned char zBuf[100];
433 if( argc!=5 ){
434 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
435 " START MULTIPLIER COUNT INCREMENT\"", 0);
436 return TCL_ERROR;
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;
442 in = start;
443 in *= mult;
444 for(i=0; i<(int)count; i++){
445 char zErr[200];
446 n1 = putVarint(zBuf, in);
447 if( n1>9 || n1<1 ){
448 sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
449 Tcl_AppendResult(interp, zErr, 0);
450 return TCL_ERROR;
452 n2 = getVarint(zBuf, &out);
453 if( n1!=n2 ){
454 sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
455 Tcl_AppendResult(interp, zErr, 0);
456 return TCL_ERROR;
458 if( in!=out ){
459 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
460 Tcl_AppendResult(interp, zErr, 0);
461 return TCL_ERROR;
463 if( (in & 0xffffffff)==in ){
464 u32 out32;
465 n2 = getVarint32(zBuf, out32);
466 out = out32;
467 if( n1!=n2 ){
468 sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d",
469 n1, n2);
470 Tcl_AppendResult(interp, zErr, 0);
471 return TCL_ERROR;
473 if( in!=out ){
474 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
475 in, out);
476 Tcl_AppendResult(interp, zErr, 0);
477 return TCL_ERROR;
481 /* In order to get realistic timings, run getVarint 19 more times.
482 ** This is because getVarint is called about 20 times more often
483 ** than putVarint.
485 for(j=0; j<19; j++){
486 getVarint(zBuf, &out);
488 in += incr;
490 return TCL_OK;
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(
503 void *NotUsed,
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 */
508 char zBuf[100];
509 Tcl_CmdInfo info;
510 sqlite3 *db;
511 Btree *pBt;
512 int iDb = 0;
514 if( argc!=2 && argc!=3 ){
515 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
516 " DB-HANDLE ?N?\"", 0);
517 return TCL_ERROR;
520 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
521 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
522 return TCL_ERROR;
524 if( argc==3 ){
525 iDb = atoi(argv[2]);
528 db = *((sqlite3 **)info.objClientData);
529 assert( db );
531 pBt = db->aDb[iDb].pBt;
532 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
533 Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
534 return TCL_OK;
538 ** Usage: btree_ismemdb ID
540 ** Return true if the B-Tree is in-memory.
542 static int btree_ismemdb(
543 void *NotUsed,
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 */
548 Btree *pBt;
549 int res;
551 if( argc!=2 ){
552 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
553 " ID\"", 0);
554 return TCL_ERROR;
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));
563 return SQLITE_OK;
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(
572 void *NotUsed,
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 */
577 int nCache;
578 Btree *pBt;
580 if( argc!=3 ){
581 Tcl_AppendResult(
582 interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0);
583 return TCL_ERROR;
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);
593 return TCL_OK;
599 ** Register commands with the TCL interpreter.
601 int Sqlitetest3_Init(Tcl_Interp *interp){
602 static struct {
603 char *zName;
604 Tcl_CmdProc *xProc;
605 } aCmd[] = {
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 }
621 int i;
623 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
624 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
627 return TCL_OK;