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