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