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