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