blob: c8bb40d5cd954a5ad775e70eb91f23006f3ee4cc [file] [log] [blame]
drh5c4d9702001-08-20 00:33:58 +00001/*
drhb19a2bc2001-09-16 00:13:26 +00002** 2001 September 15
drh5c4d9702001-08-20 00:33:58 +00003**
drhb19a2bc2001-09-16 00:13:26 +00004** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
drh5c4d9702001-08-20 00:33:58 +00006**
drhb19a2bc2001-09-16 00:13:26 +00007** 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.
drh5c4d9702001-08-20 00:33:58 +000010**
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**
drh0de8c112002-07-06 16:32:14 +000016** $Id: test3.c,v 1.16 2002/07/06 16:32:15 drh Exp $
drh5c4d9702001-08-20 00:33:58 +000017*/
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*/
28static 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*/
56static int btree_open(
57 void *NotUsed,
58 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
59 int argc, /* Number of arguments */
60 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 }
drh0de8c112002-07-06 16:32:14 +000070 rc = sqliteBtreeOpen(argv[1], 0666, 1000, &pBt);
drh5c4d9702001-08-20 00:33:58 +000071 if( rc!=SQLITE_OK ){
72 Tcl_AppendResult(interp, errorName(rc), 0);
73 return TCL_ERROR;
74 }
drh06b27182002-06-26 20:06:05 +000075 sprintf(zBuf,"%p", pBt);
drh5c4d9702001-08-20 00:33:58 +000076 Tcl_AppendResult(interp, zBuf, 0);
77 return TCL_OK;
78}
79
80/*
81** Usage: btree_close ID
82**
83** Close the given database.
84*/
85static int btree_close(
86 void *NotUsed,
87 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
88 int argc, /* Number of arguments */
89 char **argv /* Text of each argument */
90){
91 Btree *pBt;
92 int rc;
93 if( argc!=2 ){
94 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
95 " ID\"", 0);
96 return TCL_ERROR;
97 }
98 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
99 rc = sqliteBtreeClose(pBt);
100 if( rc!=SQLITE_OK ){
101 Tcl_AppendResult(interp, errorName(rc), 0);
102 return TCL_ERROR;
103 }
104 return TCL_OK;
105}
106
107/*
108** Usage: btree_begin_transaction ID
109**
110** Start a new transaction
111*/
112static int btree_begin_transaction(
113 void *NotUsed,
114 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
115 int argc, /* Number of arguments */
116 char **argv /* Text of each argument */
117){
118 Btree *pBt;
119 int rc;
120 if( argc!=2 ){
121 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
122 " ID\"", 0);
123 return TCL_ERROR;
124 }
125 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
126 rc = sqliteBtreeBeginTrans(pBt);
127 if( rc!=SQLITE_OK ){
128 Tcl_AppendResult(interp, errorName(rc), 0);
129 return TCL_ERROR;
130 }
131 return TCL_OK;
132}
133
134/*
135** Usage: btree_rollback ID
136**
137** Rollback changes
138*/
139static int btree_rollback(
140 void *NotUsed,
141 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
142 int argc, /* Number of arguments */
143 char **argv /* Text of each argument */
144){
145 Btree *pBt;
146 int rc;
147 if( argc!=2 ){
148 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
149 " ID\"", 0);
150 return TCL_ERROR;
151 }
152 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
153 rc = sqliteBtreeRollback(pBt);
154 if( rc!=SQLITE_OK ){
155 Tcl_AppendResult(interp, errorName(rc), 0);
156 return TCL_ERROR;
157 }
158 return TCL_OK;
159}
160
161/*
162** Usage: btree_commit ID
163**
164** Commit all changes
165*/
166static int btree_commit(
167 void *NotUsed,
168 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
169 int argc, /* Number of arguments */
170 char **argv /* Text of each argument */
171){
172 Btree *pBt;
173 int rc;
174 if( argc!=2 ){
175 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
176 " ID\"", 0);
177 return TCL_ERROR;
178 }
179 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
180 rc = sqliteBtreeCommit(pBt);
181 if( rc!=SQLITE_OK ){
182 Tcl_AppendResult(interp, errorName(rc), 0);
183 return TCL_ERROR;
184 }
185 return TCL_OK;
186}
187
188/*
189** Usage: btree_create_table ID
190**
191** Create a new table in the database
192*/
193static int btree_create_table(
194 void *NotUsed,
195 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
196 int argc, /* Number of arguments */
197 char **argv /* Text of each argument */
198){
199 Btree *pBt;
200 int rc, iTable;
201 char zBuf[30];
202 if( argc!=2 ){
203 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
204 " ID\"", 0);
205 return TCL_ERROR;
206 }
207 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
208 rc = sqliteBtreeCreateTable(pBt, &iTable);
209 if( rc!=SQLITE_OK ){
210 Tcl_AppendResult(interp, errorName(rc), 0);
211 return TCL_ERROR;
212 }
213 sprintf(zBuf, "%d", iTable);
214 Tcl_AppendResult(interp, zBuf, 0);
215 return TCL_OK;
216}
217
218/*
219** Usage: btree_drop_table ID TABLENUM
220**
221** Delete an entire table from the database
222*/
223static int btree_drop_table(
224 void *NotUsed,
225 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
226 int argc, /* Number of arguments */
227 char **argv /* Text of each argument */
228){
229 Btree *pBt;
230 int iTable;
231 int rc;
232 if( argc!=3 ){
233 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
234 " ID TABLENUM\"", 0);
235 return TCL_ERROR;
236 }
237 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
238 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
239 rc = sqliteBtreeDropTable(pBt, iTable);
240 if( rc!=SQLITE_OK ){
241 Tcl_AppendResult(interp, errorName(rc), 0);
242 return TCL_ERROR;
243 }
244 return TCL_OK;
245}
246
247/*
248** Usage: btree_clear_table ID TABLENUM
249**
250** Remove all entries from the given table but keep the table around.
251*/
252static int btree_clear_table(
253 void *NotUsed,
254 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
255 int argc, /* Number of arguments */
256 char **argv /* Text of each argument */
257){
258 Btree *pBt;
259 int iTable;
260 int rc;
261 if( argc!=3 ){
262 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
263 " ID TABLENUM\"", 0);
264 return TCL_ERROR;
265 }
266 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
267 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
268 rc = sqliteBtreeClearTable(pBt, iTable);
269 if( rc!=SQLITE_OK ){
270 Tcl_AppendResult(interp, errorName(rc), 0);
271 return TCL_ERROR;
272 }
273 return TCL_OK;
274}
275
276/*
277** Usage: btree_get_meta ID
278**
279** Return meta data
280*/
281static int btree_get_meta(
282 void *NotUsed,
283 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
284 int argc, /* Number of arguments */
285 char **argv /* Text of each argument */
286){
287 Btree *pBt;
288 int rc;
289 int i;
290 int aMeta[SQLITE_N_BTREE_META];
291 if( argc!=2 ){
292 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
293 " ID\"", 0);
294 return TCL_ERROR;
295 }
296 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
297 rc = sqliteBtreeGetMeta(pBt, aMeta);
298 if( rc!=SQLITE_OK ){
299 Tcl_AppendResult(interp, errorName(rc), 0);
300 return TCL_ERROR;
301 }
302 for(i=0; i<SQLITE_N_BTREE_META; i++){
303 char zBuf[30];
304 sprintf(zBuf,"%d",aMeta[i]);
305 Tcl_AppendElement(interp, zBuf);
306 }
307 return TCL_OK;
308}
309
310/*
311** Usage: btree_update_meta ID METADATA...
312**
313** Return meta data
314*/
315static int btree_update_meta(
316 void *NotUsed,
317 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
318 int argc, /* Number of arguments */
319 char **argv /* Text of each argument */
320){
321 Btree *pBt;
322 int rc;
323 int i;
324 int aMeta[SQLITE_N_BTREE_META];
325
326 if( argc!=2+SQLITE_N_BTREE_META ){
327 char zBuf[30];
328 sprintf(zBuf,"%d",SQLITE_N_BTREE_META);
329 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
330 " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0);
331 return TCL_ERROR;
332 }
333 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
334 for(i=0; i<SQLITE_N_BTREE_META; i++){
335 if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR;
336 }
337 rc = sqliteBtreeUpdateMeta(pBt, aMeta);
338 if( rc!=SQLITE_OK ){
339 Tcl_AppendResult(interp, errorName(rc), 0);
340 return TCL_ERROR;
341 }
342 return TCL_OK;
343}
344
345/*
346** Usage: btree_page_dump ID PAGENUM
347**
348** Print a disassembly of a page on standard output
349*/
350static int btree_page_dump(
351 void *NotUsed,
352 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
353 int argc, /* Number of arguments */
354 char **argv /* Text of each argument */
355){
356 Btree *pBt;
357 int iPage;
358 int rc;
359
360 if( argc!=3 ){
361 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
362 " ID\"", 0);
363 return TCL_ERROR;
364 }
365 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
366 if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR;
367 rc = sqliteBtreePageDump(pBt, iPage, 0);
368 if( rc!=SQLITE_OK ){
369 Tcl_AppendResult(interp, errorName(rc), 0);
370 return TCL_ERROR;
371 }
372 return TCL_OK;
373}
374
375/*
376** Usage: btree_tree_dump ID PAGENUM
377**
378** Print a disassembly of a page and all its child pages on standard output
379*/
380static int btree_tree_dump(
381 void *NotUsed,
382 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
383 int argc, /* Number of arguments */
384 char **argv /* Text of each argument */
385){
386 Btree *pBt;
387 int iPage;
388 int rc;
389
390 if( argc!=3 ){
391 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
392 " ID\"", 0);
393 return TCL_ERROR;
394 }
395 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
396 if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR;
397 rc = sqliteBtreePageDump(pBt, iPage, 1);
398 if( rc!=SQLITE_OK ){
399 Tcl_AppendResult(interp, errorName(rc), 0);
400 return TCL_ERROR;
401 }
402 return TCL_OK;
403}
404
405/*
406** Usage: btree_pager_stats ID
407**
408** Returns pager statistics
409*/
410static int btree_pager_stats(
411 void *NotUsed,
412 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
413 int argc, /* Number of arguments */
414 char **argv /* Text of each argument */
415){
416 Btree *pBt;
417 int i;
418 int *a;
419
420 if( argc!=2 ){
421 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
422 " ID\"", 0);
423 return TCL_ERROR;
424 }
425 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
426 a = sqlitepager_stats(sqliteBtreePager(pBt));
427 for(i=0; i<9; i++){
428 static char *zName[] = {
429 "ref", "page", "max", "size", "state", "err",
430 "hit", "miss", "ovfl",
431 };
432 char zBuf[100];
433 Tcl_AppendElement(interp, zName[i]);
434 sprintf(zBuf,"%d",a[i]);
435 Tcl_AppendElement(interp, zBuf);
436 }
437 return TCL_OK;
438}
439
440/*
441** Usage: btree_pager_ref_dump ID
442**
443** Print out all outstanding pages.
444*/
445static int btree_pager_ref_dump(
446 void *NotUsed,
447 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
448 int argc, /* Number of arguments */
449 char **argv /* Text of each argument */
450){
451 Btree *pBt;
452
453 if( argc!=2 ){
454 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
455 " ID\"", 0);
456 return TCL_ERROR;
457 }
458 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
459 sqlitepager_refdump(sqliteBtreePager(pBt));
460 return TCL_OK;
461}
462
463/*
drhaaab5722002-02-19 13:39:21 +0000464** Usage: btree_integrity_check ID ROOT ...
drh5c4d9702001-08-20 00:33:58 +0000465**
466** Look through every page of the given BTree file to verify correct
467** formatting and linkage. Return a line of text for each problem found.
468** Return an empty string if everything worked.
469*/
drhaaab5722002-02-19 13:39:21 +0000470static int btree_integrity_check(
drh5c4d9702001-08-20 00:33:58 +0000471 void *NotUsed,
472 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
473 int argc, /* Number of arguments */
474 char **argv /* Text of each argument */
475){
476 Btree *pBt;
477 char *zResult;
478 int nRoot;
479 int *aRoot;
480 int i;
481
482 if( argc<3 ){
483 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
484 " ID ROOT ...\"", 0);
485 return TCL_ERROR;
486 }
487 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
488 nRoot = argc-2;
489 aRoot = malloc( sizeof(int)*(argc-2) );
490 for(i=0; i<argc-2; i++){
491 if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
492 }
drhaaab5722002-02-19 13:39:21 +0000493 zResult = sqliteBtreeIntegrityCheck(pBt, aRoot, nRoot);
drh5c4d9702001-08-20 00:33:58 +0000494 if( zResult ){
495 Tcl_AppendResult(interp, zResult, 0);
496 free(zResult);
497 }
498 return TCL_OK;
499}
500
501/*
drhecdc7532001-09-23 02:35:53 +0000502** Usage: btree_cursor ID TABLENUM WRITEABLE
drh5c4d9702001-08-20 00:33:58 +0000503**
504** Create a new cursor. Return the ID for the cursor.
505*/
506static int btree_cursor(
507 void *NotUsed,
508 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
509 int argc, /* Number of arguments */
510 char **argv /* Text of each argument */
511){
512 Btree *pBt;
513 int iTable;
514 BtCursor *pCur;
515 int rc;
drhecdc7532001-09-23 02:35:53 +0000516 int wrFlag;
drh5c4d9702001-08-20 00:33:58 +0000517 char zBuf[30];
518
drhecdc7532001-09-23 02:35:53 +0000519 if( argc!=4 ){
drh5c4d9702001-08-20 00:33:58 +0000520 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drhecdc7532001-09-23 02:35:53 +0000521 " ID TABLENUM WRITEABLE\"", 0);
drh5c4d9702001-08-20 00:33:58 +0000522 return TCL_ERROR;
523 }
524 if( Tcl_GetInt(interp, argv[1], (int*)&pBt) ) return TCL_ERROR;
525 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
drhecdc7532001-09-23 02:35:53 +0000526 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
527 rc = sqliteBtreeCursor(pBt, iTable, wrFlag, &pCur);
drh5c4d9702001-08-20 00:33:58 +0000528 if( rc ){
529 Tcl_AppendResult(interp, errorName(rc), 0);
530 return TCL_ERROR;
531 }
532 sprintf(zBuf,"0x%x", (int)pCur);
533 Tcl_AppendResult(interp, zBuf, 0);
534 return SQLITE_OK;
535}
536
537/*
538** Usage: btree_close_cursor ID
539**
540** Close a cursor opened using btree_cursor.
541*/
542static int btree_close_cursor(
543 void *NotUsed,
544 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
545 int argc, /* Number of arguments */
546 char **argv /* Text of each argument */
547){
548 BtCursor *pCur;
549 int rc;
550
551 if( argc!=2 ){
552 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
553 " ID\"", 0);
554 return TCL_ERROR;
555 }
556 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
557 rc = sqliteBtreeCloseCursor(pCur);
558 if( rc ){
559 Tcl_AppendResult(interp, errorName(rc), 0);
560 return TCL_ERROR;
561 }
562 return SQLITE_OK;
563}
564
565/*
566** Usage: btree_move_to ID KEY
567**
568** Move the cursor to the entry with the given key.
569*/
570static int btree_move_to(
571 void *NotUsed,
572 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
573 int argc, /* Number of arguments */
574 char **argv /* Text of each argument */
575){
576 BtCursor *pCur;
577 int rc;
578 int res;
579 char zBuf[20];
580
581 if( argc!=3 ){
582 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
583 " ID KEY\"", 0);
584 return TCL_ERROR;
585 }
586 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
587 rc = sqliteBtreeMoveto(pCur, argv[2], strlen(argv[2]), &res);
588 if( rc ){
589 Tcl_AppendResult(interp, errorName(rc), 0);
590 return TCL_ERROR;
591 }
drhce927062001-11-09 13:41:09 +0000592 if( res<0 ) res = -1;
593 if( res>0 ) res = 1;
drh5c4d9702001-08-20 00:33:58 +0000594 sprintf(zBuf,"%d",res);
595 Tcl_AppendResult(interp, zBuf, 0);
596 return SQLITE_OK;
597}
598
599/*
600** Usage: btree_delete ID
601**
602** Delete the entry that the cursor is pointing to
603*/
604static int btree_delete(
605 void *NotUsed,
606 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
607 int argc, /* Number of arguments */
608 char **argv /* Text of each argument */
609){
610 BtCursor *pCur;
611 int rc;
612
613 if( argc!=2 ){
614 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
615 " ID\"", 0);
616 return TCL_ERROR;
617 }
618 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
619 rc = sqliteBtreeDelete(pCur);
620 if( rc ){
621 Tcl_AppendResult(interp, errorName(rc), 0);
622 return TCL_ERROR;
623 }
624 return SQLITE_OK;
625}
626
627/*
628** Usage: btree_insert ID KEY DATA
629**
630** Create a new entry with the given key and data. If an entry already
631** exists with the same key the old entry is overwritten.
632*/
633static int btree_insert(
634 void *NotUsed,
635 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
636 int argc, /* Number of arguments */
637 char **argv /* Text of each argument */
638){
639 BtCursor *pCur;
640 int rc;
641
642 if( argc!=4 ){
643 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
644 " ID KEY DATA\"", 0);
645 return TCL_ERROR;
646 }
647 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
648 rc = sqliteBtreeInsert(pCur, argv[2], strlen(argv[2]),
649 argv[3], strlen(argv[3]));
650 if( rc ){
651 Tcl_AppendResult(interp, errorName(rc), 0);
652 return TCL_ERROR;
653 }
654 return SQLITE_OK;
655}
656
657/*
658** Usage: btree_next ID
659**
660** Move the cursor to the next entry in the table.
661*/
662static int btree_next(
663 void *NotUsed,
664 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
665 int argc, /* Number of arguments */
666 char **argv /* Text of each argument */
667){
668 BtCursor *pCur;
669 int rc;
drh0de8c112002-07-06 16:32:14 +0000670 int res = 0;
671 char zBuf[100];
drh5c4d9702001-08-20 00:33:58 +0000672
673 if( argc!=2 ){
674 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
675 " ID\"", 0);
676 return TCL_ERROR;
677 }
678 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
drh0de8c112002-07-06 16:32:14 +0000679 rc = sqliteBtreeNext(pCur, &res);
drh5c4d9702001-08-20 00:33:58 +0000680 if( rc ){
681 Tcl_AppendResult(interp, errorName(rc), 0);
682 return TCL_ERROR;
683 }
drh0de8c112002-07-06 16:32:14 +0000684 sprintf(zBuf,"%d",res);
685 Tcl_AppendResult(interp, zBuf, 0);
686 return SQLITE_OK;
687}
688
689/*
690** Usage: btree_first ID
691**
692** Move the cursor to the first entry in the table.
693*/
694static int btree_first(
695 void *NotUsed,
696 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
697 int argc, /* Number of arguments */
698 char **argv /* Text of each argument */
699){
700 BtCursor *pCur;
701 int rc;
702 int res = 0;
703 char zBuf[100];
704
705 if( argc!=2 ){
706 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
707 " ID\"", 0);
708 return TCL_ERROR;
709 }
710 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
711 rc = sqliteBtreeFirst(pCur, &res);
712 if( rc ){
713 Tcl_AppendResult(interp, errorName(rc), 0);
714 return TCL_ERROR;
715 }
716 sprintf(zBuf,"%d",res);
717 Tcl_AppendResult(interp, zBuf, 0);
drh5c4d9702001-08-20 00:33:58 +0000718 return SQLITE_OK;
719}
720
721/*
722** Usage: btree_key ID
723**
724** Return the key for the entry at which the cursor is pointing.
725*/
726static int btree_key(
727 void *NotUsed,
728 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
729 int argc, /* Number of arguments */
730 char **argv /* Text of each argument */
731){
732 BtCursor *pCur;
733 int rc;
734 int n;
735 char *zBuf;
736
737 if( argc!=2 ){
738 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
739 " ID\"", 0);
740 return TCL_ERROR;
741 }
742 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
743 sqliteBtreeKeySize(pCur, &n);
744 zBuf = malloc( n+1 );
745 rc = sqliteBtreeKey(pCur, 0, n, zBuf);
drh5edc3122001-09-13 21:53:09 +0000746 if( rc!=n ){
747 char zMsg[100];
drh5c4d9702001-08-20 00:33:58 +0000748 free(zBuf);
drh5edc3122001-09-13 21:53:09 +0000749 sprintf(zMsg, "truncated key: got %d of %d bytes", rc, n);
750 Tcl_AppendResult(interp, zMsg, 0);
drh5c4d9702001-08-20 00:33:58 +0000751 return TCL_ERROR;
752 }
753 zBuf[n] = 0;
754 Tcl_AppendResult(interp, zBuf, 0);
755 free(zBuf);
756 return SQLITE_OK;
757}
758
759/*
760** Usage: btree_data ID
761**
762** Return the data for the entry at which the cursor is pointing.
763*/
764static int btree_data(
765 void *NotUsed,
766 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
767 int argc, /* Number of arguments */
768 char **argv /* Text of each argument */
769){
770 BtCursor *pCur;
771 int rc;
772 int n;
773 char *zBuf;
774
775 if( argc!=2 ){
776 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
777 " ID\"", 0);
778 return TCL_ERROR;
779 }
780 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
781 sqliteBtreeDataSize(pCur, &n);
782 zBuf = malloc( n+1 );
783 rc = sqliteBtreeData(pCur, 0, n, zBuf);
drh5edc3122001-09-13 21:53:09 +0000784 if( rc!=n ){
785 char zMsg[100];
drh5c4d9702001-08-20 00:33:58 +0000786 free(zBuf);
drh5edc3122001-09-13 21:53:09 +0000787 sprintf(zMsg, "truncated data: got %d of %d bytes", rc, n);
788 Tcl_AppendResult(interp, zMsg, 0);
drh5c4d9702001-08-20 00:33:58 +0000789 return TCL_ERROR;
790 }
791 zBuf[n] = 0;
792 Tcl_AppendResult(interp, zBuf, 0);
793 free(zBuf);
794 return SQLITE_OK;
795}
796
797/*
drh0de8c112002-07-06 16:32:14 +0000798** Usage: btree_payload_size ID
799**
800** Return the number of bytes of payload
801*/
802static int btree_payload_size(
803 void *NotUsed,
804 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
805 int argc, /* Number of arguments */
806 char **argv /* Text of each argument */
807){
808 BtCursor *pCur;
809 int n1, n2;
810 char zBuf[50];
811
812 if( argc!=2 ){
813 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
814 " ID\"", 0);
815 return TCL_ERROR;
816 }
817 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
818 sqliteBtreeKeySize(pCur, &n1);
819 sqliteBtreeDataSize(pCur, &n2);
820 sprintf(zBuf, "%d", n1+n2);
821 Tcl_AppendResult(interp, zBuf, 0);
822 free(zBuf);
823 return SQLITE_OK;
824}
825
826/*
drh5c4d9702001-08-20 00:33:58 +0000827** Usage: btree_cursor_dump ID
828**
829** Return eight integers containing information about the entry the
830** cursor is pointing to:
831**
832** aResult[0] = The page number
833** aResult[1] = The entry number
834** aResult[2] = Total number of entries on this page
835** aResult[3] = Size of this entry
836** aResult[4] = Number of free bytes on this page
837** aResult[5] = Number of free blocks on the page
838** aResult[6] = Page number of the left child of this entry
839** aResult[7] = Page number of the right child for the whole page
840*/
841static int btree_cursor_dump(
842 void *NotUsed,
843 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
844 int argc, /* Number of arguments */
845 char **argv /* Text of each argument */
846){
847 BtCursor *pCur;
848 int rc;
849 int i, j;
850 int aResult[8];
851 char zBuf[400];
852
853 if( argc!=2 ){
854 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
855 " ID\"", 0);
856 return TCL_ERROR;
857 }
858 if( Tcl_GetInt(interp, argv[1], (int*)&pCur) ) return TCL_ERROR;
859 rc = sqliteBtreeCursorDump(pCur, aResult);
860 if( rc ){
861 Tcl_AppendResult(interp, errorName(rc), 0);
862 return TCL_ERROR;
863 }
864 j = 0;
865 for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){
866 sprintf(&zBuf[j]," %d", aResult[i]);
867 j += strlen(&zBuf[j]);
868 }
869 Tcl_AppendResult(interp, &zBuf[1], 0);
870 return SQLITE_OK;
871}
872
873/*
874** Register commands with the TCL interpreter.
875*/
876int Sqlitetest3_Init(Tcl_Interp *interp){
877 Tcl_CreateCommand(interp, "btree_open", btree_open, 0, 0);
878 Tcl_CreateCommand(interp, "btree_close", btree_close, 0, 0);
879 Tcl_CreateCommand(interp, "btree_begin_transaction",
880 btree_begin_transaction, 0, 0);
881 Tcl_CreateCommand(interp, "btree_commit", btree_commit, 0, 0);
882 Tcl_CreateCommand(interp, "btree_rollback", btree_rollback, 0, 0);
883 Tcl_CreateCommand(interp, "btree_create_table", btree_create_table, 0, 0);
884 Tcl_CreateCommand(interp, "btree_drop_table", btree_drop_table, 0, 0);
885 Tcl_CreateCommand(interp, "btree_clear_table", btree_clear_table, 0, 0);
886 Tcl_CreateCommand(interp, "btree_get_meta", btree_get_meta, 0, 0);
887 Tcl_CreateCommand(interp, "btree_update_meta", btree_update_meta, 0, 0);
888 Tcl_CreateCommand(interp, "btree_page_dump", btree_page_dump, 0, 0);
889 Tcl_CreateCommand(interp, "btree_tree_dump", btree_tree_dump, 0, 0);
890 Tcl_CreateCommand(interp, "btree_pager_stats", btree_pager_stats, 0, 0);
891 Tcl_CreateCommand(interp, "btree_pager_ref_dump", btree_pager_ref_dump, 0, 0);
892 Tcl_CreateCommand(interp, "btree_cursor", btree_cursor, 0, 0);
893 Tcl_CreateCommand(interp, "btree_close_cursor", btree_close_cursor, 0, 0);
894 Tcl_CreateCommand(interp, "btree_move_to", btree_move_to, 0, 0);
895 Tcl_CreateCommand(interp, "btree_delete", btree_delete, 0, 0);
896 Tcl_CreateCommand(interp, "btree_insert", btree_insert, 0, 0);
897 Tcl_CreateCommand(interp, "btree_next", btree_next, 0, 0);
898 Tcl_CreateCommand(interp, "btree_key", btree_key, 0, 0);
899 Tcl_CreateCommand(interp, "btree_data", btree_data, 0, 0);
drh0de8c112002-07-06 16:32:14 +0000900 Tcl_CreateCommand(interp, "btree_payload_size", btree_payload_size, 0, 0);
901 Tcl_CreateCommand(interp, "btree_first", btree_first, 0, 0);
drh5c4d9702001-08-20 00:33:58 +0000902 Tcl_CreateCommand(interp, "btree_cursor_dump", btree_cursor_dump, 0, 0);
drhaaab5722002-02-19 13:39:21 +0000903 Tcl_CreateCommand(interp, "btree_integrity_check", btree_integrity_check,0,0);
drh5c4d9702001-08-20 00:33:58 +0000904 Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager_refinfo_enable,
905 TCL_LINK_INT);
906 return TCL_OK;
907}