fix issue with short page reads causing hmac failures with auto vacuum enabled
[sqlcipher.git] / src / test3.c
blobe460c42e46c092ae67572eeb59dce1bd2cc0d7ce
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>
23 ** Interpret an SQLite error number
25 static char *errorName(int rc){
26 char *zName;
27 switch( rc ){
28 case SQLITE_OK: zName = "SQLITE_OK"; break;
29 case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
30 case SQLITE_PERM: zName = "SQLITE_PERM"; break;
31 case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
32 case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
33 case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
34 case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
35 case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
36 case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
37 case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
38 case SQLITE_FULL: zName = "SQLITE_FULL"; break;
39 case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
40 case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
41 case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
42 case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
43 default: zName = "SQLITE_Unknown"; break;
45 return zName;
49 ** A bogus sqlite3 connection structure for use in the btree
50 ** tests.
52 static sqlite3 sDb;
53 static int nRefSqlite3 = 0;
56 ** Usage: btree_open FILENAME NCACHE
58 ** Open a new database
60 static int btree_open(
61 void *NotUsed,
62 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
63 int argc, /* Number of arguments */
64 const char **argv /* Text of each argument */
66 Btree *pBt;
67 int rc, nCache;
68 char zBuf[100];
69 int n;
70 char *zFilename;
71 if( argc!=3 ){
72 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
73 " FILENAME NCACHE FLAGS\"", 0);
74 return TCL_ERROR;
76 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
77 nRefSqlite3++;
78 if( nRefSqlite3==1 ){
79 sDb.pVfs = sqlite3_vfs_find(0);
80 sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
81 sqlite3_mutex_enter(sDb.mutex);
83 n = (int)strlen(argv[1]);
84 zFilename = sqlite3_malloc( n+2 );
85 if( zFilename==0 ) return TCL_ERROR;
86 memcpy(zFilename, argv[1], n+1);
87 zFilename[n+1] = 0;
88 rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0,
89 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
90 sqlite3_free(zFilename);
91 if( rc!=SQLITE_OK ){
92 Tcl_AppendResult(interp, errorName(rc), 0);
93 return TCL_ERROR;
95 sqlite3BtreeSetCacheSize(pBt, nCache);
96 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
97 Tcl_AppendResult(interp, zBuf, 0);
98 return TCL_OK;
102 ** Usage: btree_close ID
104 ** Close the given database.
106 static int btree_close(
107 void *NotUsed,
108 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
109 int argc, /* Number of arguments */
110 const char **argv /* Text of each argument */
112 Btree *pBt;
113 int rc;
114 if( argc!=2 ){
115 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
116 " ID\"", 0);
117 return TCL_ERROR;
119 pBt = sqlite3TestTextToPtr(argv[1]);
120 rc = sqlite3BtreeClose(pBt);
121 if( rc!=SQLITE_OK ){
122 Tcl_AppendResult(interp, errorName(rc), 0);
123 return TCL_ERROR;
125 nRefSqlite3--;
126 if( nRefSqlite3==0 ){
127 sqlite3_mutex_leave(sDb.mutex);
128 sqlite3_mutex_free(sDb.mutex);
129 sDb.mutex = 0;
130 sDb.pVfs = 0;
132 return TCL_OK;
137 ** Usage: btree_begin_transaction ID
139 ** Start a new transaction
141 static int btree_begin_transaction(
142 void *NotUsed,
143 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
144 int argc, /* Number of arguments */
145 const char **argv /* Text of each argument */
147 Btree *pBt;
148 int rc;
149 if( argc!=2 ){
150 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
151 " ID\"", 0);
152 return TCL_ERROR;
154 pBt = sqlite3TestTextToPtr(argv[1]);
155 sqlite3BtreeEnter(pBt);
156 rc = sqlite3BtreeBeginTrans(pBt, 1);
157 sqlite3BtreeLeave(pBt);
158 if( rc!=SQLITE_OK ){
159 Tcl_AppendResult(interp, errorName(rc), 0);
160 return TCL_ERROR;
162 return TCL_OK;
166 ** Usage: btree_pager_stats ID
168 ** Returns pager statistics
170 static int btree_pager_stats(
171 void *NotUsed,
172 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
173 int argc, /* Number of arguments */
174 const char **argv /* Text of each argument */
176 Btree *pBt;
177 int i;
178 int *a;
180 if( argc!=2 ){
181 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
182 " ID\"", 0);
183 return TCL_ERROR;
185 pBt = sqlite3TestTextToPtr(argv[1]);
187 /* Normally in this file, with a b-tree handle opened using the
188 ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
189 ** But this function is sometimes called with a btree handle obtained
190 ** from an open SQLite connection (using [btree_from_db]). In this case
191 ** we need to obtain the mutex for the controlling SQLite handle before
192 ** it is safe to call sqlite3BtreeEnter().
194 sqlite3_mutex_enter(pBt->db->mutex);
196 sqlite3BtreeEnter(pBt);
197 a = sqlite3PagerStats(sqlite3BtreePager(pBt));
198 for(i=0; i<11; i++){
199 static char *zName[] = {
200 "ref", "page", "max", "size", "state", "err",
201 "hit", "miss", "ovfl", "read", "write"
203 char zBuf[100];
204 Tcl_AppendElement(interp, zName[i]);
205 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
206 Tcl_AppendElement(interp, zBuf);
208 sqlite3BtreeLeave(pBt);
210 /* Release the mutex on the SQLite handle that controls this b-tree */
211 sqlite3_mutex_leave(pBt->db->mutex);
212 return TCL_OK;
216 ** Usage: btree_cursor ID TABLENUM WRITEABLE
218 ** Create a new cursor. Return the ID for the cursor.
220 static int btree_cursor(
221 void *NotUsed,
222 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
223 int argc, /* Number of arguments */
224 const char **argv /* Text of each argument */
226 Btree *pBt;
227 int iTable;
228 BtCursor *pCur;
229 int rc = SQLITE_OK;
230 int wrFlag;
231 char zBuf[30];
233 if( argc!=4 ){
234 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
235 " ID TABLENUM WRITEABLE\"", 0);
236 return TCL_ERROR;
238 pBt = sqlite3TestTextToPtr(argv[1]);
239 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
240 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
241 pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
242 memset(pCur, 0, sqlite3BtreeCursorSize());
243 sqlite3BtreeEnter(pBt);
244 #ifndef SQLITE_OMIT_SHARED_CACHE
245 rc = sqlite3BtreeLockTable(pBt, iTable, wrFlag);
246 #endif
247 if( rc==SQLITE_OK ){
248 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
250 sqlite3BtreeLeave(pBt);
251 if( rc ){
252 ckfree((char *)pCur);
253 Tcl_AppendResult(interp, errorName(rc), 0);
254 return TCL_ERROR;
256 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
257 Tcl_AppendResult(interp, zBuf, 0);
258 return SQLITE_OK;
262 ** Usage: btree_close_cursor ID
264 ** Close a cursor opened using btree_cursor.
266 static int btree_close_cursor(
267 void *NotUsed,
268 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
269 int argc, /* Number of arguments */
270 const char **argv /* Text of each argument */
272 BtCursor *pCur;
273 Btree *pBt;
274 int rc;
276 if( argc!=2 ){
277 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
278 " ID\"", 0);
279 return TCL_ERROR;
281 pCur = sqlite3TestTextToPtr(argv[1]);
282 pBt = pCur->pBtree;
283 sqlite3BtreeEnter(pBt);
284 rc = sqlite3BtreeCloseCursor(pCur);
285 sqlite3BtreeLeave(pBt);
286 ckfree((char *)pCur);
287 if( rc ){
288 Tcl_AppendResult(interp, errorName(rc), 0);
289 return TCL_ERROR;
291 return SQLITE_OK;
295 ** Usage: btree_next ID
297 ** Move the cursor to the next entry in the table. Return 0 on success
298 ** or 1 if the cursor was already on the last entry in the table or if
299 ** the table is empty.
301 static int btree_next(
302 void *NotUsed,
303 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
304 int argc, /* Number of arguments */
305 const char **argv /* Text of each argument */
307 BtCursor *pCur;
308 int rc;
309 int res = 0;
310 char zBuf[100];
312 if( argc!=2 ){
313 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
314 " ID\"", 0);
315 return TCL_ERROR;
317 pCur = sqlite3TestTextToPtr(argv[1]);
318 sqlite3BtreeEnter(pCur->pBtree);
319 rc = sqlite3BtreeNext(pCur, &res);
320 sqlite3BtreeLeave(pCur->pBtree);
321 if( rc ){
322 Tcl_AppendResult(interp, errorName(rc), 0);
323 return TCL_ERROR;
325 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
326 Tcl_AppendResult(interp, zBuf, 0);
327 return SQLITE_OK;
331 ** Usage: btree_first ID
333 ** Move the cursor to the first entry in the table. Return 0 if the
334 ** cursor was left point to something and 1 if the table is empty.
336 static int btree_first(
337 void *NotUsed,
338 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
339 int argc, /* Number of arguments */
340 const char **argv /* Text of each argument */
342 BtCursor *pCur;
343 int rc;
344 int res = 0;
345 char zBuf[100];
347 if( argc!=2 ){
348 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
349 " ID\"", 0);
350 return TCL_ERROR;
352 pCur = sqlite3TestTextToPtr(argv[1]);
353 sqlite3BtreeEnter(pCur->pBtree);
354 rc = sqlite3BtreeFirst(pCur, &res);
355 sqlite3BtreeLeave(pCur->pBtree);
356 if( rc ){
357 Tcl_AppendResult(interp, errorName(rc), 0);
358 return TCL_ERROR;
360 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
361 Tcl_AppendResult(interp, zBuf, 0);
362 return SQLITE_OK;
366 ** Usage: btree_eof ID
368 ** Return TRUE if the given cursor is not pointing at a valid entry.
369 ** Return FALSE if the cursor does point to a valid entry.
371 static int btree_eof(
372 void *NotUsed,
373 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
374 int argc, /* Number of arguments */
375 const char **argv /* Text of each argument */
377 BtCursor *pCur;
378 int rc;
379 char zBuf[50];
381 if( argc!=2 ){
382 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
383 " ID\"", 0);
384 return TCL_ERROR;
386 pCur = sqlite3TestTextToPtr(argv[1]);
387 sqlite3BtreeEnter(pCur->pBtree);
388 rc = sqlite3BtreeEof(pCur);
389 sqlite3BtreeLeave(pCur->pBtree);
390 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
391 Tcl_AppendResult(interp, zBuf, 0);
392 return SQLITE_OK;
396 ** Usage: btree_payload_size ID
398 ** Return the number of bytes of payload
400 static int btree_payload_size(
401 void *NotUsed,
402 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
403 int argc, /* Number of arguments */
404 const char **argv /* Text of each argument */
406 BtCursor *pCur;
407 int n2;
408 u64 n1;
409 char zBuf[50];
411 if( argc!=2 ){
412 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
413 " ID\"", 0);
414 return TCL_ERROR;
416 pCur = sqlite3TestTextToPtr(argv[1]);
417 sqlite3BtreeEnter(pCur->pBtree);
419 /* The cursor may be in "require-seek" state. If this is the case, the
420 ** call to BtreeDataSize() will fix it. */
421 sqlite3BtreeDataSize(pCur, (u32*)&n2);
422 if( pCur->apPage[pCur->iPage]->intKey ){
423 n1 = 0;
424 }else{
425 sqlite3BtreeKeySize(pCur, (i64*)&n1);
427 sqlite3BtreeLeave(pCur->pBtree);
428 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
429 Tcl_AppendResult(interp, zBuf, 0);
430 return SQLITE_OK;
434 ** usage: varint_test START MULTIPLIER COUNT INCREMENT
436 ** This command tests the putVarint() and getVarint()
437 ** routines, both for accuracy and for speed.
439 ** An integer is written using putVarint() and read back with
440 ** getVarint() and varified to be unchanged. This repeats COUNT
441 ** times. The first integer is START*MULTIPLIER. Each iteration
442 ** increases the integer by INCREMENT.
444 ** This command returns nothing if it works. It returns an error message
445 ** if something goes wrong.
447 static int btree_varint_test(
448 void *NotUsed,
449 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
450 int argc, /* Number of arguments */
451 const char **argv /* Text of each argument */
453 u32 start, mult, count, incr;
454 u64 in, out;
455 int n1, n2, i, j;
456 unsigned char zBuf[100];
457 if( argc!=5 ){
458 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
459 " START MULTIPLIER COUNT INCREMENT\"", 0);
460 return TCL_ERROR;
462 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
463 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
464 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
465 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
466 in = start;
467 in *= mult;
468 for(i=0; i<(int)count; i++){
469 char zErr[200];
470 n1 = putVarint(zBuf, in);
471 if( n1>9 || n1<1 ){
472 sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
473 Tcl_AppendResult(interp, zErr, 0);
474 return TCL_ERROR;
476 n2 = getVarint(zBuf, &out);
477 if( n1!=n2 ){
478 sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
479 Tcl_AppendResult(interp, zErr, 0);
480 return TCL_ERROR;
482 if( in!=out ){
483 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
484 Tcl_AppendResult(interp, zErr, 0);
485 return TCL_ERROR;
487 if( (in & 0xffffffff)==in ){
488 u32 out32;
489 n2 = getVarint32(zBuf, out32);
490 out = out32;
491 if( n1!=n2 ){
492 sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d",
493 n1, n2);
494 Tcl_AppendResult(interp, zErr, 0);
495 return TCL_ERROR;
497 if( in!=out ){
498 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
499 in, out);
500 Tcl_AppendResult(interp, zErr, 0);
501 return TCL_ERROR;
505 /* In order to get realistic timings, run getVarint 19 more times.
506 ** This is because getVarint is called about 20 times more often
507 ** than putVarint.
509 for(j=0; j<19; j++){
510 getVarint(zBuf, &out);
512 in += incr;
514 return TCL_OK;
518 ** usage: btree_from_db DB-HANDLE
520 ** This command returns the btree handle for the main database associated
521 ** with the database-handle passed as the argument. Example usage:
523 ** sqlite3 db test.db
524 ** set bt [btree_from_db db]
526 static int btree_from_db(
527 void *NotUsed,
528 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
529 int argc, /* Number of arguments */
530 const char **argv /* Text of each argument */
532 char zBuf[100];
533 Tcl_CmdInfo info;
534 sqlite3 *db;
535 Btree *pBt;
536 int iDb = 0;
538 if( argc!=2 && argc!=3 ){
539 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
540 " DB-HANDLE ?N?\"", 0);
541 return TCL_ERROR;
544 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
545 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
546 return TCL_ERROR;
548 if( argc==3 ){
549 iDb = atoi(argv[2]);
552 db = *((sqlite3 **)info.objClientData);
553 assert( db );
555 pBt = db->aDb[iDb].pBt;
556 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
557 Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
558 return TCL_OK;
562 ** Usage: btree_ismemdb ID
564 ** Return true if the B-Tree is in-memory.
566 static int btree_ismemdb(
567 void *NotUsed,
568 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
569 int argc, /* Number of arguments */
570 const char **argv /* Text of each argument */
572 Btree *pBt;
573 int res;
575 if( argc!=2 ){
576 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
577 " ID\"", 0);
578 return TCL_ERROR;
580 pBt = sqlite3TestTextToPtr(argv[1]);
581 sqlite3_mutex_enter(pBt->db->mutex);
582 sqlite3BtreeEnter(pBt);
583 res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt));
584 sqlite3BtreeLeave(pBt);
585 sqlite3_mutex_leave(pBt->db->mutex);
586 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
587 return SQLITE_OK;
591 ** usage: btree_set_cache_size ID NCACHE
593 ** Set the size of the cache used by btree $ID.
595 static int btree_set_cache_size(
596 void *NotUsed,
597 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
598 int argc, /* Number of arguments */
599 const char **argv /* Text of each argument */
601 int nCache;
602 Btree *pBt;
604 if( argc!=3 ){
605 Tcl_AppendResult(
606 interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0);
607 return TCL_ERROR;
609 pBt = sqlite3TestTextToPtr(argv[1]);
610 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
612 sqlite3_mutex_enter(pBt->db->mutex);
613 sqlite3BtreeEnter(pBt);
614 sqlite3BtreeSetCacheSize(pBt, nCache);
615 sqlite3BtreeLeave(pBt);
616 sqlite3_mutex_leave(pBt->db->mutex);
617 return TCL_OK;
623 ** Register commands with the TCL interpreter.
625 int Sqlitetest3_Init(Tcl_Interp *interp){
626 static struct {
627 char *zName;
628 Tcl_CmdProc *xProc;
629 } aCmd[] = {
630 { "btree_open", (Tcl_CmdProc*)btree_open },
631 { "btree_close", (Tcl_CmdProc*)btree_close },
632 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction },
633 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats },
634 { "btree_cursor", (Tcl_CmdProc*)btree_cursor },
635 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor },
636 { "btree_next", (Tcl_CmdProc*)btree_next },
637 { "btree_eof", (Tcl_CmdProc*)btree_eof },
638 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
639 { "btree_first", (Tcl_CmdProc*)btree_first },
640 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test },
641 { "btree_from_db", (Tcl_CmdProc*)btree_from_db },
642 { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb },
643 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }
645 int i;
647 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
648 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
651 return TCL_OK;