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