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