xref: /illumos-gate/usr/src/lib/libsqlite/src/test3.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
1*c5c4113dSnw141292 /*
2*c5c4113dSnw141292 ** 2001 September 15
3*c5c4113dSnw141292 **
4*c5c4113dSnw141292 ** The author disclaims copyright to this source code.  In place of
5*c5c4113dSnw141292 ** a legal notice, here is a blessing:
6*c5c4113dSnw141292 **
7*c5c4113dSnw141292 **    May you do good and not evil.
8*c5c4113dSnw141292 **    May you find forgiveness for yourself and forgive others.
9*c5c4113dSnw141292 **    May you share freely, never taking more than you give.
10*c5c4113dSnw141292 **
11*c5c4113dSnw141292 *************************************************************************
12*c5c4113dSnw141292 ** Code for testing the btree.c module in SQLite.  This code
13*c5c4113dSnw141292 ** is not included in the SQLite library.  It is used for automated
14*c5c4113dSnw141292 ** testing of the SQLite library.
15*c5c4113dSnw141292 **
16*c5c4113dSnw141292 ** $Id: test3.c,v 1.23 2003/04/13 18:26:52 paul Exp $
17*c5c4113dSnw141292 */
18*c5c4113dSnw141292 #include "sqliteInt.h"
19*c5c4113dSnw141292 #include "pager.h"
20*c5c4113dSnw141292 #include "btree.h"
21*c5c4113dSnw141292 #include "tcl.h"
22*c5c4113dSnw141292 #include <stdlib.h>
23*c5c4113dSnw141292 #include <string.h>
24*c5c4113dSnw141292 
25*c5c4113dSnw141292 /*
26*c5c4113dSnw141292 ** Interpret an SQLite error number
27*c5c4113dSnw141292 */
errorName(int rc)28*c5c4113dSnw141292 static char *errorName(int rc){
29*c5c4113dSnw141292   char *zName;
30*c5c4113dSnw141292   switch( rc ){
31*c5c4113dSnw141292     case SQLITE_OK:         zName = "SQLITE_OK";          break;
32*c5c4113dSnw141292     case SQLITE_ERROR:      zName = "SQLITE_ERROR";       break;
33*c5c4113dSnw141292     case SQLITE_INTERNAL:   zName = "SQLITE_INTERNAL";    break;
34*c5c4113dSnw141292     case SQLITE_PERM:       zName = "SQLITE_PERM";        break;
35*c5c4113dSnw141292     case SQLITE_ABORT:      zName = "SQLITE_ABORT";       break;
36*c5c4113dSnw141292     case SQLITE_BUSY:       zName = "SQLITE_BUSY";        break;
37*c5c4113dSnw141292     case SQLITE_NOMEM:      zName = "SQLITE_NOMEM";       break;
38*c5c4113dSnw141292     case SQLITE_READONLY:   zName = "SQLITE_READONLY";    break;
39*c5c4113dSnw141292     case SQLITE_INTERRUPT:  zName = "SQLITE_INTERRUPT";   break;
40*c5c4113dSnw141292     case SQLITE_IOERR:      zName = "SQLITE_IOERR";       break;
41*c5c4113dSnw141292     case SQLITE_CORRUPT:    zName = "SQLITE_CORRUPT";     break;
42*c5c4113dSnw141292     case SQLITE_NOTFOUND:   zName = "SQLITE_NOTFOUND";    break;
43*c5c4113dSnw141292     case SQLITE_FULL:       zName = "SQLITE_FULL";        break;
44*c5c4113dSnw141292     case SQLITE_CANTOPEN:   zName = "SQLITE_CANTOPEN";    break;
45*c5c4113dSnw141292     case SQLITE_PROTOCOL:   zName = "SQLITE_PROTOCOL";    break;
46*c5c4113dSnw141292     default:                zName = "SQLITE_Unknown";     break;
47*c5c4113dSnw141292   }
48*c5c4113dSnw141292   return zName;
49*c5c4113dSnw141292 }
50*c5c4113dSnw141292 
51*c5c4113dSnw141292 /*
52*c5c4113dSnw141292 ** Usage:   btree_open FILENAME
53*c5c4113dSnw141292 **
54*c5c4113dSnw141292 ** Open a new database
55*c5c4113dSnw141292 */
btree_open(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)56*c5c4113dSnw141292 static int btree_open(
57*c5c4113dSnw141292   void *NotUsed,
58*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
59*c5c4113dSnw141292   int argc,              /* Number of arguments */
60*c5c4113dSnw141292   const char **argv      /* Text of each argument */
61*c5c4113dSnw141292 ){
62*c5c4113dSnw141292   Btree *pBt;
63*c5c4113dSnw141292   int rc;
64*c5c4113dSnw141292   char zBuf[100];
65*c5c4113dSnw141292   if( argc!=2 ){
66*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
67*c5c4113dSnw141292        " FILENAME\"", 0);
68*c5c4113dSnw141292     return TCL_ERROR;
69*c5c4113dSnw141292   }
70*c5c4113dSnw141292   rc = sqliteBtreeFactory(0, argv[1], 0, 1000, &pBt);
71*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
72*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
73*c5c4113dSnw141292     return TCL_ERROR;
74*c5c4113dSnw141292   }
75*c5c4113dSnw141292   sprintf(zBuf,"%p", pBt);
76*c5c4113dSnw141292   if( strncmp(zBuf,"0x",2) ){
77*c5c4113dSnw141292     sprintf(zBuf, "0x%p", pBt);
78*c5c4113dSnw141292   }
79*c5c4113dSnw141292   Tcl_AppendResult(interp, zBuf, 0);
80*c5c4113dSnw141292   return TCL_OK;
81*c5c4113dSnw141292 }
82*c5c4113dSnw141292 
83*c5c4113dSnw141292 /*
84*c5c4113dSnw141292 ** Usage:   btree_close ID
85*c5c4113dSnw141292 **
86*c5c4113dSnw141292 ** Close the given database.
87*c5c4113dSnw141292 */
btree_close(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)88*c5c4113dSnw141292 static int btree_close(
89*c5c4113dSnw141292   void *NotUsed,
90*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
91*c5c4113dSnw141292   int argc,              /* Number of arguments */
92*c5c4113dSnw141292   const char **argv      /* Text of each argument */
93*c5c4113dSnw141292 ){
94*c5c4113dSnw141292   Btree *pBt;
95*c5c4113dSnw141292   int rc;
96*c5c4113dSnw141292   if( argc!=2 ){
97*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
98*c5c4113dSnw141292        " ID\"", 0);
99*c5c4113dSnw141292     return TCL_ERROR;
100*c5c4113dSnw141292   }
101*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
102*c5c4113dSnw141292   rc = sqliteBtreeClose(pBt);
103*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
104*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
105*c5c4113dSnw141292     return TCL_ERROR;
106*c5c4113dSnw141292   }
107*c5c4113dSnw141292   return TCL_OK;
108*c5c4113dSnw141292 }
109*c5c4113dSnw141292 
110*c5c4113dSnw141292 /*
111*c5c4113dSnw141292 ** Usage:   btree_begin_transaction ID
112*c5c4113dSnw141292 **
113*c5c4113dSnw141292 ** Start a new transaction
114*c5c4113dSnw141292 */
btree_begin_transaction(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)115*c5c4113dSnw141292 static int btree_begin_transaction(
116*c5c4113dSnw141292   void *NotUsed,
117*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
118*c5c4113dSnw141292   int argc,              /* Number of arguments */
119*c5c4113dSnw141292   const char **argv      /* Text of each argument */
120*c5c4113dSnw141292 ){
121*c5c4113dSnw141292   Btree *pBt;
122*c5c4113dSnw141292   int rc;
123*c5c4113dSnw141292   if( argc!=2 ){
124*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
125*c5c4113dSnw141292        " ID\"", 0);
126*c5c4113dSnw141292     return TCL_ERROR;
127*c5c4113dSnw141292   }
128*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
129*c5c4113dSnw141292   rc = sqliteBtreeBeginTrans(pBt);
130*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
131*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
132*c5c4113dSnw141292     return TCL_ERROR;
133*c5c4113dSnw141292   }
134*c5c4113dSnw141292   return TCL_OK;
135*c5c4113dSnw141292 }
136*c5c4113dSnw141292 
137*c5c4113dSnw141292 /*
138*c5c4113dSnw141292 ** Usage:   btree_rollback ID
139*c5c4113dSnw141292 **
140*c5c4113dSnw141292 ** Rollback changes
141*c5c4113dSnw141292 */
btree_rollback(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)142*c5c4113dSnw141292 static int btree_rollback(
143*c5c4113dSnw141292   void *NotUsed,
144*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
145*c5c4113dSnw141292   int argc,              /* Number of arguments */
146*c5c4113dSnw141292   const char **argv      /* Text of each argument */
147*c5c4113dSnw141292 ){
148*c5c4113dSnw141292   Btree *pBt;
149*c5c4113dSnw141292   int rc;
150*c5c4113dSnw141292   if( argc!=2 ){
151*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
152*c5c4113dSnw141292        " ID\"", 0);
153*c5c4113dSnw141292     return TCL_ERROR;
154*c5c4113dSnw141292   }
155*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
156*c5c4113dSnw141292   rc = sqliteBtreeRollback(pBt);
157*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
158*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
159*c5c4113dSnw141292     return TCL_ERROR;
160*c5c4113dSnw141292   }
161*c5c4113dSnw141292   return TCL_OK;
162*c5c4113dSnw141292 }
163*c5c4113dSnw141292 
164*c5c4113dSnw141292 /*
165*c5c4113dSnw141292 ** Usage:   btree_commit ID
166*c5c4113dSnw141292 **
167*c5c4113dSnw141292 ** Commit all changes
168*c5c4113dSnw141292 */
btree_commit(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)169*c5c4113dSnw141292 static int btree_commit(
170*c5c4113dSnw141292   void *NotUsed,
171*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
172*c5c4113dSnw141292   int argc,              /* Number of arguments */
173*c5c4113dSnw141292   const char **argv      /* Text of each argument */
174*c5c4113dSnw141292 ){
175*c5c4113dSnw141292   Btree *pBt;
176*c5c4113dSnw141292   int rc;
177*c5c4113dSnw141292   if( argc!=2 ){
178*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
179*c5c4113dSnw141292        " ID\"", 0);
180*c5c4113dSnw141292     return TCL_ERROR;
181*c5c4113dSnw141292   }
182*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
183*c5c4113dSnw141292   rc = sqliteBtreeCommit(pBt);
184*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
185*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
186*c5c4113dSnw141292     return TCL_ERROR;
187*c5c4113dSnw141292   }
188*c5c4113dSnw141292   return TCL_OK;
189*c5c4113dSnw141292 }
190*c5c4113dSnw141292 
191*c5c4113dSnw141292 /*
192*c5c4113dSnw141292 ** Usage:   btree_create_table ID
193*c5c4113dSnw141292 **
194*c5c4113dSnw141292 ** Create a new table in the database
195*c5c4113dSnw141292 */
btree_create_table(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)196*c5c4113dSnw141292 static int btree_create_table(
197*c5c4113dSnw141292   void *NotUsed,
198*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
199*c5c4113dSnw141292   int argc,              /* Number of arguments */
200*c5c4113dSnw141292   const char **argv      /* Text of each argument */
201*c5c4113dSnw141292 ){
202*c5c4113dSnw141292   Btree *pBt;
203*c5c4113dSnw141292   int rc, iTable;
204*c5c4113dSnw141292   char zBuf[30];
205*c5c4113dSnw141292   if( argc!=2 ){
206*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
207*c5c4113dSnw141292        " ID\"", 0);
208*c5c4113dSnw141292     return TCL_ERROR;
209*c5c4113dSnw141292   }
210*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
211*c5c4113dSnw141292   rc = sqliteBtreeCreateTable(pBt, &iTable);
212*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
213*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
214*c5c4113dSnw141292     return TCL_ERROR;
215*c5c4113dSnw141292   }
216*c5c4113dSnw141292   sprintf(zBuf, "%d", iTable);
217*c5c4113dSnw141292   Tcl_AppendResult(interp, zBuf, 0);
218*c5c4113dSnw141292   return TCL_OK;
219*c5c4113dSnw141292 }
220*c5c4113dSnw141292 
221*c5c4113dSnw141292 /*
222*c5c4113dSnw141292 ** Usage:   btree_drop_table ID TABLENUM
223*c5c4113dSnw141292 **
224*c5c4113dSnw141292 ** Delete an entire table from the database
225*c5c4113dSnw141292 */
btree_drop_table(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)226*c5c4113dSnw141292 static int btree_drop_table(
227*c5c4113dSnw141292   void *NotUsed,
228*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
229*c5c4113dSnw141292   int argc,              /* Number of arguments */
230*c5c4113dSnw141292   const char **argv      /* Text of each argument */
231*c5c4113dSnw141292 ){
232*c5c4113dSnw141292   Btree *pBt;
233*c5c4113dSnw141292   int iTable;
234*c5c4113dSnw141292   int rc;
235*c5c4113dSnw141292   if( argc!=3 ){
236*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
237*c5c4113dSnw141292        " ID TABLENUM\"", 0);
238*c5c4113dSnw141292     return TCL_ERROR;
239*c5c4113dSnw141292   }
240*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
241*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
242*c5c4113dSnw141292   rc = sqliteBtreeDropTable(pBt, iTable);
243*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
244*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
245*c5c4113dSnw141292     return TCL_ERROR;
246*c5c4113dSnw141292   }
247*c5c4113dSnw141292   return TCL_OK;
248*c5c4113dSnw141292 }
249*c5c4113dSnw141292 
250*c5c4113dSnw141292 /*
251*c5c4113dSnw141292 ** Usage:   btree_clear_table ID TABLENUM
252*c5c4113dSnw141292 **
253*c5c4113dSnw141292 ** Remove all entries from the given table but keep the table around.
254*c5c4113dSnw141292 */
btree_clear_table(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)255*c5c4113dSnw141292 static int btree_clear_table(
256*c5c4113dSnw141292   void *NotUsed,
257*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
258*c5c4113dSnw141292   int argc,              /* Number of arguments */
259*c5c4113dSnw141292   const char **argv      /* Text of each argument */
260*c5c4113dSnw141292 ){
261*c5c4113dSnw141292   Btree *pBt;
262*c5c4113dSnw141292   int iTable;
263*c5c4113dSnw141292   int rc;
264*c5c4113dSnw141292   if( argc!=3 ){
265*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
266*c5c4113dSnw141292        " ID TABLENUM\"", 0);
267*c5c4113dSnw141292     return TCL_ERROR;
268*c5c4113dSnw141292   }
269*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
270*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
271*c5c4113dSnw141292   rc = sqliteBtreeClearTable(pBt, iTable);
272*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
273*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
274*c5c4113dSnw141292     return TCL_ERROR;
275*c5c4113dSnw141292   }
276*c5c4113dSnw141292   return TCL_OK;
277*c5c4113dSnw141292 }
278*c5c4113dSnw141292 
279*c5c4113dSnw141292 /*
280*c5c4113dSnw141292 ** Usage:   btree_get_meta ID
281*c5c4113dSnw141292 **
282*c5c4113dSnw141292 ** Return meta data
283*c5c4113dSnw141292 */
btree_get_meta(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)284*c5c4113dSnw141292 static int btree_get_meta(
285*c5c4113dSnw141292   void *NotUsed,
286*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
287*c5c4113dSnw141292   int argc,              /* Number of arguments */
288*c5c4113dSnw141292   const char **argv      /* Text of each argument */
289*c5c4113dSnw141292 ){
290*c5c4113dSnw141292   Btree *pBt;
291*c5c4113dSnw141292   int rc;
292*c5c4113dSnw141292   int i;
293*c5c4113dSnw141292   int aMeta[SQLITE_N_BTREE_META];
294*c5c4113dSnw141292   if( argc!=2 ){
295*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
296*c5c4113dSnw141292        " ID\"", 0);
297*c5c4113dSnw141292     return TCL_ERROR;
298*c5c4113dSnw141292   }
299*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
300*c5c4113dSnw141292   rc = sqliteBtreeGetMeta(pBt, aMeta);
301*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
302*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
303*c5c4113dSnw141292     return TCL_ERROR;
304*c5c4113dSnw141292   }
305*c5c4113dSnw141292   for(i=0; i<SQLITE_N_BTREE_META; i++){
306*c5c4113dSnw141292     char zBuf[30];
307*c5c4113dSnw141292     sprintf(zBuf,"%d",aMeta[i]);
308*c5c4113dSnw141292     Tcl_AppendElement(interp, zBuf);
309*c5c4113dSnw141292   }
310*c5c4113dSnw141292   return TCL_OK;
311*c5c4113dSnw141292 }
312*c5c4113dSnw141292 
313*c5c4113dSnw141292 /*
314*c5c4113dSnw141292 ** Usage:   btree_update_meta ID METADATA...
315*c5c4113dSnw141292 **
316*c5c4113dSnw141292 ** Return meta data
317*c5c4113dSnw141292 */
btree_update_meta(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)318*c5c4113dSnw141292 static int btree_update_meta(
319*c5c4113dSnw141292   void *NotUsed,
320*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
321*c5c4113dSnw141292   int argc,              /* Number of arguments */
322*c5c4113dSnw141292   const char **argv      /* Text of each argument */
323*c5c4113dSnw141292 ){
324*c5c4113dSnw141292   Btree *pBt;
325*c5c4113dSnw141292   int rc;
326*c5c4113dSnw141292   int i;
327*c5c4113dSnw141292   int aMeta[SQLITE_N_BTREE_META];
328*c5c4113dSnw141292 
329*c5c4113dSnw141292   if( argc!=2+SQLITE_N_BTREE_META ){
330*c5c4113dSnw141292     char zBuf[30];
331*c5c4113dSnw141292     sprintf(zBuf,"%d",SQLITE_N_BTREE_META);
332*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
333*c5c4113dSnw141292        " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0);
334*c5c4113dSnw141292     return TCL_ERROR;
335*c5c4113dSnw141292   }
336*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
337*c5c4113dSnw141292   for(i=0; i<SQLITE_N_BTREE_META; i++){
338*c5c4113dSnw141292     if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR;
339*c5c4113dSnw141292   }
340*c5c4113dSnw141292   rc = sqliteBtreeUpdateMeta(pBt, aMeta);
341*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
342*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
343*c5c4113dSnw141292     return TCL_ERROR;
344*c5c4113dSnw141292   }
345*c5c4113dSnw141292   return TCL_OK;
346*c5c4113dSnw141292 }
347*c5c4113dSnw141292 
348*c5c4113dSnw141292 /*
349*c5c4113dSnw141292 ** Usage:   btree_page_dump ID PAGENUM
350*c5c4113dSnw141292 **
351*c5c4113dSnw141292 ** Print a disassembly of a page on standard output
352*c5c4113dSnw141292 */
btree_page_dump(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)353*c5c4113dSnw141292 static int btree_page_dump(
354*c5c4113dSnw141292   void *NotUsed,
355*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
356*c5c4113dSnw141292   int argc,              /* Number of arguments */
357*c5c4113dSnw141292   const char **argv      /* Text of each argument */
358*c5c4113dSnw141292 ){
359*c5c4113dSnw141292   Btree *pBt;
360*c5c4113dSnw141292   int iPage;
361*c5c4113dSnw141292   int rc;
362*c5c4113dSnw141292 
363*c5c4113dSnw141292   if( argc!=3 ){
364*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
365*c5c4113dSnw141292        " ID\"", 0);
366*c5c4113dSnw141292     return TCL_ERROR;
367*c5c4113dSnw141292   }
368*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
369*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR;
370*c5c4113dSnw141292   rc = sqliteBtreePageDump(pBt, iPage, 0);
371*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
372*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
373*c5c4113dSnw141292     return TCL_ERROR;
374*c5c4113dSnw141292   }
375*c5c4113dSnw141292   return TCL_OK;
376*c5c4113dSnw141292 }
377*c5c4113dSnw141292 
378*c5c4113dSnw141292 /*
379*c5c4113dSnw141292 ** Usage:   btree_tree_dump ID PAGENUM
380*c5c4113dSnw141292 **
381*c5c4113dSnw141292 ** Print a disassembly of a page and all its child pages on standard output
382*c5c4113dSnw141292 */
btree_tree_dump(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)383*c5c4113dSnw141292 static int btree_tree_dump(
384*c5c4113dSnw141292   void *NotUsed,
385*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
386*c5c4113dSnw141292   int argc,              /* Number of arguments */
387*c5c4113dSnw141292   const char **argv      /* Text of each argument */
388*c5c4113dSnw141292 ){
389*c5c4113dSnw141292   Btree *pBt;
390*c5c4113dSnw141292   int iPage;
391*c5c4113dSnw141292   int rc;
392*c5c4113dSnw141292 
393*c5c4113dSnw141292   if( argc!=3 ){
394*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
395*c5c4113dSnw141292        " ID\"", 0);
396*c5c4113dSnw141292     return TCL_ERROR;
397*c5c4113dSnw141292   }
398*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
399*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR;
400*c5c4113dSnw141292   rc = sqliteBtreePageDump(pBt, iPage, 1);
401*c5c4113dSnw141292   if( rc!=SQLITE_OK ){
402*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
403*c5c4113dSnw141292     return TCL_ERROR;
404*c5c4113dSnw141292   }
405*c5c4113dSnw141292   return TCL_OK;
406*c5c4113dSnw141292 }
407*c5c4113dSnw141292 
408*c5c4113dSnw141292 /*
409*c5c4113dSnw141292 ** Usage:   btree_pager_stats ID
410*c5c4113dSnw141292 **
411*c5c4113dSnw141292 ** Returns pager statistics
412*c5c4113dSnw141292 */
btree_pager_stats(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)413*c5c4113dSnw141292 static int btree_pager_stats(
414*c5c4113dSnw141292   void *NotUsed,
415*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
416*c5c4113dSnw141292   int argc,              /* Number of arguments */
417*c5c4113dSnw141292   const char **argv      /* Text of each argument */
418*c5c4113dSnw141292 ){
419*c5c4113dSnw141292   Btree *pBt;
420*c5c4113dSnw141292   int i;
421*c5c4113dSnw141292   int *a;
422*c5c4113dSnw141292 
423*c5c4113dSnw141292   if( argc!=2 ){
424*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
425*c5c4113dSnw141292        " ID\"", 0);
426*c5c4113dSnw141292     return TCL_ERROR;
427*c5c4113dSnw141292   }
428*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
429*c5c4113dSnw141292   a = sqlitepager_stats(sqliteBtreePager(pBt));
430*c5c4113dSnw141292   for(i=0; i<9; i++){
431*c5c4113dSnw141292     static char *zName[] = {
432*c5c4113dSnw141292       "ref", "page", "max", "size", "state", "err",
433*c5c4113dSnw141292       "hit", "miss", "ovfl",
434*c5c4113dSnw141292     };
435*c5c4113dSnw141292     char zBuf[100];
436*c5c4113dSnw141292     Tcl_AppendElement(interp, zName[i]);
437*c5c4113dSnw141292     sprintf(zBuf,"%d",a[i]);
438*c5c4113dSnw141292     Tcl_AppendElement(interp, zBuf);
439*c5c4113dSnw141292   }
440*c5c4113dSnw141292   return TCL_OK;
441*c5c4113dSnw141292 }
442*c5c4113dSnw141292 
443*c5c4113dSnw141292 /*
444*c5c4113dSnw141292 ** Usage:   btree_pager_ref_dump ID
445*c5c4113dSnw141292 **
446*c5c4113dSnw141292 ** Print out all outstanding pages.
447*c5c4113dSnw141292 */
btree_pager_ref_dump(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)448*c5c4113dSnw141292 static int btree_pager_ref_dump(
449*c5c4113dSnw141292   void *NotUsed,
450*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
451*c5c4113dSnw141292   int argc,              /* Number of arguments */
452*c5c4113dSnw141292   const char **argv      /* Text of each argument */
453*c5c4113dSnw141292 ){
454*c5c4113dSnw141292   Btree *pBt;
455*c5c4113dSnw141292 
456*c5c4113dSnw141292   if( argc!=2 ){
457*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
458*c5c4113dSnw141292        " ID\"", 0);
459*c5c4113dSnw141292     return TCL_ERROR;
460*c5c4113dSnw141292   }
461*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
462*c5c4113dSnw141292   sqlitepager_refdump(sqliteBtreePager(pBt));
463*c5c4113dSnw141292   return TCL_OK;
464*c5c4113dSnw141292 }
465*c5c4113dSnw141292 
466*c5c4113dSnw141292 /*
467*c5c4113dSnw141292 ** Usage:   btree_integrity_check ID ROOT ...
468*c5c4113dSnw141292 **
469*c5c4113dSnw141292 ** Look through every page of the given BTree file to verify correct
470*c5c4113dSnw141292 ** formatting and linkage.  Return a line of text for each problem found.
471*c5c4113dSnw141292 ** Return an empty string if everything worked.
472*c5c4113dSnw141292 */
btree_integrity_check(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)473*c5c4113dSnw141292 static int btree_integrity_check(
474*c5c4113dSnw141292   void *NotUsed,
475*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
476*c5c4113dSnw141292   int argc,              /* Number of arguments */
477*c5c4113dSnw141292   const char **argv      /* Text of each argument */
478*c5c4113dSnw141292 ){
479*c5c4113dSnw141292   Btree *pBt;
480*c5c4113dSnw141292   char *zResult;
481*c5c4113dSnw141292   int nRoot;
482*c5c4113dSnw141292   int *aRoot;
483*c5c4113dSnw141292   int i;
484*c5c4113dSnw141292 
485*c5c4113dSnw141292   if( argc<3 ){
486*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
487*c5c4113dSnw141292        " ID ROOT ...\"", 0);
488*c5c4113dSnw141292     return TCL_ERROR;
489*c5c4113dSnw141292   }
490*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
491*c5c4113dSnw141292   nRoot = argc-2;
492*c5c4113dSnw141292   aRoot = malloc( sizeof(int)*(argc-2) );
493*c5c4113dSnw141292   for(i=0; i<argc-2; i++){
494*c5c4113dSnw141292     if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
495*c5c4113dSnw141292   }
496*c5c4113dSnw141292   zResult = sqliteBtreeIntegrityCheck(pBt, aRoot, nRoot);
497*c5c4113dSnw141292   if( zResult ){
498*c5c4113dSnw141292     Tcl_AppendResult(interp, zResult, 0);
499*c5c4113dSnw141292     sqliteFree(zResult);
500*c5c4113dSnw141292   }
501*c5c4113dSnw141292   return TCL_OK;
502*c5c4113dSnw141292 }
503*c5c4113dSnw141292 
504*c5c4113dSnw141292 /*
505*c5c4113dSnw141292 ** Usage:   btree_cursor ID TABLENUM WRITEABLE
506*c5c4113dSnw141292 **
507*c5c4113dSnw141292 ** Create a new cursor.  Return the ID for the cursor.
508*c5c4113dSnw141292 */
btree_cursor(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)509*c5c4113dSnw141292 static int btree_cursor(
510*c5c4113dSnw141292   void *NotUsed,
511*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
512*c5c4113dSnw141292   int argc,              /* Number of arguments */
513*c5c4113dSnw141292   const char **argv      /* Text of each argument */
514*c5c4113dSnw141292 ){
515*c5c4113dSnw141292   Btree *pBt;
516*c5c4113dSnw141292   int iTable;
517*c5c4113dSnw141292   BtCursor *pCur;
518*c5c4113dSnw141292   int rc;
519*c5c4113dSnw141292   int wrFlag;
520*c5c4113dSnw141292   char zBuf[30];
521*c5c4113dSnw141292 
522*c5c4113dSnw141292   if( argc!=4 ){
523*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
524*c5c4113dSnw141292        " ID TABLENUM WRITEABLE\"", 0);
525*c5c4113dSnw141292     return TCL_ERROR;
526*c5c4113dSnw141292   }
527*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
528*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
529*c5c4113dSnw141292   if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
530*c5c4113dSnw141292   rc = sqliteBtreeCursor(pBt, iTable, wrFlag, &pCur);
531*c5c4113dSnw141292   if( rc ){
532*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
533*c5c4113dSnw141292     return TCL_ERROR;
534*c5c4113dSnw141292   }
535*c5c4113dSnw141292   sprintf(zBuf,"0x%x", (int)pCur);
536*c5c4113dSnw141292   Tcl_AppendResult(interp, zBuf, 0);
537*c5c4113dSnw141292   return SQLITE_OK;
538*c5c4113dSnw141292 }
539*c5c4113dSnw141292 
540*c5c4113dSnw141292 /*
541*c5c4113dSnw141292 ** Usage:   btree_close_cursor ID
542*c5c4113dSnw141292 **
543*c5c4113dSnw141292 ** Close a cursor opened using btree_cursor.
544*c5c4113dSnw141292 */
btree_close_cursor(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)545*c5c4113dSnw141292 static int btree_close_cursor(
546*c5c4113dSnw141292   void *NotUsed,
547*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
548*c5c4113dSnw141292   int argc,              /* Number of arguments */
549*c5c4113dSnw141292   const char **argv      /* Text of each argument */
550*c5c4113dSnw141292 ){
551*c5c4113dSnw141292   BtCursor *pCur;
552*c5c4113dSnw141292   int rc;
553*c5c4113dSnw141292 
554*c5c4113dSnw141292   if( argc!=2 ){
555*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
556*c5c4113dSnw141292        " ID\"", 0);
557*c5c4113dSnw141292     return TCL_ERROR;
558*c5c4113dSnw141292   }
559*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
560*c5c4113dSnw141292   rc = sqliteBtreeCloseCursor(pCur);
561*c5c4113dSnw141292   if( rc ){
562*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
563*c5c4113dSnw141292     return TCL_ERROR;
564*c5c4113dSnw141292   }
565*c5c4113dSnw141292   return SQLITE_OK;
566*c5c4113dSnw141292 }
567*c5c4113dSnw141292 
568*c5c4113dSnw141292 /*
569*c5c4113dSnw141292 ** Usage:   btree_move_to ID KEY
570*c5c4113dSnw141292 **
571*c5c4113dSnw141292 ** Move the cursor to the entry with the given key.
572*c5c4113dSnw141292 */
btree_move_to(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)573*c5c4113dSnw141292 static int btree_move_to(
574*c5c4113dSnw141292   void *NotUsed,
575*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
576*c5c4113dSnw141292   int argc,              /* Number of arguments */
577*c5c4113dSnw141292   const char **argv      /* Text of each argument */
578*c5c4113dSnw141292 ){
579*c5c4113dSnw141292   BtCursor *pCur;
580*c5c4113dSnw141292   int rc;
581*c5c4113dSnw141292   int res;
582*c5c4113dSnw141292   char zBuf[20];
583*c5c4113dSnw141292 
584*c5c4113dSnw141292   if( argc!=3 ){
585*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
586*c5c4113dSnw141292        " ID KEY\"", 0);
587*c5c4113dSnw141292     return TCL_ERROR;
588*c5c4113dSnw141292   }
589*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
590*c5c4113dSnw141292   rc = sqliteBtreeMoveto(pCur, argv[2], strlen(argv[2]), &res);
591*c5c4113dSnw141292   if( rc ){
592*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
593*c5c4113dSnw141292     return TCL_ERROR;
594*c5c4113dSnw141292   }
595*c5c4113dSnw141292   if( res<0 ) res = -1;
596*c5c4113dSnw141292   if( res>0 ) res = 1;
597*c5c4113dSnw141292   sprintf(zBuf,"%d",res);
598*c5c4113dSnw141292   Tcl_AppendResult(interp, zBuf, 0);
599*c5c4113dSnw141292   return SQLITE_OK;
600*c5c4113dSnw141292 }
601*c5c4113dSnw141292 
602*c5c4113dSnw141292 /*
603*c5c4113dSnw141292 ** Usage:   btree_delete ID
604*c5c4113dSnw141292 **
605*c5c4113dSnw141292 ** Delete the entry that the cursor is pointing to
606*c5c4113dSnw141292 */
btree_delete(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)607*c5c4113dSnw141292 static int btree_delete(
608*c5c4113dSnw141292   void *NotUsed,
609*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
610*c5c4113dSnw141292   int argc,              /* Number of arguments */
611*c5c4113dSnw141292   const char **argv      /* Text of each argument */
612*c5c4113dSnw141292 ){
613*c5c4113dSnw141292   BtCursor *pCur;
614*c5c4113dSnw141292   int rc;
615*c5c4113dSnw141292 
616*c5c4113dSnw141292   if( argc!=2 ){
617*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
618*c5c4113dSnw141292        " ID\"", 0);
619*c5c4113dSnw141292     return TCL_ERROR;
620*c5c4113dSnw141292   }
621*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
622*c5c4113dSnw141292   rc = sqliteBtreeDelete(pCur);
623*c5c4113dSnw141292   if( rc ){
624*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
625*c5c4113dSnw141292     return TCL_ERROR;
626*c5c4113dSnw141292   }
627*c5c4113dSnw141292   return SQLITE_OK;
628*c5c4113dSnw141292 }
629*c5c4113dSnw141292 
630*c5c4113dSnw141292 /*
631*c5c4113dSnw141292 ** Usage:   btree_insert ID KEY DATA
632*c5c4113dSnw141292 **
633*c5c4113dSnw141292 ** Create a new entry with the given key and data.  If an entry already
634*c5c4113dSnw141292 ** exists with the same key the old entry is overwritten.
635*c5c4113dSnw141292 */
btree_insert(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)636*c5c4113dSnw141292 static int btree_insert(
637*c5c4113dSnw141292   void *NotUsed,
638*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
639*c5c4113dSnw141292   int argc,              /* Number of arguments */
640*c5c4113dSnw141292   const char **argv      /* Text of each argument */
641*c5c4113dSnw141292 ){
642*c5c4113dSnw141292   BtCursor *pCur;
643*c5c4113dSnw141292   int rc;
644*c5c4113dSnw141292 
645*c5c4113dSnw141292   if( argc!=4 ){
646*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
647*c5c4113dSnw141292        " ID KEY DATA\"", 0);
648*c5c4113dSnw141292     return TCL_ERROR;
649*c5c4113dSnw141292   }
650*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
651*c5c4113dSnw141292   rc = sqliteBtreeInsert(pCur, argv[2], strlen(argv[2]),
652*c5c4113dSnw141292                          argv[3], strlen(argv[3]));
653*c5c4113dSnw141292   if( rc ){
654*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
655*c5c4113dSnw141292     return TCL_ERROR;
656*c5c4113dSnw141292   }
657*c5c4113dSnw141292   return SQLITE_OK;
658*c5c4113dSnw141292 }
659*c5c4113dSnw141292 
660*c5c4113dSnw141292 /*
661*c5c4113dSnw141292 ** Usage:   btree_next ID
662*c5c4113dSnw141292 **
663*c5c4113dSnw141292 ** Move the cursor to the next entry in the table.  Return 0 on success
664*c5c4113dSnw141292 ** or 1 if the cursor was already on the last entry in the table or if
665*c5c4113dSnw141292 ** the table is empty.
666*c5c4113dSnw141292 */
btree_next(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)667*c5c4113dSnw141292 static int btree_next(
668*c5c4113dSnw141292   void *NotUsed,
669*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
670*c5c4113dSnw141292   int argc,              /* Number of arguments */
671*c5c4113dSnw141292   const char **argv      /* Text of each argument */
672*c5c4113dSnw141292 ){
673*c5c4113dSnw141292   BtCursor *pCur;
674*c5c4113dSnw141292   int rc;
675*c5c4113dSnw141292   int res = 0;
676*c5c4113dSnw141292   char zBuf[100];
677*c5c4113dSnw141292 
678*c5c4113dSnw141292   if( argc!=2 ){
679*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
680*c5c4113dSnw141292        " ID\"", 0);
681*c5c4113dSnw141292     return TCL_ERROR;
682*c5c4113dSnw141292   }
683*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
684*c5c4113dSnw141292   rc = sqliteBtreeNext(pCur, &res);
685*c5c4113dSnw141292   if( rc ){
686*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
687*c5c4113dSnw141292     return TCL_ERROR;
688*c5c4113dSnw141292   }
689*c5c4113dSnw141292   sprintf(zBuf,"%d",res);
690*c5c4113dSnw141292   Tcl_AppendResult(interp, zBuf, 0);
691*c5c4113dSnw141292   return SQLITE_OK;
692*c5c4113dSnw141292 }
693*c5c4113dSnw141292 
694*c5c4113dSnw141292 /*
695*c5c4113dSnw141292 ** Usage:   btree_prev ID
696*c5c4113dSnw141292 **
697*c5c4113dSnw141292 ** Move the cursor to the previous entry in the table.  Return 0 on
698*c5c4113dSnw141292 ** success and 1 if the cursor was already on the first entry in
699*c5c4113dSnw141292 ** the table or if the table was empty.
700*c5c4113dSnw141292 */
btree_prev(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)701*c5c4113dSnw141292 static int btree_prev(
702*c5c4113dSnw141292   void *NotUsed,
703*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
704*c5c4113dSnw141292   int argc,              /* Number of arguments */
705*c5c4113dSnw141292   const char **argv      /* Text of each argument */
706*c5c4113dSnw141292 ){
707*c5c4113dSnw141292   BtCursor *pCur;
708*c5c4113dSnw141292   int rc;
709*c5c4113dSnw141292   int res = 0;
710*c5c4113dSnw141292   char zBuf[100];
711*c5c4113dSnw141292 
712*c5c4113dSnw141292   if( argc!=2 ){
713*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
714*c5c4113dSnw141292        " ID\"", 0);
715*c5c4113dSnw141292     return TCL_ERROR;
716*c5c4113dSnw141292   }
717*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
718*c5c4113dSnw141292   rc = sqliteBtreePrevious(pCur, &res);
719*c5c4113dSnw141292   if( rc ){
720*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
721*c5c4113dSnw141292     return TCL_ERROR;
722*c5c4113dSnw141292   }
723*c5c4113dSnw141292   sprintf(zBuf,"%d",res);
724*c5c4113dSnw141292   Tcl_AppendResult(interp, zBuf, 0);
725*c5c4113dSnw141292   return SQLITE_OK;
726*c5c4113dSnw141292 }
727*c5c4113dSnw141292 
728*c5c4113dSnw141292 /*
729*c5c4113dSnw141292 ** Usage:   btree_first ID
730*c5c4113dSnw141292 **
731*c5c4113dSnw141292 ** Move the cursor to the first entry in the table.  Return 0 if the
732*c5c4113dSnw141292 ** cursor was left point to something and 1 if the table is empty.
733*c5c4113dSnw141292 */
btree_first(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)734*c5c4113dSnw141292 static int btree_first(
735*c5c4113dSnw141292   void *NotUsed,
736*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
737*c5c4113dSnw141292   int argc,              /* Number of arguments */
738*c5c4113dSnw141292   const char **argv      /* Text of each argument */
739*c5c4113dSnw141292 ){
740*c5c4113dSnw141292   BtCursor *pCur;
741*c5c4113dSnw141292   int rc;
742*c5c4113dSnw141292   int res = 0;
743*c5c4113dSnw141292   char zBuf[100];
744*c5c4113dSnw141292 
745*c5c4113dSnw141292   if( argc!=2 ){
746*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
747*c5c4113dSnw141292        " ID\"", 0);
748*c5c4113dSnw141292     return TCL_ERROR;
749*c5c4113dSnw141292   }
750*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
751*c5c4113dSnw141292   rc = sqliteBtreeFirst(pCur, &res);
752*c5c4113dSnw141292   if( rc ){
753*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
754*c5c4113dSnw141292     return TCL_ERROR;
755*c5c4113dSnw141292   }
756*c5c4113dSnw141292   sprintf(zBuf,"%d",res);
757*c5c4113dSnw141292   Tcl_AppendResult(interp, zBuf, 0);
758*c5c4113dSnw141292   return SQLITE_OK;
759*c5c4113dSnw141292 }
760*c5c4113dSnw141292 
761*c5c4113dSnw141292 /*
762*c5c4113dSnw141292 ** Usage:   btree_last ID
763*c5c4113dSnw141292 **
764*c5c4113dSnw141292 ** Move the cursor to the last entry in the table.  Return 0 if the
765*c5c4113dSnw141292 ** cursor was left point to something and 1 if the table is empty.
766*c5c4113dSnw141292 */
btree_last(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)767*c5c4113dSnw141292 static int btree_last(
768*c5c4113dSnw141292   void *NotUsed,
769*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
770*c5c4113dSnw141292   int argc,              /* Number of arguments */
771*c5c4113dSnw141292   const char **argv      /* Text of each argument */
772*c5c4113dSnw141292 ){
773*c5c4113dSnw141292   BtCursor *pCur;
774*c5c4113dSnw141292   int rc;
775*c5c4113dSnw141292   int res = 0;
776*c5c4113dSnw141292   char zBuf[100];
777*c5c4113dSnw141292 
778*c5c4113dSnw141292   if( argc!=2 ){
779*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
780*c5c4113dSnw141292        " ID\"", 0);
781*c5c4113dSnw141292     return TCL_ERROR;
782*c5c4113dSnw141292   }
783*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
784*c5c4113dSnw141292   rc = sqliteBtreeLast(pCur, &res);
785*c5c4113dSnw141292   if( rc ){
786*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
787*c5c4113dSnw141292     return TCL_ERROR;
788*c5c4113dSnw141292   }
789*c5c4113dSnw141292   sprintf(zBuf,"%d",res);
790*c5c4113dSnw141292   Tcl_AppendResult(interp, zBuf, 0);
791*c5c4113dSnw141292   return SQLITE_OK;
792*c5c4113dSnw141292 }
793*c5c4113dSnw141292 
794*c5c4113dSnw141292 /*
795*c5c4113dSnw141292 ** Usage:   btree_key ID
796*c5c4113dSnw141292 **
797*c5c4113dSnw141292 ** Return the key for the entry at which the cursor is pointing.
798*c5c4113dSnw141292 */
btree_key(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)799*c5c4113dSnw141292 static int btree_key(
800*c5c4113dSnw141292   void *NotUsed,
801*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
802*c5c4113dSnw141292   int argc,              /* Number of arguments */
803*c5c4113dSnw141292   const char **argv      /* Text of each argument */
804*c5c4113dSnw141292 ){
805*c5c4113dSnw141292   BtCursor *pCur;
806*c5c4113dSnw141292   int rc;
807*c5c4113dSnw141292   int n;
808*c5c4113dSnw141292   char *zBuf;
809*c5c4113dSnw141292 
810*c5c4113dSnw141292   if( argc!=2 ){
811*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
812*c5c4113dSnw141292        " ID\"", 0);
813*c5c4113dSnw141292     return TCL_ERROR;
814*c5c4113dSnw141292   }
815*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
816*c5c4113dSnw141292   sqliteBtreeKeySize(pCur, &n);
817*c5c4113dSnw141292   zBuf = malloc( n+1 );
818*c5c4113dSnw141292   rc = sqliteBtreeKey(pCur, 0, n, zBuf);
819*c5c4113dSnw141292   if( rc!=n ){
820*c5c4113dSnw141292     char zMsg[100];
821*c5c4113dSnw141292     free(zBuf);
822*c5c4113dSnw141292     sprintf(zMsg, "truncated key: got %d of %d bytes", rc, n);
823*c5c4113dSnw141292     Tcl_AppendResult(interp, zMsg, 0);
824*c5c4113dSnw141292     return TCL_ERROR;
825*c5c4113dSnw141292   }
826*c5c4113dSnw141292   zBuf[n] = 0;
827*c5c4113dSnw141292   Tcl_AppendResult(interp, zBuf, 0);
828*c5c4113dSnw141292   free(zBuf);
829*c5c4113dSnw141292   return SQLITE_OK;
830*c5c4113dSnw141292 }
831*c5c4113dSnw141292 
832*c5c4113dSnw141292 /*
833*c5c4113dSnw141292 ** Usage:   btree_data ID
834*c5c4113dSnw141292 **
835*c5c4113dSnw141292 ** Return the data for the entry at which the cursor is pointing.
836*c5c4113dSnw141292 */
btree_data(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)837*c5c4113dSnw141292 static int btree_data(
838*c5c4113dSnw141292   void *NotUsed,
839*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
840*c5c4113dSnw141292   int argc,              /* Number of arguments */
841*c5c4113dSnw141292   const char **argv      /* Text of each argument */
842*c5c4113dSnw141292 ){
843*c5c4113dSnw141292   BtCursor *pCur;
844*c5c4113dSnw141292   int rc;
845*c5c4113dSnw141292   int n;
846*c5c4113dSnw141292   char *zBuf;
847*c5c4113dSnw141292 
848*c5c4113dSnw141292   if( argc!=2 ){
849*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
850*c5c4113dSnw141292        " ID\"", 0);
851*c5c4113dSnw141292     return TCL_ERROR;
852*c5c4113dSnw141292   }
853*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
854*c5c4113dSnw141292   sqliteBtreeDataSize(pCur, &n);
855*c5c4113dSnw141292   zBuf = malloc( n+1 );
856*c5c4113dSnw141292   rc = sqliteBtreeData(pCur, 0, n, zBuf);
857*c5c4113dSnw141292   if( rc!=n ){
858*c5c4113dSnw141292     char zMsg[100];
859*c5c4113dSnw141292     free(zBuf);
860*c5c4113dSnw141292     sprintf(zMsg, "truncated data: got %d of %d bytes", rc, n);
861*c5c4113dSnw141292     Tcl_AppendResult(interp, zMsg, 0);
862*c5c4113dSnw141292     return TCL_ERROR;
863*c5c4113dSnw141292   }
864*c5c4113dSnw141292   zBuf[n] = 0;
865*c5c4113dSnw141292   Tcl_AppendResult(interp, zBuf, 0);
866*c5c4113dSnw141292   free(zBuf);
867*c5c4113dSnw141292   return SQLITE_OK;
868*c5c4113dSnw141292 }
869*c5c4113dSnw141292 
870*c5c4113dSnw141292 /*
871*c5c4113dSnw141292 ** Usage:   btree_payload_size ID
872*c5c4113dSnw141292 **
873*c5c4113dSnw141292 ** Return the number of bytes of payload
874*c5c4113dSnw141292 */
btree_payload_size(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)875*c5c4113dSnw141292 static int btree_payload_size(
876*c5c4113dSnw141292   void *NotUsed,
877*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
878*c5c4113dSnw141292   int argc,              /* Number of arguments */
879*c5c4113dSnw141292   const char **argv      /* Text of each argument */
880*c5c4113dSnw141292 ){
881*c5c4113dSnw141292   BtCursor *pCur;
882*c5c4113dSnw141292   int n1, n2;
883*c5c4113dSnw141292   char zBuf[50];
884*c5c4113dSnw141292 
885*c5c4113dSnw141292   if( argc!=2 ){
886*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
887*c5c4113dSnw141292        " ID\"", 0);
888*c5c4113dSnw141292     return TCL_ERROR;
889*c5c4113dSnw141292   }
890*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
891*c5c4113dSnw141292   sqliteBtreeKeySize(pCur, &n1);
892*c5c4113dSnw141292   sqliteBtreeDataSize(pCur, &n2);
893*c5c4113dSnw141292   sprintf(zBuf, "%d", n1+n2);
894*c5c4113dSnw141292   Tcl_AppendResult(interp, zBuf, 0);
895*c5c4113dSnw141292   return SQLITE_OK;
896*c5c4113dSnw141292 }
897*c5c4113dSnw141292 
898*c5c4113dSnw141292 /*
899*c5c4113dSnw141292 ** Usage:   btree_cursor_dump ID
900*c5c4113dSnw141292 **
901*c5c4113dSnw141292 ** Return eight integers containing information about the entry the
902*c5c4113dSnw141292 ** cursor is pointing to:
903*c5c4113dSnw141292 **
904*c5c4113dSnw141292 **   aResult[0] =  The page number
905*c5c4113dSnw141292 **   aResult[1] =  The entry number
906*c5c4113dSnw141292 **   aResult[2] =  Total number of entries on this page
907*c5c4113dSnw141292 **   aResult[3] =  Size of this entry
908*c5c4113dSnw141292 **   aResult[4] =  Number of free bytes on this page
909*c5c4113dSnw141292 **   aResult[5] =  Number of free blocks on the page
910*c5c4113dSnw141292 **   aResult[6] =  Page number of the left child of this entry
911*c5c4113dSnw141292 **   aResult[7] =  Page number of the right child for the whole page
912*c5c4113dSnw141292 */
btree_cursor_dump(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)913*c5c4113dSnw141292 static int btree_cursor_dump(
914*c5c4113dSnw141292   void *NotUsed,
915*c5c4113dSnw141292   Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
916*c5c4113dSnw141292   int argc,              /* Number of arguments */
917*c5c4113dSnw141292   const char **argv      /* Text of each argument */
918*c5c4113dSnw141292 ){
919*c5c4113dSnw141292   BtCursor *pCur;
920*c5c4113dSnw141292   int rc;
921*c5c4113dSnw141292   int i, j;
922*c5c4113dSnw141292   int aResult[8];
923*c5c4113dSnw141292   char zBuf[400];
924*c5c4113dSnw141292 
925*c5c4113dSnw141292   if( argc!=2 ){
926*c5c4113dSnw141292     Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
927*c5c4113dSnw141292        " ID\"", 0);
928*c5c4113dSnw141292     return TCL_ERROR;
929*c5c4113dSnw141292   }
930*c5c4113dSnw141292   if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
931*c5c4113dSnw141292   rc = sqliteBtreeCursorDump(pCur, aResult);
932*c5c4113dSnw141292   if( rc ){
933*c5c4113dSnw141292     Tcl_AppendResult(interp, errorName(rc), 0);
934*c5c4113dSnw141292     return TCL_ERROR;
935*c5c4113dSnw141292   }
936*c5c4113dSnw141292   j = 0;
937*c5c4113dSnw141292   for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){
938*c5c4113dSnw141292     sprintf(&zBuf[j]," %d", aResult[i]);
939*c5c4113dSnw141292     j += strlen(&zBuf[j]);
940*c5c4113dSnw141292   }
941*c5c4113dSnw141292   Tcl_AppendResult(interp, &zBuf[1], 0);
942*c5c4113dSnw141292   return SQLITE_OK;
943*c5c4113dSnw141292 }
944*c5c4113dSnw141292 
945*c5c4113dSnw141292 /*
946*c5c4113dSnw141292 ** Register commands with the TCL interpreter.
947*c5c4113dSnw141292 */
Sqlitetest3_Init(Tcl_Interp * interp)948*c5c4113dSnw141292 int Sqlitetest3_Init(Tcl_Interp *interp){
949*c5c4113dSnw141292   static struct {
950*c5c4113dSnw141292      char *zName;
951*c5c4113dSnw141292      Tcl_CmdProc *xProc;
952*c5c4113dSnw141292   } aCmd[] = {
953*c5c4113dSnw141292      { "btree_open",               (Tcl_CmdProc*)btree_open               },
954*c5c4113dSnw141292      { "btree_close",              (Tcl_CmdProc*)btree_close              },
955*c5c4113dSnw141292      { "btree_begin_transaction",  (Tcl_CmdProc*)btree_begin_transaction  },
956*c5c4113dSnw141292      { "btree_commit",             (Tcl_CmdProc*)btree_commit             },
957*c5c4113dSnw141292      { "btree_rollback",           (Tcl_CmdProc*)btree_rollback           },
958*c5c4113dSnw141292      { "btree_create_table",       (Tcl_CmdProc*)btree_create_table       },
959*c5c4113dSnw141292      { "btree_drop_table",         (Tcl_CmdProc*)btree_drop_table         },
960*c5c4113dSnw141292      { "btree_clear_table",        (Tcl_CmdProc*)btree_clear_table        },
961*c5c4113dSnw141292      { "btree_get_meta",           (Tcl_CmdProc*)btree_get_meta           },
962*c5c4113dSnw141292      { "btree_update_meta",        (Tcl_CmdProc*)btree_update_meta        },
963*c5c4113dSnw141292      { "btree_page_dump",          (Tcl_CmdProc*)btree_page_dump          },
964*c5c4113dSnw141292      { "btree_tree_dump",          (Tcl_CmdProc*)btree_tree_dump          },
965*c5c4113dSnw141292      { "btree_pager_stats",        (Tcl_CmdProc*)btree_pager_stats        },
966*c5c4113dSnw141292      { "btree_pager_ref_dump",     (Tcl_CmdProc*)btree_pager_ref_dump     },
967*c5c4113dSnw141292      { "btree_cursor",             (Tcl_CmdProc*)btree_cursor             },
968*c5c4113dSnw141292      { "btree_close_cursor",       (Tcl_CmdProc*)btree_close_cursor       },
969*c5c4113dSnw141292      { "btree_move_to",            (Tcl_CmdProc*)btree_move_to            },
970*c5c4113dSnw141292      { "btree_delete",             (Tcl_CmdProc*)btree_delete             },
971*c5c4113dSnw141292      { "btree_insert",             (Tcl_CmdProc*)btree_insert             },
972*c5c4113dSnw141292      { "btree_next",               (Tcl_CmdProc*)btree_next               },
973*c5c4113dSnw141292      { "btree_prev",               (Tcl_CmdProc*)btree_prev               },
974*c5c4113dSnw141292      { "btree_key",                (Tcl_CmdProc*)btree_key                },
975*c5c4113dSnw141292      { "btree_data",               (Tcl_CmdProc*)btree_data               },
976*c5c4113dSnw141292      { "btree_payload_size",       (Tcl_CmdProc*)btree_payload_size       },
977*c5c4113dSnw141292      { "btree_first",              (Tcl_CmdProc*)btree_first              },
978*c5c4113dSnw141292      { "btree_last",               (Tcl_CmdProc*)btree_last               },
979*c5c4113dSnw141292      { "btree_cursor_dump",        (Tcl_CmdProc*)btree_cursor_dump        },
980*c5c4113dSnw141292      { "btree_integrity_check",    (Tcl_CmdProc*)btree_integrity_check    },
981*c5c4113dSnw141292   };
982*c5c4113dSnw141292   int i;
983*c5c4113dSnw141292 
984*c5c4113dSnw141292   for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
985*c5c4113dSnw141292     Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
986*c5c4113dSnw141292   }
987*c5c4113dSnw141292   Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager_refinfo_enable,
988*c5c4113dSnw141292      TCL_LINK_INT);
989*c5c4113dSnw141292   Tcl_LinkVar(interp, "btree_native_byte_order",(char*)&btree_native_byte_order,
990*c5c4113dSnw141292      TCL_LINK_INT);
991*c5c4113dSnw141292   return TCL_OK;
992*c5c4113dSnw141292 }
993