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