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