xref: /sqlite-3.40.0/src/test3.c (revision 20a35fd8)
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.109 2009/07/09 02:48:24 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( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
412     n1 = 0;
413   }else{
414     sqlite3BtreeKeySize(pCur, (i64*)&n1);
415   }
416   sqlite3BtreeDataSize(pCur, (u32*)&n2);
417   sqlite3BtreeLeave(pCur->pBtree);
418   sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
419   Tcl_AppendResult(interp, zBuf, 0);
420   return SQLITE_OK;
421 }
422 
423 /*
424 ** usage:   varint_test  START  MULTIPLIER  COUNT  INCREMENT
425 **
426 ** This command tests the putVarint() and getVarint()
427 ** routines, both for accuracy and for speed.
428 **
429 ** An integer is written using putVarint() and read back with
430 ** getVarint() and varified to be unchanged.  This repeats COUNT
431 ** times.  The first integer is START*MULTIPLIER.  Each iteration
432 ** increases the integer by INCREMENT.
433 **
434 ** This command returns nothing if it works.  It returns an error message
435 ** if something goes wrong.
436 */
437 static int btree_varint_test(
438   void *NotUsed,
439   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
440   int argc,              /* Number of arguments */
441   const char **argv      /* Text of each argument */
442 ){
443   u32 start, mult, count, incr;
444   u64 in, out;
445   int n1, n2, i, j;
446   unsigned char zBuf[100];
447   if( argc!=5 ){
448     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
449        " START MULTIPLIER COUNT INCREMENT\"", 0);
450     return TCL_ERROR;
451   }
452   if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
453   if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
454   if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
455   if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
456   in = start;
457   in *= mult;
458   for(i=0; i<count; i++){
459     char zErr[200];
460     n1 = putVarint(zBuf, in);
461     if( n1>9 || n1<1 ){
462       sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
463       Tcl_AppendResult(interp, zErr, 0);
464       return TCL_ERROR;
465     }
466     n2 = getVarint(zBuf, &out);
467     if( n1!=n2 ){
468       sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
469       Tcl_AppendResult(interp, zErr, 0);
470       return TCL_ERROR;
471     }
472     if( in!=out ){
473       sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
474       Tcl_AppendResult(interp, zErr, 0);
475       return TCL_ERROR;
476     }
477     if( (in & 0xffffffff)==in ){
478       u32 out32;
479       n2 = getVarint32(zBuf, out32);
480       out = out32;
481       if( n1!=n2 ){
482         sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d",
483                   n1, n2);
484         Tcl_AppendResult(interp, zErr, 0);
485         return TCL_ERROR;
486       }
487       if( in!=out ){
488         sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
489             in, out);
490         Tcl_AppendResult(interp, zErr, 0);
491         return TCL_ERROR;
492       }
493     }
494 
495     /* In order to get realistic timings, run getVarint 19 more times.
496     ** This is because getVarint is called about 20 times more often
497     ** than putVarint.
498     */
499     for(j=0; j<19; j++){
500       getVarint(zBuf, &out);
501     }
502     in += incr;
503   }
504   return TCL_OK;
505 }
506 
507 /*
508 ** usage:   btree_from_db  DB-HANDLE
509 **
510 ** This command returns the btree handle for the main database associated
511 ** with the database-handle passed as the argument. Example usage:
512 **
513 ** sqlite3 db test.db
514 ** set bt [btree_from_db db]
515 */
516 static int btree_from_db(
517   void *NotUsed,
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 */
521 ){
522   char zBuf[100];
523   Tcl_CmdInfo info;
524   sqlite3 *db;
525   Btree *pBt;
526   int iDb = 0;
527 
528   if( argc!=2 && argc!=3 ){
529     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
530        " DB-HANDLE ?N?\"", 0);
531     return TCL_ERROR;
532   }
533 
534   if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
535     Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
536     return TCL_ERROR;
537   }
538   if( argc==3 ){
539     iDb = atoi(argv[2]);
540   }
541 
542   db = *((sqlite3 **)info.objClientData);
543   assert( db );
544 
545   pBt = db->aDb[iDb].pBt;
546   sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
547   Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
548   return TCL_OK;
549 }
550 
551 /*
552 ** Usage:   btree_ismemdb ID
553 **
554 ** Return true if the B-Tree is in-memory.
555 */
556 static int btree_ismemdb(
557   void *NotUsed,
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 */
561 ){
562   Btree *pBt;
563   int res;
564 
565   if( argc!=2 ){
566     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
567        " ID\"", 0);
568     return TCL_ERROR;
569   }
570   pBt = sqlite3TestTextToPtr(argv[1]);
571   sqlite3_mutex_enter(pBt->db->mutex);
572   sqlite3BtreeEnter(pBt);
573   res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt));
574   sqlite3BtreeLeave(pBt);
575   sqlite3_mutex_leave(pBt->db->mutex);
576   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
577   return SQLITE_OK;
578 }
579 
580 
581 /*
582 ** Register commands with the TCL interpreter.
583 */
584 int Sqlitetest3_Init(Tcl_Interp *interp){
585   static struct {
586      char *zName;
587      Tcl_CmdProc *xProc;
588   } aCmd[] = {
589      { "btree_open",               (Tcl_CmdProc*)btree_open               },
590      { "btree_close",              (Tcl_CmdProc*)btree_close              },
591      { "btree_begin_transaction",  (Tcl_CmdProc*)btree_begin_transaction  },
592      { "btree_pager_stats",        (Tcl_CmdProc*)btree_pager_stats        },
593      { "btree_cursor",             (Tcl_CmdProc*)btree_cursor             },
594      { "btree_close_cursor",       (Tcl_CmdProc*)btree_close_cursor       },
595      { "btree_next",               (Tcl_CmdProc*)btree_next               },
596      { "btree_eof",                (Tcl_CmdProc*)btree_eof                },
597      { "btree_payload_size",       (Tcl_CmdProc*)btree_payload_size       },
598      { "btree_first",              (Tcl_CmdProc*)btree_first              },
599      { "btree_varint_test",        (Tcl_CmdProc*)btree_varint_test        },
600      { "btree_from_db",            (Tcl_CmdProc*)btree_from_db            },
601      { "btree_ismemdb",            (Tcl_CmdProc*)btree_ismemdb            }
602   };
603   int i;
604 
605   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
606     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
607   }
608 
609   return TCL_OK;
610 }
611