xref: /sqlite-3.40.0/src/test3.c (revision 74217cc0)
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.62 2005/08/11 02:10:19 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], &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   char *zResult;
571 
572   if( argc<3 ){
573     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
574        " ID ROOT ...\"", 0);
575     return TCL_ERROR;
576   }
577   pBt = sqlite3TextToPtr(argv[1]);
578   nRoot = argc-2;
579   aRoot = malloc( sizeof(int)*(argc-2) );
580   for(i=0; i<argc-2; i++){
581     if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
582   }
583 #ifndef SQLITE_OMIT_INTEGRITY_CHECK
584   zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot);
585 #else
586   zResult = 0;
587 #endif
588   if( zResult ){
589     Tcl_AppendResult(interp, zResult, 0);
590     sqliteFree(zResult);
591   }
592   return TCL_OK;
593 }
594 
595 /*
596 ** Usage:   btree_cursor_list ID
597 **
598 ** Print information about all cursors to standard output for debugging.
599 */
600 static int btree_cursor_list(
601   void *NotUsed,
602   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
603   int argc,              /* Number of arguments */
604   const char **argv      /* Text of each argument */
605 ){
606   Btree *pBt;
607 
608   if( argc!=2 ){
609     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
610        " ID\"", 0);
611     return TCL_ERROR;
612   }
613   pBt = sqlite3TextToPtr(argv[1]);
614   sqlite3BtreeCursorList(pBt);
615   return SQLITE_OK;
616 }
617 
618 /*
619 ** Usage:   btree_cursor ID TABLENUM WRITEABLE
620 **
621 ** Create a new cursor.  Return the ID for the cursor.
622 */
623 static int btree_cursor(
624   void *NotUsed,
625   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
626   int argc,              /* Number of arguments */
627   const char **argv      /* Text of each argument */
628 ){
629   Btree *pBt;
630   int iTable;
631   BtCursor *pCur;
632   int rc;
633   int wrFlag;
634   char zBuf[30];
635 
636   if( argc!=4 ){
637     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
638        " ID TABLENUM WRITEABLE\"", 0);
639     return TCL_ERROR;
640   }
641   pBt = sqlite3TextToPtr(argv[1]);
642   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
643   if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
644   rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, 0, &pCur);
645   if( rc ){
646     Tcl_AppendResult(interp, errorName(rc), 0);
647     return TCL_ERROR;
648   }
649   sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
650   Tcl_AppendResult(interp, zBuf, 0);
651   return SQLITE_OK;
652 }
653 
654 /*
655 ** Usage:   btree_close_cursor ID
656 **
657 ** Close a cursor opened using btree_cursor.
658 */
659 static int btree_close_cursor(
660   void *NotUsed,
661   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
662   int argc,              /* Number of arguments */
663   const char **argv      /* Text of each argument */
664 ){
665   BtCursor *pCur;
666   int rc;
667 
668   if( argc!=2 ){
669     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
670        " ID\"", 0);
671     return TCL_ERROR;
672   }
673   pCur = sqlite3TextToPtr(argv[1]);
674   rc = sqlite3BtreeCloseCursor(pCur);
675   if( rc ){
676     Tcl_AppendResult(interp, errorName(rc), 0);
677     return TCL_ERROR;
678   }
679   return SQLITE_OK;
680 }
681 
682 /*
683 ** Usage:   btree_move_to ID KEY
684 **
685 ** Move the cursor to the entry with the given key.
686 */
687 static int btree_move_to(
688   void *NotUsed,
689   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
690   int argc,              /* Number of arguments */
691   const char **argv      /* Text of each argument */
692 ){
693   BtCursor *pCur;
694   int rc;
695   int res;
696   char zBuf[20];
697 
698   if( argc!=3 ){
699     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
700        " ID KEY\"", 0);
701     return TCL_ERROR;
702   }
703   pCur = sqlite3TextToPtr(argv[1]);
704   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
705     int iKey;
706     if( Tcl_GetInt(interp, argv[2], &iKey) ) return TCL_ERROR;
707     rc = sqlite3BtreeMoveto(pCur, 0, iKey, &res);
708   }else{
709     rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), &res);
710   }
711   if( rc ){
712     Tcl_AppendResult(interp, errorName(rc), 0);
713     return TCL_ERROR;
714   }
715   if( res<0 ) res = -1;
716   if( res>0 ) res = 1;
717   sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",res);
718   Tcl_AppendResult(interp, zBuf, 0);
719   return SQLITE_OK;
720 }
721 
722 /*
723 ** Usage:   btree_delete ID
724 **
725 ** Delete the entry that the cursor is pointing to
726 */
727 static int btree_delete(
728   void *NotUsed,
729   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
730   int argc,              /* Number of arguments */
731   const char **argv      /* Text of each argument */
732 ){
733   BtCursor *pCur;
734   int rc;
735 
736   if( argc!=2 ){
737     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
738        " ID\"", 0);
739     return TCL_ERROR;
740   }
741   pCur = sqlite3TextToPtr(argv[1]);
742   rc = sqlite3BtreeDelete(pCur);
743   if( rc ){
744     Tcl_AppendResult(interp, errorName(rc), 0);
745     return TCL_ERROR;
746   }
747   return SQLITE_OK;
748 }
749 
750 /*
751 ** Usage:   btree_insert ID KEY DATA
752 **
753 ** Create a new entry with the given key and data.  If an entry already
754 ** exists with the same key the old entry is overwritten.
755 */
756 static int btree_insert(
757   void * clientData,
758   Tcl_Interp *interp,
759   int objc,
760   Tcl_Obj *CONST objv[]
761 ){
762   BtCursor *pCur;
763   int rc;
764 
765   if( objc!=4 ){
766     Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA");
767     return TCL_ERROR;
768   }
769   pCur = sqlite3TextToPtr(Tcl_GetString(objv[1]));
770   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
771     i64 iKey;
772     int len;
773     unsigned char *pBuf;
774     if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR;
775     pBuf = Tcl_GetByteArrayFromObj(objv[3], &len);
776     rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len);
777   }else{
778     int keylen;
779     int dlen;
780     unsigned char *pKBuf;
781     unsigned char *pDBuf;
782     pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen);
783     pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen);
784     rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen);
785   }
786   if( rc ){
787     Tcl_AppendResult(interp, errorName(rc), 0);
788     return TCL_ERROR;
789   }
790   return SQLITE_OK;
791 }
792 
793 /*
794 ** Usage:   btree_next ID
795 **
796 ** Move the cursor to the next entry in the table.  Return 0 on success
797 ** or 1 if the cursor was already on the last entry in the table or if
798 ** the table is empty.
799 */
800 static int btree_next(
801   void *NotUsed,
802   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
803   int argc,              /* Number of arguments */
804   const char **argv      /* Text of each argument */
805 ){
806   BtCursor *pCur;
807   int rc;
808   int res = 0;
809   char zBuf[100];
810 
811   if( argc!=2 ){
812     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
813        " ID\"", 0);
814     return TCL_ERROR;
815   }
816   pCur = sqlite3TextToPtr(argv[1]);
817   rc = sqlite3BtreeNext(pCur, &res);
818   if( rc ){
819     Tcl_AppendResult(interp, errorName(rc), 0);
820     return TCL_ERROR;
821   }
822   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
823   Tcl_AppendResult(interp, zBuf, 0);
824   return SQLITE_OK;
825 }
826 
827 /*
828 ** Usage:   btree_prev ID
829 **
830 ** Move the cursor to the previous entry in the table.  Return 0 on
831 ** success and 1 if the cursor was already on the first entry in
832 ** the table or if the table was empty.
833 */
834 static int btree_prev(
835   void *NotUsed,
836   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
837   int argc,              /* Number of arguments */
838   const char **argv      /* Text of each argument */
839 ){
840   BtCursor *pCur;
841   int rc;
842   int res = 0;
843   char zBuf[100];
844 
845   if( argc!=2 ){
846     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
847        " ID\"", 0);
848     return TCL_ERROR;
849   }
850   pCur = sqlite3TextToPtr(argv[1]);
851   rc = sqlite3BtreePrevious(pCur, &res);
852   if( rc ){
853     Tcl_AppendResult(interp, errorName(rc), 0);
854     return TCL_ERROR;
855   }
856   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
857   Tcl_AppendResult(interp, zBuf, 0);
858   return SQLITE_OK;
859 }
860 
861 /*
862 ** Usage:   btree_first ID
863 **
864 ** Move the cursor to the first entry in the table.  Return 0 if the
865 ** cursor was left point to something and 1 if the table is empty.
866 */
867 static int btree_first(
868   void *NotUsed,
869   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
870   int argc,              /* Number of arguments */
871   const char **argv      /* Text of each argument */
872 ){
873   BtCursor *pCur;
874   int rc;
875   int res = 0;
876   char zBuf[100];
877 
878   if( argc!=2 ){
879     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
880        " ID\"", 0);
881     return TCL_ERROR;
882   }
883   pCur = sqlite3TextToPtr(argv[1]);
884   rc = sqlite3BtreeFirst(pCur, &res);
885   if( rc ){
886     Tcl_AppendResult(interp, errorName(rc), 0);
887     return TCL_ERROR;
888   }
889   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
890   Tcl_AppendResult(interp, zBuf, 0);
891   return SQLITE_OK;
892 }
893 
894 /*
895 ** Usage:   btree_last ID
896 **
897 ** Move the cursor to the last entry in the table.  Return 0 if the
898 ** cursor was left point to something and 1 if the table is empty.
899 */
900 static int btree_last(
901   void *NotUsed,
902   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
903   int argc,              /* Number of arguments */
904   const char **argv      /* Text of each argument */
905 ){
906   BtCursor *pCur;
907   int rc;
908   int res = 0;
909   char zBuf[100];
910 
911   if( argc!=2 ){
912     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
913        " ID\"", 0);
914     return TCL_ERROR;
915   }
916   pCur = sqlite3TextToPtr(argv[1]);
917   rc = sqlite3BtreeLast(pCur, &res);
918   if( rc ){
919     Tcl_AppendResult(interp, errorName(rc), 0);
920     return TCL_ERROR;
921   }
922   sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
923   Tcl_AppendResult(interp, zBuf, 0);
924   return SQLITE_OK;
925 }
926 
927 /*
928 ** Usage:   btree_eof ID
929 **
930 ** Return TRUE if the given cursor is not pointing at a valid entry.
931 ** Return FALSE if the cursor does point to a valid entry.
932 */
933 static int btree_eof(
934   void *NotUsed,
935   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
936   int argc,              /* Number of arguments */
937   const char **argv      /* Text of each argument */
938 ){
939   BtCursor *pCur;
940   char zBuf[50];
941 
942   if( argc!=2 ){
943     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
944        " ID\"", 0);
945     return TCL_ERROR;
946   }
947   pCur = sqlite3TextToPtr(argv[1]);
948   sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", sqlite3BtreeEof(pCur));
949   Tcl_AppendResult(interp, zBuf, 0);
950   return SQLITE_OK;
951 }
952 
953 /*
954 ** Usage:   btree_keysize ID
955 **
956 ** Return the number of bytes of key.  For an INTKEY table, this
957 ** returns the key itself.
958 */
959 static int btree_keysize(
960   void *NotUsed,
961   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
962   int argc,              /* Number of arguments */
963   const char **argv      /* Text of each argument */
964 ){
965   BtCursor *pCur;
966   u64 n;
967   char zBuf[50];
968 
969   if( argc!=2 ){
970     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
971        " ID\"", 0);
972     return TCL_ERROR;
973   }
974   pCur = sqlite3TextToPtr(argv[1]);
975   sqlite3BtreeKeySize(pCur, &n);
976   sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n);
977   Tcl_AppendResult(interp, zBuf, 0);
978   return SQLITE_OK;
979 }
980 
981 /*
982 ** Usage:   btree_key ID
983 **
984 ** Return the key for the entry at which the cursor is pointing.
985 */
986 static int btree_key(
987   void *NotUsed,
988   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
989   int argc,              /* Number of arguments */
990   const char **argv      /* Text of each argument */
991 ){
992   BtCursor *pCur;
993   int rc;
994   u64 n;
995   char *zBuf;
996 
997   if( argc!=2 ){
998     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
999        " ID\"", 0);
1000     return TCL_ERROR;
1001   }
1002   pCur = sqlite3TextToPtr(argv[1]);
1003   sqlite3BtreeKeySize(pCur, &n);
1004   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
1005     char zBuf2[60];
1006     sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n);
1007     Tcl_AppendResult(interp, zBuf2, 0);
1008   }else{
1009     zBuf = malloc( n+1 );
1010     rc = sqlite3BtreeKey(pCur, 0, n, zBuf);
1011     if( rc ){
1012       Tcl_AppendResult(interp, errorName(rc), 0);
1013       return TCL_ERROR;
1014     }
1015     zBuf[n] = 0;
1016     Tcl_AppendResult(interp, zBuf, 0);
1017     free(zBuf);
1018   }
1019   return SQLITE_OK;
1020 }
1021 
1022 /*
1023 ** Usage:   btree_data ID ?N?
1024 **
1025 ** Return the data for the entry at which the cursor is pointing.
1026 */
1027 static int btree_data(
1028   void *NotUsed,
1029   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1030   int argc,              /* Number of arguments */
1031   const char **argv      /* Text of each argument */
1032 ){
1033   BtCursor *pCur;
1034   int rc;
1035   u32 n;
1036   char *zBuf;
1037 
1038   if( argc!=2 && argc!=3 ){
1039     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1040        " ID\"", 0);
1041     return TCL_ERROR;
1042   }
1043   pCur = sqlite3TextToPtr(argv[1]);
1044   if( argc==2 ){
1045     sqlite3BtreeDataSize(pCur, &n);
1046   }else{
1047     n = atoi(argv[2]);
1048   }
1049   zBuf = malloc( n+1 );
1050   rc = sqlite3BtreeData(pCur, 0, n, zBuf);
1051   if( rc ){
1052     Tcl_AppendResult(interp, errorName(rc), 0);
1053     return TCL_ERROR;
1054   }
1055   zBuf[n] = 0;
1056   Tcl_AppendResult(interp, zBuf, 0);
1057   free(zBuf);
1058   return SQLITE_OK;
1059 }
1060 
1061 /*
1062 ** Usage:   btree_fetch_key ID AMT
1063 **
1064 ** Use the sqlite3BtreeKeyFetch() routine to get AMT bytes of the key.
1065 ** If sqlite3BtreeKeyFetch() fails, return an empty string.
1066 */
1067 static int btree_fetch_key(
1068   void *NotUsed,
1069   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1070   int argc,              /* Number of arguments */
1071   const char **argv      /* Text of each argument */
1072 ){
1073   BtCursor *pCur;
1074   int n;
1075   int amt;
1076   u64 nKey;
1077   const char *zBuf;
1078   char zStatic[1000];
1079 
1080   if( argc!=3 ){
1081     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1082        " ID AMT\"", 0);
1083     return TCL_ERROR;
1084   }
1085   pCur = sqlite3TextToPtr(argv[1]);
1086   if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
1087   sqlite3BtreeKeySize(pCur, &nKey);
1088   zBuf = sqlite3BtreeKeyFetch(pCur, &amt);
1089   if( zBuf && amt>=n ){
1090     assert( nKey<sizeof(zStatic) );
1091     if( n>0 ) nKey = n;
1092     memcpy(zStatic, zBuf, (int)nKey);
1093     zStatic[nKey] = 0;
1094     Tcl_AppendResult(interp, zStatic, 0);
1095   }
1096   return TCL_OK;
1097 }
1098 
1099 /*
1100 ** Usage:   btree_fetch_data ID AMT
1101 **
1102 ** Use the sqlite3BtreeDataFetch() routine to get AMT bytes of the key.
1103 ** If sqlite3BtreeDataFetch() fails, return an empty string.
1104 */
1105 static int btree_fetch_data(
1106   void *NotUsed,
1107   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1108   int argc,              /* Number of arguments */
1109   const char **argv      /* Text of each argument */
1110 ){
1111   BtCursor *pCur;
1112   int n;
1113   int amt;
1114   u32 nData;
1115   const char *zBuf;
1116   char zStatic[1000];
1117 
1118   if( argc!=3 ){
1119     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1120        " ID AMT\"", 0);
1121     return TCL_ERROR;
1122   }
1123   pCur = sqlite3TextToPtr(argv[1]);
1124   if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
1125   sqlite3BtreeDataSize(pCur, &nData);
1126   zBuf = sqlite3BtreeDataFetch(pCur, &amt);
1127   if( zBuf && amt>=n ){
1128     assert( nData<sizeof(zStatic) );
1129     if( n>0 ) nData = n;
1130     memcpy(zStatic, zBuf, (int)nData);
1131     zStatic[nData] = 0;
1132     Tcl_AppendResult(interp, zStatic, 0);
1133   }
1134   return TCL_OK;
1135 }
1136 
1137 /*
1138 ** Usage:   btree_payload_size ID
1139 **
1140 ** Return the number of bytes of payload
1141 */
1142 static int btree_payload_size(
1143   void *NotUsed,
1144   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1145   int argc,              /* Number of arguments */
1146   const char **argv      /* Text of each argument */
1147 ){
1148   BtCursor *pCur;
1149   int n2;
1150   u64 n1;
1151   char zBuf[50];
1152 
1153   if( argc!=2 ){
1154     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1155        " ID\"", 0);
1156     return TCL_ERROR;
1157   }
1158   pCur = sqlite3TextToPtr(argv[1]);
1159   if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
1160     n1 = 0;
1161   }else{
1162     sqlite3BtreeKeySize(pCur, &n1);
1163   }
1164   sqlite3BtreeDataSize(pCur, &n2);
1165   sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
1166   Tcl_AppendResult(interp, zBuf, 0);
1167   return SQLITE_OK;
1168 }
1169 
1170 /*
1171 ** Usage:   btree_cursor_info ID ?UP-CNT?
1172 **
1173 ** Return integers containing information about the entry the
1174 ** cursor is pointing to:
1175 **
1176 **   aResult[0] =  The page number
1177 **   aResult[1] =  The entry number
1178 **   aResult[2] =  Total number of entries on this page
1179 **   aResult[3] =  Cell size (local payload + header)
1180 **   aResult[4] =  Number of free bytes on this page
1181 **   aResult[5] =  Number of free blocks on the page
1182 **   aResult[6] =  Total payload size (local + overflow)
1183 **   aResult[7] =  Header size in bytes
1184 **   aResult[8] =  Local payload size
1185 **   aResult[9] =  Parent page number
1186 */
1187 static int btree_cursor_info(
1188   void *NotUsed,
1189   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1190   int argc,              /* Number of arguments */
1191   const char **argv      /* Text of each argument */
1192 ){
1193   BtCursor *pCur;
1194   int rc;
1195   int i, j;
1196   int up;
1197   int aResult[10];
1198   char zBuf[400];
1199 
1200   if( argc!=2 && argc!=3 ){
1201     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1202        " ID ?UP-CNT?\"", 0);
1203     return TCL_ERROR;
1204   }
1205   pCur = sqlite3TextToPtr(argv[1]);
1206   if( argc==3 ){
1207     if( Tcl_GetInt(interp, argv[2], &up) ) return TCL_ERROR;
1208   }else{
1209     up = 0;
1210   }
1211   rc = sqlite3BtreeCursorInfo(pCur, aResult, up);
1212   if( rc ){
1213     Tcl_AppendResult(interp, errorName(rc), 0);
1214     return TCL_ERROR;
1215   }
1216   j = 0;
1217   for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){
1218     sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]);
1219     j += strlen(&zBuf[j]);
1220   }
1221   Tcl_AppendResult(interp, &zBuf[1], 0);
1222   return SQLITE_OK;
1223 }
1224 
1225 /*
1226 ** The command is provided for the purpose of setting breakpoints.
1227 ** in regression test scripts.
1228 **
1229 ** By setting a GDB breakpoint on this procedure and executing the
1230 ** btree_breakpoint command in a test script, we can stop GDB at
1231 ** the point in the script where the btree_breakpoint command is
1232 ** inserted.  This is useful for debugging.
1233 */
1234 static int btree_breakpoint(
1235   void *NotUsed,
1236   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1237   int argc,              /* Number of arguments */
1238   const char **argv      /* Text of each argument */
1239 ){
1240   return TCL_OK;
1241 }
1242 
1243 /*
1244 ** usage:   varint_test  START  MULTIPLIER  COUNT  INCREMENT
1245 **
1246 ** This command tests the sqlite3PutVarint() and sqlite3GetVarint()
1247 ** routines, both for accuracy and for speed.
1248 **
1249 ** An integer is written using PutVarint() and read back with
1250 ** GetVarint() and varified to be unchanged.  This repeats COUNT
1251 ** times.  The first integer is START*MULTIPLIER.  Each iteration
1252 ** increases the integer by INCREMENT.
1253 **
1254 ** This command returns nothing if it works.  It returns an error message
1255 ** if something goes wrong.
1256 */
1257 static int btree_varint_test(
1258   void *NotUsed,
1259   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1260   int argc,              /* Number of arguments */
1261   const char **argv      /* Text of each argument */
1262 ){
1263   u32 start, mult, count, incr;
1264   u64 in, out;
1265   int n1, n2, i, j;
1266   unsigned char zBuf[100];
1267   if( argc!=5 ){
1268     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1269        " START MULTIPLIER COUNT INCREMENT\"", 0);
1270     return TCL_ERROR;
1271   }
1272   if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
1273   if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
1274   if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
1275   if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
1276   in = start;
1277   in *= mult;
1278   for(i=0; i<count; i++){
1279     char zErr[200];
1280     n1 = sqlite3PutVarint(zBuf, in);
1281     if( n1>9 || n1<1 ){
1282       sprintf(zErr, "PutVarint returned %d - should be between 1 and 9", n1);
1283       Tcl_AppendResult(interp, zErr, 0);
1284       return TCL_ERROR;
1285     }
1286     n2 = sqlite3GetVarint(zBuf, &out);
1287     if( n1!=n2 ){
1288       sprintf(zErr, "PutVarint returned %d and GetVarint returned %d", n1, n2);
1289       Tcl_AppendResult(interp, zErr, 0);
1290       return TCL_ERROR;
1291     }
1292     if( in!=out ){
1293       sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
1294       Tcl_AppendResult(interp, zErr, 0);
1295       return TCL_ERROR;
1296     }
1297     if( (in & 0xffffffff)==in ){
1298       u32 out32;
1299       n2 = sqlite3GetVarint32(zBuf, &out32);
1300       out = out32;
1301       if( n1!=n2 ){
1302         sprintf(zErr, "PutVarint returned %d and GetVarint32 returned %d",
1303                   n1, n2);
1304         Tcl_AppendResult(interp, zErr, 0);
1305         return TCL_ERROR;
1306       }
1307       if( in!=out ){
1308         sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
1309             in, out);
1310         Tcl_AppendResult(interp, zErr, 0);
1311         return TCL_ERROR;
1312       }
1313     }
1314 
1315     /* In order to get realistic timings, run getVarint 19 more times.
1316     ** This is because getVarint is called about 20 times more often
1317     ** than putVarint.
1318     */
1319     for(j=0; j<19; j++){
1320       sqlite3GetVarint(zBuf, &out);
1321     }
1322     in += incr;
1323   }
1324   return TCL_OK;
1325 }
1326 
1327 /*
1328 ** usage:   btree_from_db  DB-HANDLE
1329 **
1330 ** This command returns the btree handle for the main database associated
1331 ** with the database-handle passed as the argument. Example usage:
1332 **
1333 ** sqlite3 db test.db
1334 ** set bt [btree_from_db db]
1335 */
1336 static int btree_from_db(
1337   void *NotUsed,
1338   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1339   int argc,              /* Number of arguments */
1340   const char **argv      /* Text of each argument */
1341 ){
1342   char zBuf[100];
1343   Tcl_CmdInfo info;
1344   sqlite3 *db;
1345   Btree *pBt;
1346 
1347   if( argc!=2 ){
1348     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1349        " DB-HANDLE\"", 0);
1350     return TCL_ERROR;
1351   }
1352 
1353   if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
1354     Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
1355     return TCL_ERROR;
1356   }
1357   db = *((sqlite3 **)info.objClientData);
1358   assert( db );
1359 
1360   pBt = db->aDb[0].pBt;
1361   sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
1362   Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
1363   return TCL_OK;
1364 }
1365 
1366 
1367 /*
1368 ** usage:   btree_set_cache_size ID NCACHE
1369 **
1370 ** Set the size of the cache used by btree $ID.
1371 */
1372 static int btree_set_cache_size(
1373   void *NotUsed,
1374   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
1375   int argc,              /* Number of arguments */
1376   const char **argv      /* Text of each argument */
1377 ){
1378   int nCache;
1379   Btree *pBt;
1380 
1381   if( argc!=3 ){
1382     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1383        " BT NCACHE\"", 0);
1384     return TCL_ERROR;
1385   }
1386   pBt = sqlite3TextToPtr(argv[1]);
1387   if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
1388   sqlite3BtreeSetCacheSize(pBt, nCache);
1389   return TCL_OK;
1390 }
1391 
1392 
1393 /*
1394 ** Register commands with the TCL interpreter.
1395 */
1396 int Sqlitetest3_Init(Tcl_Interp *interp){
1397   extern int sqlite3_btree_trace;
1398   static struct {
1399      char *zName;
1400      Tcl_CmdProc *xProc;
1401   } aCmd[] = {
1402      { "btree_open",               (Tcl_CmdProc*)btree_open               },
1403      { "btree_close",              (Tcl_CmdProc*)btree_close              },
1404      { "btree_begin_transaction",  (Tcl_CmdProc*)btree_begin_transaction  },
1405      { "btree_commit",             (Tcl_CmdProc*)btree_commit             },
1406      { "btree_rollback",           (Tcl_CmdProc*)btree_rollback           },
1407      { "btree_create_table",       (Tcl_CmdProc*)btree_create_table       },
1408      { "btree_drop_table",         (Tcl_CmdProc*)btree_drop_table         },
1409      { "btree_clear_table",        (Tcl_CmdProc*)btree_clear_table        },
1410      { "btree_get_meta",           (Tcl_CmdProc*)btree_get_meta           },
1411      { "btree_update_meta",        (Tcl_CmdProc*)btree_update_meta        },
1412      { "btree_page_dump",          (Tcl_CmdProc*)btree_page_dump          },
1413      { "btree_tree_dump",          (Tcl_CmdProc*)btree_tree_dump          },
1414      { "btree_pager_stats",        (Tcl_CmdProc*)btree_pager_stats        },
1415      { "btree_pager_ref_dump",     (Tcl_CmdProc*)btree_pager_ref_dump     },
1416      { "btree_cursor",             (Tcl_CmdProc*)btree_cursor             },
1417      { "btree_close_cursor",       (Tcl_CmdProc*)btree_close_cursor       },
1418      { "btree_move_to",            (Tcl_CmdProc*)btree_move_to            },
1419      { "btree_delete",             (Tcl_CmdProc*)btree_delete             },
1420      { "btree_next",               (Tcl_CmdProc*)btree_next               },
1421      { "btree_prev",               (Tcl_CmdProc*)btree_prev               },
1422      { "btree_eof",                (Tcl_CmdProc*)btree_eof                },
1423      { "btree_keysize",            (Tcl_CmdProc*)btree_keysize            },
1424      { "btree_key",                (Tcl_CmdProc*)btree_key                },
1425      { "btree_data",               (Tcl_CmdProc*)btree_data               },
1426      { "btree_fetch_key",          (Tcl_CmdProc*)btree_fetch_key          },
1427      { "btree_fetch_data",         (Tcl_CmdProc*)btree_fetch_data         },
1428      { "btree_payload_size",       (Tcl_CmdProc*)btree_payload_size       },
1429      { "btree_first",              (Tcl_CmdProc*)btree_first              },
1430      { "btree_last",               (Tcl_CmdProc*)btree_last               },
1431      { "btree_cursor_info",        (Tcl_CmdProc*)btree_cursor_info        },
1432      { "btree_cursor_list",        (Tcl_CmdProc*)btree_cursor_list        },
1433      { "btree_integrity_check",    (Tcl_CmdProc*)btree_integrity_check    },
1434      { "btree_breakpoint",         (Tcl_CmdProc*)btree_breakpoint         },
1435      { "btree_varint_test",        (Tcl_CmdProc*)btree_varint_test        },
1436      { "btree_begin_statement",    (Tcl_CmdProc*)btree_begin_statement    },
1437      { "btree_commit_statement",   (Tcl_CmdProc*)btree_commit_statement   },
1438      { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
1439      { "btree_from_db",            (Tcl_CmdProc*)btree_from_db            },
1440      { "btree_set_cache_size",     (Tcl_CmdProc*)btree_set_cache_size     },
1441   };
1442   int i;
1443 
1444   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
1445     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
1446   }
1447   Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager3_refinfo_enable,
1448      TCL_LINK_INT);
1449   Tcl_LinkVar(interp, "btree_trace", (char*)&sqlite3_btree_trace,
1450      TCL_LINK_INT);
1451 
1452   /* The btree_insert command is implemented using the tcl 'object'
1453   ** interface, not the string interface like the other commands in this
1454   ** file. This is so binary data can be inserted into btree tables.
1455   */
1456   Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0);
1457   return TCL_OK;
1458 }
1459