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