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