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