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