xref: /sqlite-3.40.0/src/test3.c (revision a3f06598)
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.103 2009/03/18 10:33:02 danielk1977 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_rollback ID
162 **
163 ** Rollback changes
164 */
165 static int btree_rollback(
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 rc;
173   if( argc!=2 ){
174     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
175        " ID\"", 0);
176     return TCL_ERROR;
177   }
178   pBt = sqlite3TestTextToPtr(argv[1]);
179   sqlite3BtreeEnter(pBt);
180   rc = sqlite3BtreeRollback(pBt);
181   sqlite3BtreeLeave(pBt);
182   if( rc!=SQLITE_OK ){
183     Tcl_AppendResult(interp, errorName(rc), 0);
184     return TCL_ERROR;
185   }
186   return TCL_OK;
187 }
188 
189 /*
190 ** Usage:   btree_commit ID
191 **
192 ** Commit all changes
193 */
194 static int btree_commit(
195   void *NotUsed,
196   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
197   int argc,              /* Number of arguments */
198   const char **argv      /* Text of each argument */
199 ){
200   Btree *pBt;
201   int rc;
202   if( argc!=2 ){
203     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
204        " ID\"", 0);
205     return TCL_ERROR;
206   }
207   pBt = sqlite3TestTextToPtr(argv[1]);
208   sqlite3BtreeEnter(pBt);
209   rc = sqlite3BtreeCommit(pBt);
210   sqlite3BtreeLeave(pBt);
211   if( rc!=SQLITE_OK ){
212     Tcl_AppendResult(interp, errorName(rc), 0);
213     return TCL_ERROR;
214   }
215   return TCL_OK;
216 }
217 
218 /*
219 ** Usage:   btree_begin_statement ID
220 **
221 ** Start a new statement transaction
222 */
223 static int btree_begin_statement(
224   void *NotUsed,
225   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
226   int argc,              /* Number of arguments */
227   const char **argv      /* Text of each argument */
228 ){
229   Btree *pBt;
230   int rc;
231   if( argc!=2 ){
232     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
233        " ID\"", 0);
234     return TCL_ERROR;
235   }
236   pBt = sqlite3TestTextToPtr(argv[1]);
237   sqlite3BtreeEnter(pBt);
238   rc = sqlite3BtreeBeginStmt(pBt, 1);
239   sqlite3BtreeLeave(pBt);
240   if( rc!=SQLITE_OK ){
241     Tcl_AppendResult(interp, errorName(rc), 0);
242     return TCL_ERROR;
243   }
244   return TCL_OK;
245 }
246 
247 /*
248 ** Usage:   btree_rollback_statement ID
249 **
250 ** Rollback changes
251 */
252 static int btree_rollback_statement(
253   void *NotUsed,
254   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
255   int argc,              /* Number of arguments */
256   const char **argv      /* Text of each argument */
257 ){
258   Btree *pBt;
259   int rc;
260   if( argc!=2 ){
261     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
262        " ID\"", 0);
263     return TCL_ERROR;
264   }
265   pBt = sqlite3TestTextToPtr(argv[1]);
266   sqlite3BtreeEnter(pBt);
267   rc = sqlite3BtreeSavepoint(pBt, SAVEPOINT_ROLLBACK, 0);
268   if( rc==SQLITE_OK ){
269     rc = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, 0);
270   }
271   sqlite3BtreeLeave(pBt);
272   if( rc!=SQLITE_OK ){
273     Tcl_AppendResult(interp, errorName(rc), 0);
274     return TCL_ERROR;
275   }
276   return TCL_OK;
277 }
278 
279 /*
280 ** Usage:   btree_commit_statement ID
281 **
282 ** Commit all changes
283 */
284 static int btree_commit_statement(
285   void *NotUsed,
286   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
287   int argc,              /* Number of arguments */
288   const char **argv      /* Text of each argument */
289 ){
290   Btree *pBt;
291   int rc;
292   if( argc!=2 ){
293     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
294        " ID\"", 0);
295     return TCL_ERROR;
296   }
297   pBt = sqlite3TestTextToPtr(argv[1]);
298   sqlite3BtreeEnter(pBt);
299   rc = sqlite3BtreeSavepoint(pBt, SAVEPOINT_RELEASE, 0);
300   sqlite3BtreeLeave(pBt);
301   if( rc!=SQLITE_OK ){
302     Tcl_AppendResult(interp, errorName(rc), 0);
303     return TCL_ERROR;
304   }
305   return TCL_OK;
306 }
307 
308 /*
309 ** Usage:   btree_create_table ID FLAGS
310 **
311 ** Create a new table in the database
312 */
313 static int btree_create_table(
314   void *NotUsed,
315   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
316   int argc,              /* Number of arguments */
317   const char **argv      /* Text of each argument */
318 ){
319   Btree *pBt;
320   int rc, iTable, flags;
321   char zBuf[30];
322   if( argc!=3 ){
323     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
324        " ID FLAGS\"", 0);
325     return TCL_ERROR;
326   }
327   pBt = sqlite3TestTextToPtr(argv[1]);
328   if( Tcl_GetInt(interp, argv[2], &flags) ) return TCL_ERROR;
329   sqlite3BtreeEnter(pBt);
330   rc = sqlite3BtreeCreateTable(pBt, &iTable, flags);
331   sqlite3BtreeLeave(pBt);
332   if( rc!=SQLITE_OK ){
333     Tcl_AppendResult(interp, errorName(rc), 0);
334     return TCL_ERROR;
335   }
336   sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iTable);
337   Tcl_AppendResult(interp, zBuf, 0);
338   return TCL_OK;
339 }
340 
341 /*
342 ** Usage:   btree_drop_table ID TABLENUM
343 **
344 ** Delete an entire table from the database
345 */
346 static int btree_drop_table(
347   void *NotUsed,
348   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
349   int argc,              /* Number of arguments */
350   const char **argv      /* Text of each argument */
351 ){
352   Btree *pBt;
353   int iTable;
354   int rc;
355   int notUsed1;
356   if( argc!=3 ){
357     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
358        " ID TABLENUM\"", 0);
359     return TCL_ERROR;
360   }
361   pBt = sqlite3TestTextToPtr(argv[1]);
362   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
363   sqlite3BtreeEnter(pBt);
364   rc = sqlite3BtreeDropTable(pBt, iTable, &notUsed1);
365   sqlite3BtreeLeave(pBt);
366   if( rc!=SQLITE_OK ){
367     Tcl_AppendResult(interp, errorName(rc), 0);
368     return TCL_ERROR;
369   }
370   return TCL_OK;
371 }
372 
373 /*
374 ** Usage:   btree_clear_table ID TABLENUM
375 **
376 ** Remove all entries from the given table but keep the table around.
377 */
378 static int btree_clear_table(
379   void *NotUsed,
380   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
381   int argc,              /* Number of arguments */
382   const char **argv      /* Text of each argument */
383 ){
384   Btree *pBt;
385   int iTable;
386   int rc;
387   if( argc!=3 ){
388     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
389        " ID TABLENUM\"", 0);
390     return TCL_ERROR;
391   }
392   pBt = sqlite3TestTextToPtr(argv[1]);
393   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
394   sqlite3BtreeEnter(pBt);
395   rc = sqlite3BtreeClearTable(pBt, iTable, 0);
396   sqlite3BtreeLeave(pBt);
397   if( rc!=SQLITE_OK ){
398     Tcl_AppendResult(interp, errorName(rc), 0);
399     return TCL_ERROR;
400   }
401   return TCL_OK;
402 }
403 
404 /*
405 ** Usage:   btree_get_meta ID
406 **
407 ** Return meta data
408 */
409 static int btree_get_meta(
410   void *NotUsed,
411   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
412   int argc,              /* Number of arguments */
413   const char **argv      /* Text of each argument */
414 ){
415   Btree *pBt;
416   int rc;
417   int i;
418   if( argc!=2 ){
419     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
420        " ID\"", 0);
421     return TCL_ERROR;
422   }
423   pBt = sqlite3TestTextToPtr(argv[1]);
424   for(i=0; i<SQLITE_N_BTREE_META; i++){
425     char zBuf[30];
426     u32 v;
427     sqlite3BtreeEnter(pBt);
428     rc = sqlite3BtreeGetMeta(pBt, i, &v);
429     sqlite3BtreeLeave(pBt);
430     if( rc!=SQLITE_OK ){
431       Tcl_AppendResult(interp, errorName(rc), 0);
432       return TCL_ERROR;
433     }
434     sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",v);
435     Tcl_AppendElement(interp, zBuf);
436   }
437   return TCL_OK;
438 }
439 
440 /*
441 ** Usage:   btree_update_meta ID METADATA...
442 **
443 ** Return meta data
444 */
445 static int btree_update_meta(
446   void *NotUsed,
447   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
448   int argc,              /* Number of arguments */
449   const char **argv      /* Text of each argument */
450 ){
451   Btree *pBt;
452   int rc;
453   int i;
454   int aMeta[SQLITE_N_BTREE_META];
455 
456   if( argc!=2+SQLITE_N_BTREE_META ){
457     char zBuf[30];
458     sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",SQLITE_N_BTREE_META);
459     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
460        " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0);
461     return TCL_ERROR;
462   }
463   pBt = sqlite3TestTextToPtr(argv[1]);
464   for(i=1; i<SQLITE_N_BTREE_META; i++){
465     if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR;
466   }
467   for(i=1; i<SQLITE_N_BTREE_META; i++){
468     sqlite3BtreeEnter(pBt);
469     rc = sqlite3BtreeUpdateMeta(pBt, i, aMeta[i]);
470     sqlite3BtreeLeave(pBt);
471     if( rc!=SQLITE_OK ){
472       Tcl_AppendResult(interp, errorName(rc), 0);
473       return TCL_ERROR;
474     }
475   }
476   return TCL_OK;
477 }
478 
479 /*
480 ** Usage:   btree_pager_stats ID
481 **
482 ** Returns pager statistics
483 */
484 static int btree_pager_stats(
485   void *NotUsed,
486   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
487   int argc,              /* Number of arguments */
488   const char **argv      /* Text of each argument */
489 ){
490   Btree *pBt;
491   int i;
492   int *a;
493 
494   if( argc!=2 ){
495     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
496        " ID\"", 0);
497     return TCL_ERROR;
498   }
499   pBt = sqlite3TestTextToPtr(argv[1]);
500 
501   /* Normally in this file, with a b-tree handle opened using the
502   ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
503   ** But this function is sometimes called with a btree handle obtained
504   ** from an open SQLite connection (using [btree_from_db]). In this case
505   ** we need to obtain the mutex for the controlling SQLite handle before
506   ** it is safe to call sqlite3BtreeEnter().
507   */
508   sqlite3_mutex_enter(pBt->db->mutex);
509 
510   sqlite3BtreeEnter(pBt);
511   a = sqlite3PagerStats(sqlite3BtreePager(pBt));
512   for(i=0; i<11; i++){
513     static char *zName[] = {
514       "ref", "page", "max", "size", "state", "err",
515       "hit", "miss", "ovfl", "read", "write"
516     };
517     char zBuf[100];
518     Tcl_AppendElement(interp, zName[i]);
519     sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
520     Tcl_AppendElement(interp, zBuf);
521   }
522   sqlite3BtreeLeave(pBt);
523 
524   /* Release the mutex on the SQLite handle that controls this b-tree */
525   sqlite3_mutex_leave(pBt->db->mutex);
526   return TCL_OK;
527 }
528 
529 /*
530 ** Usage:   btree_integrity_check ID ROOT ...
531 **
532 ** Look through every page of the given BTree file to verify correct
533 ** formatting and linkage.  Return a line of text for each problem found.
534 ** Return an empty string if everything worked.
535 */
536 static int btree_integrity_check(
537   void *NotUsed,
538   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
539   int argc,              /* Number of arguments */
540   const char **argv      /* Text of each argument */
541 ){
542   Btree *pBt;
543   int nRoot;
544   int *aRoot;
545   int i;
546   int nErr;
547   char *zResult;
548 
549   if( argc<3 ){
550     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
551        " ID ROOT ...\"", 0);
552     return TCL_ERROR;
553   }
554   pBt = sqlite3TestTextToPtr(argv[1]);
555   nRoot = argc-2;
556   aRoot = (int*)sqlite3_malloc( sizeof(int)*(argc-2) );
557   for(i=0; i<argc-2; i++){
558     if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
559   }
560 #ifndef SQLITE_OMIT_INTEGRITY_CHECK
561   sqlite3BtreeEnter(pBt);
562   zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
563   sqlite3BtreeLeave(pBt);
564 #else
565   zResult = 0;
566 #endif
567   sqlite3_free((void*)aRoot);
568   if( zResult ){
569     Tcl_AppendResult(interp, zResult, 0);
570     sqlite3_free(zResult);
571   }
572   return TCL_OK;
573 }
574 
575 /*
576 ** Usage:   btree_cursor_list ID
577 **
578 ** Print information about all cursors to standard output for debugging.
579 */
580 static int btree_cursor_list(
581   void *NotUsed,
582   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
583   int argc,              /* Number of arguments */
584   const char **argv      /* Text of each argument */
585 ){
586   Btree *pBt;
587 
588   if( argc!=2 ){
589     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
590        " ID\"", 0);
591     return TCL_ERROR;
592   }
593   pBt = sqlite3TestTextToPtr(argv[1]);
594   sqlite3BtreeEnter(pBt);
595   sqlite3BtreeCursorList(pBt);
596   sqlite3BtreeLeave(pBt);
597   return SQLITE_OK;
598 }
599 
600 /*
601 ** Usage:   btree_cursor ID TABLENUM WRITEABLE
602 **
603 ** Create a new cursor.  Return the ID for the cursor.
604 */
605 static int btree_cursor(
606   void *NotUsed,
607   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
608   int argc,              /* Number of arguments */
609   const char **argv      /* Text of each argument */
610 ){
611   Btree *pBt;
612   int iTable;
613   BtCursor *pCur;
614   int rc;
615   int wrFlag;
616   char zBuf[30];
617 
618   if( argc!=4 ){
619     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
620        " ID TABLENUM WRITEABLE\"", 0);
621     return TCL_ERROR;
622   }
623   pBt = sqlite3TestTextToPtr(argv[1]);
624   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
625   if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
626   pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
627   memset(pCur, 0, sqlite3BtreeCursorSize());
628   sqlite3BtreeEnter(pBt);
629   rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
630   sqlite3BtreeLeave(pBt);
631   if( rc ){
632     ckfree((char *)pCur);
633     Tcl_AppendResult(interp, errorName(rc), 0);
634     return TCL_ERROR;
635   }
636   sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
637   Tcl_AppendResult(interp, zBuf, 0);
638   return SQLITE_OK;
639 }
640 
641 /*
642 ** Usage:   btree_close_cursor ID
643 **
644 ** Close a cursor opened using btree_cursor.
645 */
646 static int btree_close_cursor(
647   void *NotUsed,
648   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
649   int argc,              /* Number of arguments */
650   const char **argv      /* Text of each argument */
651 ){
652   BtCursor *pCur;
653   Btree *pBt;
654   int rc;
655 
656   if( argc!=2 ){
657     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
658        " ID\"", 0);
659     return TCL_ERROR;
660   }
661   pCur = sqlite3TestTextToPtr(argv[1]);
662   pBt = pCur->pBtree;
663   sqlite3BtreeEnter(pBt);
664   rc = sqlite3BtreeCloseCursor(pCur);
665   sqlite3BtreeLeave(pBt);
666   ckfree((char *)pCur);
667   if( rc ){
668     Tcl_AppendResult(interp, errorName(rc), 0);
669     return TCL_ERROR;
670   }
671   return SQLITE_OK;
672 }
673 
674 /*
675 ** Usage:   btree_move_to ID KEY
676 **
677 ** Move the cursor to the entry with the given key.
678 */
679 static int btree_move_to(
680   void *NotUsed,
681   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
682   int argc,              /* Number of arguments */
683   const char **argv      /* Text of each argument */
684 ){
685   BtCursor *pCur;
686   int rc;
687   int res;
688   char zBuf[20];
689 
690   if( argc!=3 ){
691     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
692        " ID KEY\"", 0);
693     return TCL_ERROR;
694   }
695   pCur = sqlite3TestTextToPtr(argv[1]);
696   sqlite3BtreeEnter(pCur->pBtree);
697   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
698     int iKey;
699     if( Tcl_GetInt(interp, argv[2], &iKey) ){
700       sqlite3BtreeLeave(pCur->pBtree);
701       return TCL_ERROR;
702     }
703     rc = sqlite3BtreeMovetoUnpacked(pCur, 0, iKey, 0, &res);
704   }else{
705     rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res);
706   }
707   sqlite3BtreeLeave(pCur->pBtree);
708   if( rc ){
709     Tcl_AppendResult(interp, errorName(rc), 0);
710     return TCL_ERROR;
711   }
712   if( res<0 ) res = -1;
713   if( res>0 ) res = 1;
714   sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",res);
715   Tcl_AppendResult(interp, zBuf, 0);
716   return SQLITE_OK;
717 }
718 
719 /*
720 ** Usage:   btree_delete ID
721 **
722 ** Delete the entry that the cursor is pointing to
723 */
724 static int btree_delete(
725   void *NotUsed,
726   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
727   int argc,              /* Number of arguments */
728   const char **argv      /* Text of each argument */
729 ){
730   BtCursor *pCur;
731   int rc;
732 
733   if( argc!=2 ){
734     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
735        " ID\"", 0);
736     return TCL_ERROR;
737   }
738   pCur = sqlite3TestTextToPtr(argv[1]);
739   sqlite3BtreeEnter(pCur->pBtree);
740   rc = sqlite3BtreeDelete(pCur);
741   sqlite3BtreeLeave(pCur->pBtree);
742   if( rc ){
743     Tcl_AppendResult(interp, errorName(rc), 0);
744     return TCL_ERROR;
745   }
746   return SQLITE_OK;
747 }
748 
749 /*
750 ** Usage:   btree_insert ID KEY DATA ?NZERO?
751 **
752 ** Create a new entry with the given key and data.  If an entry already
753 ** exists with the same key the old entry is overwritten.
754 */
755 static int btree_insert(
756   void * clientData,
757   Tcl_Interp *interp,
758   int objc,
759   Tcl_Obj *CONST objv[]
760 ){
761   BtCursor *pCur;
762   int rc;
763   int nZero;
764 
765   if( objc!=4 && objc!=5 ){
766     Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA ?NZERO?");
767     return TCL_ERROR;
768   }
769   pCur = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
770   if( objc==5 ){
771     if( Tcl_GetIntFromObj(interp, objv[4], &nZero) ) return TCL_ERROR;
772   }else{
773     nZero = 0;
774   }
775   sqlite3BtreeEnter(pCur->pBtree);
776   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
777     i64 iKey;
778     int len;
779     unsigned char *pBuf;
780     if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ){
781       sqlite3BtreeLeave(pCur->pBtree);
782       return TCL_ERROR;
783     }
784     pBuf = Tcl_GetByteArrayFromObj(objv[3], &len);
785     rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0);
786   }else{
787     int keylen;
788     int dlen;
789     unsigned char *pKBuf;
790     unsigned char *pDBuf;
791     pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen);
792     pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen);
793     rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, nZero, 0);
794   }
795   sqlite3BtreeLeave(pCur->pBtree);
796   if( rc ){
797     Tcl_AppendResult(interp, errorName(rc), 0);
798     return TCL_ERROR;
799   }
800   return SQLITE_OK;
801 }
802 
803 /*
804 ** Usage:   btree_next ID
805 **
806 ** Move the cursor to the next entry in the table.  Return 0 on success
807 ** or 1 if the cursor was already on the last entry in the table or if
808 ** the table is empty.
809 */
810 static int btree_next(
811   void *NotUsed,
812   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
813   int argc,              /* Number of arguments */
814   const char **argv      /* Text of each argument */
815 ){
816   BtCursor *pCur;
817   int rc;
818   int res = 0;
819   char zBuf[100];
820 
821   if( argc!=2 ){
822     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
823        " ID\"", 0);
824     return TCL_ERROR;
825   }
826   pCur = sqlite3TestTextToPtr(argv[1]);
827   sqlite3BtreeEnter(pCur->pBtree);
828   rc = sqlite3BtreeNext(pCur, &res);
829   sqlite3BtreeLeave(pCur->pBtree);
830   if( rc ){
831     Tcl_AppendResult(interp, errorName(rc), 0);
832     return TCL_ERROR;
833   }
834   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
835   Tcl_AppendResult(interp, zBuf, 0);
836   return SQLITE_OK;
837 }
838 
839 /*
840 ** Usage:   btree_prev ID
841 **
842 ** Move the cursor to the previous entry in the table.  Return 0 on
843 ** success and 1 if the cursor was already on the first entry in
844 ** the table or if the table was empty.
845 */
846 static int btree_prev(
847   void *NotUsed,
848   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
849   int argc,              /* Number of arguments */
850   const char **argv      /* Text of each argument */
851 ){
852   BtCursor *pCur;
853   int rc;
854   int res = 0;
855   char zBuf[100];
856 
857   if( argc!=2 ){
858     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
859        " ID\"", 0);
860     return TCL_ERROR;
861   }
862   pCur = sqlite3TestTextToPtr(argv[1]);
863   sqlite3BtreeEnter(pCur->pBtree);
864   rc = sqlite3BtreePrevious(pCur, &res);
865   sqlite3BtreeLeave(pCur->pBtree);
866   if( rc ){
867     Tcl_AppendResult(interp, errorName(rc), 0);
868     return TCL_ERROR;
869   }
870   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
871   Tcl_AppendResult(interp, zBuf, 0);
872   return SQLITE_OK;
873 }
874 
875 /*
876 ** Usage:   btree_first ID
877 **
878 ** Move the cursor to the first entry in the table.  Return 0 if the
879 ** cursor was left point to something and 1 if the table is empty.
880 */
881 static int btree_first(
882   void *NotUsed,
883   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
884   int argc,              /* Number of arguments */
885   const char **argv      /* Text of each argument */
886 ){
887   BtCursor *pCur;
888   int rc;
889   int res = 0;
890   char zBuf[100];
891 
892   if( argc!=2 ){
893     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
894        " ID\"", 0);
895     return TCL_ERROR;
896   }
897   pCur = sqlite3TestTextToPtr(argv[1]);
898   sqlite3BtreeEnter(pCur->pBtree);
899   rc = sqlite3BtreeFirst(pCur, &res);
900   sqlite3BtreeLeave(pCur->pBtree);
901   if( rc ){
902     Tcl_AppendResult(interp, errorName(rc), 0);
903     return TCL_ERROR;
904   }
905   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
906   Tcl_AppendResult(interp, zBuf, 0);
907   return SQLITE_OK;
908 }
909 
910 /*
911 ** Usage:   btree_last ID
912 **
913 ** Move the cursor to the last entry in the table.  Return 0 if the
914 ** cursor was left point to something and 1 if the table is empty.
915 */
916 static int btree_last(
917   void *NotUsed,
918   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
919   int argc,              /* Number of arguments */
920   const char **argv      /* Text of each argument */
921 ){
922   BtCursor *pCur;
923   int rc;
924   int res = 0;
925   char zBuf[100];
926 
927   if( argc!=2 ){
928     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
929        " ID\"", 0);
930     return TCL_ERROR;
931   }
932   pCur = sqlite3TestTextToPtr(argv[1]);
933   sqlite3BtreeEnter(pCur->pBtree);
934   rc = sqlite3BtreeLast(pCur, &res);
935   sqlite3BtreeLeave(pCur->pBtree);
936   if( rc ){
937     Tcl_AppendResult(interp, errorName(rc), 0);
938     return TCL_ERROR;
939   }
940   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
941   Tcl_AppendResult(interp, zBuf, 0);
942   return SQLITE_OK;
943 }
944 
945 /*
946 ** Usage:   btree_eof ID
947 **
948 ** Return TRUE if the given cursor is not pointing at a valid entry.
949 ** Return FALSE if the cursor does point to a valid entry.
950 */
951 static int btree_eof(
952   void *NotUsed,
953   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
954   int argc,              /* Number of arguments */
955   const char **argv      /* Text of each argument */
956 ){
957   BtCursor *pCur;
958   int rc;
959   char zBuf[50];
960 
961   if( argc!=2 ){
962     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
963        " ID\"", 0);
964     return TCL_ERROR;
965   }
966   pCur = sqlite3TestTextToPtr(argv[1]);
967   sqlite3BtreeEnter(pCur->pBtree);
968   rc = sqlite3BtreeEof(pCur);
969   sqlite3BtreeLeave(pCur->pBtree);
970   sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
971   Tcl_AppendResult(interp, zBuf, 0);
972   return SQLITE_OK;
973 }
974 
975 /*
976 ** Usage:   btree_keysize ID
977 **
978 ** Return the number of bytes of key.  For an INTKEY table, this
979 ** returns the key itself.
980 */
981 static int btree_keysize(
982   void *NotUsed,
983   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
984   int argc,              /* Number of arguments */
985   const char **argv      /* Text of each argument */
986 ){
987   BtCursor *pCur;
988   u64 n;
989   char zBuf[50];
990 
991   if( argc!=2 ){
992     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
993        " ID\"", 0);
994     return TCL_ERROR;
995   }
996   pCur = sqlite3TestTextToPtr(argv[1]);
997   sqlite3BtreeEnter(pCur->pBtree);
998   sqlite3BtreeKeySize(pCur, (i64*)&n);
999   sqlite3BtreeLeave(pCur->pBtree);
1000   sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n);
1001   Tcl_AppendResult(interp, zBuf, 0);
1002   return SQLITE_OK;
1003 }
1004 
1005 /*
1006 ** Usage:   btree_key ID
1007 **
1008 ** Return the key for the entry at which the cursor is pointing.
1009 */
1010 static int btree_key(
1011   void *NotUsed,
1012   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1013   int argc,              /* Number of arguments */
1014   const char **argv      /* Text of each argument */
1015 ){
1016   BtCursor *pCur;
1017   int rc;
1018   u64 n;
1019   char *zBuf;
1020 
1021   if( argc!=2 ){
1022     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1023        " ID\"", 0);
1024     return TCL_ERROR;
1025   }
1026   pCur = sqlite3TestTextToPtr(argv[1]);
1027   sqlite3BtreeEnter(pCur->pBtree);
1028   sqlite3BtreeKeySize(pCur, (i64*)&n);
1029   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
1030     char zBuf2[60];
1031     sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n);
1032     Tcl_AppendResult(interp, zBuf2, 0);
1033   }else{
1034     zBuf = sqlite3_malloc( n+1 );
1035     rc = sqlite3BtreeKey(pCur, 0, n, zBuf);
1036     if( rc ){
1037       sqlite3BtreeLeave(pCur->pBtree);
1038       Tcl_AppendResult(interp, errorName(rc), 0);
1039       return TCL_ERROR;
1040     }
1041     zBuf[n] = 0;
1042     Tcl_AppendResult(interp, zBuf, 0);
1043     sqlite3_free(zBuf);
1044   }
1045   sqlite3BtreeLeave(pCur->pBtree);
1046   return SQLITE_OK;
1047 }
1048 
1049 /*
1050 ** Usage:   btree_data ID ?N?
1051 **
1052 ** Return the data for the entry at which the cursor is pointing.
1053 */
1054 static int btree_data(
1055   void *NotUsed,
1056   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1057   int argc,              /* Number of arguments */
1058   const char **argv      /* Text of each argument */
1059 ){
1060   BtCursor *pCur;
1061   int rc;
1062   u32 n;
1063   char *zBuf;
1064 
1065   if( argc!=2 && argc!=3 ){
1066     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1067        " ID\"", 0);
1068     return TCL_ERROR;
1069   }
1070   pCur = sqlite3TestTextToPtr(argv[1]);
1071   sqlite3BtreeEnter(pCur->pBtree);
1072   if( argc==2 ){
1073     sqlite3BtreeDataSize(pCur, &n);
1074   }else{
1075     n = atoi(argv[2]);
1076   }
1077   zBuf = sqlite3_malloc( n+1 );
1078   rc = sqlite3BtreeData(pCur, 0, n, zBuf);
1079   sqlite3BtreeLeave(pCur->pBtree);
1080   if( rc ){
1081     Tcl_AppendResult(interp, errorName(rc), 0);
1082     sqlite3_free(zBuf);
1083     return TCL_ERROR;
1084   }
1085   zBuf[n] = 0;
1086   Tcl_AppendResult(interp, zBuf, 0);
1087   sqlite3_free(zBuf);
1088   return SQLITE_OK;
1089 }
1090 
1091 /*
1092 ** Usage:   btree_fetch_key ID AMT
1093 **
1094 ** Use the sqlite3BtreeKeyFetch() routine to get AMT bytes of the key.
1095 ** If sqlite3BtreeKeyFetch() fails, return an empty string.
1096 */
1097 static int btree_fetch_key(
1098   void *NotUsed,
1099   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1100   int argc,              /* Number of arguments */
1101   const char **argv      /* Text of each argument */
1102 ){
1103   BtCursor *pCur;
1104   int n;
1105   int amt;
1106   u64 nKey;
1107   const char *zBuf;
1108   char zStatic[1000];
1109 
1110   if( argc!=3 ){
1111     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1112        " ID AMT\"", 0);
1113     return TCL_ERROR;
1114   }
1115   pCur = sqlite3TestTextToPtr(argv[1]);
1116   if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
1117   sqlite3BtreeEnter(pCur->pBtree);
1118   sqlite3BtreeKeySize(pCur, (i64*)&nKey);
1119   zBuf = sqlite3BtreeKeyFetch(pCur, &amt);
1120   if( zBuf && amt>=n ){
1121     assert( nKey<sizeof(zStatic) );
1122     if( n>0 ) nKey = n;
1123     memcpy(zStatic, zBuf, (int)nKey);
1124     zStatic[nKey] = 0;
1125     Tcl_AppendResult(interp, zStatic, 0);
1126   }
1127   sqlite3BtreeLeave(pCur->pBtree);
1128   return TCL_OK;
1129 }
1130 
1131 /*
1132 ** Usage:   btree_fetch_data ID AMT
1133 **
1134 ** Use the sqlite3BtreeDataFetch() routine to get AMT bytes of the key.
1135 ** If sqlite3BtreeDataFetch() fails, return an empty string.
1136 */
1137 static int btree_fetch_data(
1138   void *NotUsed,
1139   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1140   int argc,              /* Number of arguments */
1141   const char **argv      /* Text of each argument */
1142 ){
1143   BtCursor *pCur;
1144   int n;
1145   int amt;
1146   u32 nData;
1147   const char *zBuf;
1148   char zStatic[1000];
1149 
1150   if( argc!=3 ){
1151     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1152        " ID AMT\"", 0);
1153     return TCL_ERROR;
1154   }
1155   pCur = sqlite3TestTextToPtr(argv[1]);
1156   if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
1157   sqlite3BtreeEnter(pCur->pBtree);
1158   sqlite3BtreeDataSize(pCur, &nData);
1159   zBuf = sqlite3BtreeDataFetch(pCur, &amt);
1160   if( zBuf && amt>=n ){
1161     assert( nData<sizeof(zStatic) );
1162     if( n>0 ) nData = n;
1163     memcpy(zStatic, zBuf, (int)nData);
1164     zStatic[nData] = 0;
1165     Tcl_AppendResult(interp, zStatic, 0);
1166   }
1167   sqlite3BtreeLeave(pCur->pBtree);
1168   return TCL_OK;
1169 }
1170 
1171 /*
1172 ** Usage:   btree_payload_size ID
1173 **
1174 ** Return the number of bytes of payload
1175 */
1176 static int btree_payload_size(
1177   void *NotUsed,
1178   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1179   int argc,              /* Number of arguments */
1180   const char **argv      /* Text of each argument */
1181 ){
1182   BtCursor *pCur;
1183   int n2;
1184   u64 n1;
1185   char zBuf[50];
1186 
1187   if( argc!=2 ){
1188     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1189        " ID\"", 0);
1190     return TCL_ERROR;
1191   }
1192   pCur = sqlite3TestTextToPtr(argv[1]);
1193   sqlite3BtreeEnter(pCur->pBtree);
1194   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
1195     n1 = 0;
1196   }else{
1197     sqlite3BtreeKeySize(pCur, (i64*)&n1);
1198   }
1199   sqlite3BtreeDataSize(pCur, (u32*)&n2);
1200   sqlite3BtreeLeave(pCur->pBtree);
1201   sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
1202   Tcl_AppendResult(interp, zBuf, 0);
1203   return SQLITE_OK;
1204 }
1205 
1206 /*
1207 ** Usage:   btree_cursor_info ID ?UP-CNT?
1208 **
1209 ** Return integers containing information about the entry the
1210 ** cursor is pointing to:
1211 **
1212 **   aResult[0] =  The page number
1213 **   aResult[1] =  The entry number
1214 **   aResult[2] =  Total number of entries on this page
1215 **   aResult[3] =  Cell size (local payload + header)
1216 **   aResult[4] =  Number of free bytes on this page
1217 **   aResult[5] =  Number of free blocks on the page
1218 **   aResult[6] =  Total payload size (local + overflow)
1219 **   aResult[7] =  Header size in bytes
1220 **   aResult[8] =  Local payload size
1221 **   aResult[9] =  Parent page number
1222 **   aResult[10]=  Page number of the first overflow page
1223 */
1224 static int btree_cursor_info(
1225   void *NotUsed,
1226   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1227   int argc,              /* Number of arguments */
1228   const char **argv      /* Text of each argument */
1229 ){
1230   BtCursor *pCur;
1231   int rc;
1232   int i, j;
1233   int up;
1234   int aResult[11];
1235   char zBuf[400];
1236 
1237   if( argc!=2 && argc!=3 ){
1238     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1239        " ID ?UP-CNT?\"", 0);
1240     return TCL_ERROR;
1241   }
1242   pCur = sqlite3TestTextToPtr(argv[1]);
1243   if( argc==3 ){
1244     if( Tcl_GetInt(interp, argv[2], &up) ) return TCL_ERROR;
1245   }else{
1246     up = 0;
1247   }
1248   sqlite3BtreeEnter(pCur->pBtree);
1249   rc = sqlite3BtreeCursorInfo(pCur, aResult, up);
1250   if( rc ){
1251     Tcl_AppendResult(interp, errorName(rc), 0);
1252     sqlite3BtreeLeave(pCur->pBtree);
1253     return TCL_ERROR;
1254   }
1255   j = 0;
1256   for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){
1257     sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]);
1258     j += strlen(&zBuf[j]);
1259   }
1260   sqlite3BtreeLeave(pCur->pBtree);
1261   Tcl_AppendResult(interp, &zBuf[1], 0);
1262   return SQLITE_OK;
1263 }
1264 
1265 /*
1266 ** Copied from btree.c:
1267 */
1268 static u32 t4Get4byte(unsigned char *p){
1269   return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
1270 }
1271 
1272 /*
1273 **   btree_ovfl_info  BTREE  CURSOR
1274 **
1275 ** Given a cursor, return the sequence of pages number that form the
1276 ** overflow pages for the data of the entry that the cursor is point
1277 ** to.
1278 */
1279 static int btree_ovfl_info(
1280   void *NotUsed,
1281   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1282   int argc,              /* Number of arguments */
1283   const char **argv      /* Text of each argument */
1284 ){
1285   Btree *pBt;
1286   BtCursor *pCur;
1287   Pager *pPager;
1288   int rc;
1289   int n;
1290   int dataSize;
1291   u32 pgno;
1292   void *pPage;
1293   int aResult[11];
1294   char zElem[100];
1295   Tcl_DString str;
1296 
1297   if( argc!=3 ){
1298     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1299                     " BTREE CURSOR", 0);
1300     return TCL_ERROR;
1301   }
1302   pBt = sqlite3TestTextToPtr(argv[1]);
1303   pCur = sqlite3TestTextToPtr(argv[2]);
1304   if( (*(void**)pCur) != (void*)pBt ){
1305     Tcl_AppendResult(interp, "Cursor ", argv[2], " does not belong to btree ",
1306        argv[1], 0);
1307     return TCL_ERROR;
1308   }
1309   sqlite3BtreeEnter(pBt);
1310   pPager = sqlite3BtreePager(pBt);
1311   rc = sqlite3BtreeCursorInfo(pCur, aResult, 0);
1312   if( rc ){
1313     Tcl_AppendResult(interp, errorName(rc), 0);
1314     sqlite3BtreeLeave(pBt);
1315     return TCL_ERROR;
1316   }
1317   dataSize = pBt->pBt->usableSize;
1318   Tcl_DStringInit(&str);
1319   n = aResult[6] - aResult[8];
1320   n = (n + dataSize - 1)/dataSize;
1321   pgno = (u32)aResult[10];
1322   while( pgno && n-- ){
1323     DbPage *pDbPage;
1324     sprintf(zElem, "%d", pgno);
1325     Tcl_DStringAppendElement(&str, zElem);
1326     if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){
1327       Tcl_DStringFree(&str);
1328       Tcl_AppendResult(interp, "unable to get page ", zElem, 0);
1329       sqlite3BtreeLeave(pBt);
1330       return TCL_ERROR;
1331     }
1332     pPage = sqlite3PagerGetData(pDbPage);
1333     pgno = t4Get4byte((unsigned char*)pPage);
1334     sqlite3PagerUnref(pDbPage);
1335   }
1336   sqlite3BtreeLeave(pBt);
1337   Tcl_DStringResult(interp, &str);
1338   return SQLITE_OK;
1339 }
1340 
1341 /*
1342 ** The command is provided for the purpose of setting breakpoints.
1343 ** in regression test scripts.
1344 **
1345 ** By setting a GDB breakpoint on this procedure and executing the
1346 ** btree_breakpoint command in a test script, we can stop GDB at
1347 ** the point in the script where the btree_breakpoint command is
1348 ** inserted.  This is useful for debugging.
1349 */
1350 static int btree_breakpoint(
1351   void *NotUsed,
1352   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1353   int argc,              /* Number of arguments */
1354   const char **argv      /* Text of each argument */
1355 ){
1356   return TCL_OK;
1357 }
1358 
1359 /*
1360 ** usage:   varint_test  START  MULTIPLIER  COUNT  INCREMENT
1361 **
1362 ** This command tests the putVarint() and getVarint()
1363 ** routines, both for accuracy and for speed.
1364 **
1365 ** An integer is written using putVarint() and read back with
1366 ** getVarint() and varified to be unchanged.  This repeats COUNT
1367 ** times.  The first integer is START*MULTIPLIER.  Each iteration
1368 ** increases the integer by INCREMENT.
1369 **
1370 ** This command returns nothing if it works.  It returns an error message
1371 ** if something goes wrong.
1372 */
1373 static int btree_varint_test(
1374   void *NotUsed,
1375   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1376   int argc,              /* Number of arguments */
1377   const char **argv      /* Text of each argument */
1378 ){
1379   u32 start, mult, count, incr;
1380   u64 in, out;
1381   int n1, n2, i, j;
1382   unsigned char zBuf[100];
1383   if( argc!=5 ){
1384     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1385        " START MULTIPLIER COUNT INCREMENT\"", 0);
1386     return TCL_ERROR;
1387   }
1388   if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
1389   if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
1390   if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
1391   if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
1392   in = start;
1393   in *= mult;
1394   for(i=0; i<count; i++){
1395     char zErr[200];
1396     n1 = putVarint(zBuf, in);
1397     if( n1>9 || n1<1 ){
1398       sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
1399       Tcl_AppendResult(interp, zErr, 0);
1400       return TCL_ERROR;
1401     }
1402     n2 = getVarint(zBuf, &out);
1403     if( n1!=n2 ){
1404       sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
1405       Tcl_AppendResult(interp, zErr, 0);
1406       return TCL_ERROR;
1407     }
1408     if( in!=out ){
1409       sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
1410       Tcl_AppendResult(interp, zErr, 0);
1411       return TCL_ERROR;
1412     }
1413     if( (in & 0xffffffff)==in ){
1414       u32 out32;
1415       n2 = getVarint32(zBuf, out32);
1416       out = out32;
1417       if( n1!=n2 ){
1418         sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d",
1419                   n1, n2);
1420         Tcl_AppendResult(interp, zErr, 0);
1421         return TCL_ERROR;
1422       }
1423       if( in!=out ){
1424         sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
1425             in, out);
1426         Tcl_AppendResult(interp, zErr, 0);
1427         return TCL_ERROR;
1428       }
1429     }
1430 
1431     /* In order to get realistic timings, run getVarint 19 more times.
1432     ** This is because getVarint is called about 20 times more often
1433     ** than putVarint.
1434     */
1435     for(j=0; j<19; j++){
1436       getVarint(zBuf, &out);
1437     }
1438     in += incr;
1439   }
1440   return TCL_OK;
1441 }
1442 
1443 /*
1444 ** usage:   btree_from_db  DB-HANDLE
1445 **
1446 ** This command returns the btree handle for the main database associated
1447 ** with the database-handle passed as the argument. Example usage:
1448 **
1449 ** sqlite3 db test.db
1450 ** set bt [btree_from_db db]
1451 */
1452 static int btree_from_db(
1453   void *NotUsed,
1454   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1455   int argc,              /* Number of arguments */
1456   const char **argv      /* Text of each argument */
1457 ){
1458   char zBuf[100];
1459   Tcl_CmdInfo info;
1460   sqlite3 *db;
1461   Btree *pBt;
1462   int iDb = 0;
1463 
1464   if( argc!=2 && argc!=3 ){
1465     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1466        " DB-HANDLE ?N?\"", 0);
1467     return TCL_ERROR;
1468   }
1469 
1470   if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
1471     Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
1472     return TCL_ERROR;
1473   }
1474   if( argc==3 ){
1475     iDb = atoi(argv[2]);
1476   }
1477 
1478   db = *((sqlite3 **)info.objClientData);
1479   assert( db );
1480 
1481   pBt = db->aDb[iDb].pBt;
1482   sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
1483   Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
1484   return TCL_OK;
1485 }
1486 
1487 
1488 /*
1489 ** usage:   btree_set_cache_size ID NCACHE
1490 **
1491 ** Set the size of the cache used by btree $ID.
1492 */
1493 static int btree_set_cache_size(
1494   void *NotUsed,
1495   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1496   int argc,              /* Number of arguments */
1497   const char **argv      /* Text of each argument */
1498 ){
1499   int nCache;
1500   Btree *pBt;
1501 
1502   if( argc!=3 ){
1503     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1504        " BT NCACHE\"", 0);
1505     return TCL_ERROR;
1506   }
1507   pBt = sqlite3TestTextToPtr(argv[1]);
1508   if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
1509 
1510   sqlite3_mutex_enter(pBt->db->mutex);
1511   sqlite3BtreeEnter(pBt);
1512   sqlite3BtreeSetCacheSize(pBt, nCache);
1513   sqlite3BtreeLeave(pBt);
1514   sqlite3_mutex_leave(pBt->db->mutex);
1515 
1516   return TCL_OK;
1517 }
1518 
1519 /*
1520 ** Usage:   btree_ismemdb ID
1521 **
1522 ** Return true if the B-Tree is in-memory.
1523 */
1524 static int btree_ismemdb(
1525   void *NotUsed,
1526   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1527   int argc,              /* Number of arguments */
1528   const char **argv      /* Text of each argument */
1529 ){
1530   Btree *pBt;
1531   int res;
1532 
1533   if( argc!=2 ){
1534     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1535        " ID\"", 0);
1536     return TCL_ERROR;
1537   }
1538   pBt = sqlite3TestTextToPtr(argv[1]);
1539   sqlite3_mutex_enter(pBt->db->mutex);
1540   sqlite3BtreeEnter(pBt);
1541   res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt));
1542   sqlite3BtreeLeave(pBt);
1543   sqlite3_mutex_leave(pBt->db->mutex);
1544   Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
1545   return SQLITE_OK;
1546 }
1547 
1548 
1549 /*
1550 ** Register commands with the TCL interpreter.
1551 */
1552 int Sqlitetest3_Init(Tcl_Interp *interp){
1553   static struct {
1554      char *zName;
1555      Tcl_CmdProc *xProc;
1556   } aCmd[] = {
1557      { "btree_open",               (Tcl_CmdProc*)btree_open               },
1558      { "btree_close",              (Tcl_CmdProc*)btree_close              },
1559      { "btree_begin_transaction",  (Tcl_CmdProc*)btree_begin_transaction  },
1560      { "btree_commit",             (Tcl_CmdProc*)btree_commit             },
1561      { "btree_rollback",           (Tcl_CmdProc*)btree_rollback           },
1562      { "btree_create_table",       (Tcl_CmdProc*)btree_create_table       },
1563      { "btree_drop_table",         (Tcl_CmdProc*)btree_drop_table         },
1564      { "btree_clear_table",        (Tcl_CmdProc*)btree_clear_table        },
1565      { "btree_get_meta",           (Tcl_CmdProc*)btree_get_meta           },
1566      { "btree_update_meta",        (Tcl_CmdProc*)btree_update_meta        },
1567      { "btree_pager_stats",        (Tcl_CmdProc*)btree_pager_stats        },
1568      { "btree_cursor",             (Tcl_CmdProc*)btree_cursor             },
1569      { "btree_close_cursor",       (Tcl_CmdProc*)btree_close_cursor       },
1570      { "btree_move_to",            (Tcl_CmdProc*)btree_move_to            },
1571      { "btree_delete",             (Tcl_CmdProc*)btree_delete             },
1572      { "btree_next",               (Tcl_CmdProc*)btree_next               },
1573      { "btree_prev",               (Tcl_CmdProc*)btree_prev               },
1574      { "btree_eof",                (Tcl_CmdProc*)btree_eof                },
1575      { "btree_keysize",            (Tcl_CmdProc*)btree_keysize            },
1576      { "btree_key",                (Tcl_CmdProc*)btree_key                },
1577      { "btree_data",               (Tcl_CmdProc*)btree_data               },
1578      { "btree_fetch_key",          (Tcl_CmdProc*)btree_fetch_key          },
1579      { "btree_fetch_data",         (Tcl_CmdProc*)btree_fetch_data         },
1580      { "btree_payload_size",       (Tcl_CmdProc*)btree_payload_size       },
1581      { "btree_first",              (Tcl_CmdProc*)btree_first              },
1582      { "btree_last",               (Tcl_CmdProc*)btree_last               },
1583      { "btree_integrity_check",    (Tcl_CmdProc*)btree_integrity_check    },
1584      { "btree_breakpoint",         (Tcl_CmdProc*)btree_breakpoint         },
1585      { "btree_varint_test",        (Tcl_CmdProc*)btree_varint_test        },
1586      { "btree_begin_statement",    (Tcl_CmdProc*)btree_begin_statement    },
1587      { "btree_commit_statement",   (Tcl_CmdProc*)btree_commit_statement   },
1588      { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
1589      { "btree_from_db",            (Tcl_CmdProc*)btree_from_db            },
1590      { "btree_set_cache_size",     (Tcl_CmdProc*)btree_set_cache_size     },
1591      { "btree_cursor_info",        (Tcl_CmdProc*)btree_cursor_info        },
1592      { "btree_ovfl_info",          (Tcl_CmdProc*)btree_ovfl_info          },
1593      { "btree_cursor_list",        (Tcl_CmdProc*)btree_cursor_list        },
1594      { "btree_ismemdb",            (Tcl_CmdProc*)btree_ismemdb            },
1595   };
1596   int i;
1597 
1598   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
1599     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
1600   }
1601 
1602   /* The btree_insert command is implemented using the tcl 'object'
1603   ** interface, not the string interface like the other commands in this
1604   ** file. This is so binary data can be inserted into btree tables.
1605   */
1606   Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0);
1607   return TCL_OK;
1608 }
1609