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