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