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