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 #include "sqliteInt.h"
17 #include "btreeInt.h"
18 #include "tcl.h"
19 #include <stdlib.h>
20 #include <string.h>
21
22 /*
23 ** Interpret an SQLite error number
24 */
errorName(int rc)25 static char *errorName(int rc){
26 char *zName;
27 switch( rc ){
28 case SQLITE_OK: zName = "SQLITE_OK"; break;
29 case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
30 case SQLITE_PERM: zName = "SQLITE_PERM"; break;
31 case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
32 case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
33 case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
34 case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
35 case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
36 case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
37 case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
38 case SQLITE_FULL: zName = "SQLITE_FULL"; break;
39 case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
40 case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
41 case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
42 case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
43 default: zName = "SQLITE_Unknown"; break;
44 }
45 return zName;
46 }
47
48 /*
49 ** A bogus sqlite3 connection structure for use in the btree
50 ** tests.
51 */
52 static sqlite3 sDb;
53 static int nRefSqlite3 = 0;
54
55 /*
56 ** Usage: btree_open FILENAME NCACHE
57 **
58 ** Open a new database
59 */
btree_open(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)60 static int btree_open(
61 void *NotUsed,
62 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
63 int argc, /* Number of arguments */
64 const char **argv /* Text of each argument */
65 ){
66 Btree *pBt;
67 int rc, nCache;
68 char zBuf[100];
69 if( argc!=3 ){
70 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
71 " FILENAME NCACHE FLAGS\"", 0);
72 return TCL_ERROR;
73 }
74 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
75 nRefSqlite3++;
76 if( nRefSqlite3==1 ){
77 sDb.pVfs = sqlite3_vfs_find(0);
78 sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
79 sqlite3_mutex_enter(sDb.mutex);
80 }
81 rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, 0,
82 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
83 if( rc!=SQLITE_OK ){
84 Tcl_AppendResult(interp, errorName(rc), 0);
85 return TCL_ERROR;
86 }
87 sqlite3BtreeSetCacheSize(pBt, nCache);
88 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
89 Tcl_AppendResult(interp, zBuf, 0);
90 return TCL_OK;
91 }
92
93 /*
94 ** Usage: btree_close ID
95 **
96 ** Close the given database.
97 */
btree_close(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)98 static int btree_close(
99 void *NotUsed,
100 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
101 int argc, /* Number of arguments */
102 const char **argv /* Text of each argument */
103 ){
104 Btree *pBt;
105 int rc;
106 if( argc!=2 ){
107 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
108 " ID\"", 0);
109 return TCL_ERROR;
110 }
111 pBt = sqlite3TestTextToPtr(argv[1]);
112 rc = sqlite3BtreeClose(pBt);
113 if( rc!=SQLITE_OK ){
114 Tcl_AppendResult(interp, errorName(rc), 0);
115 return TCL_ERROR;
116 }
117 nRefSqlite3--;
118 if( nRefSqlite3==0 ){
119 sqlite3_mutex_leave(sDb.mutex);
120 sqlite3_mutex_free(sDb.mutex);
121 sDb.mutex = 0;
122 sDb.pVfs = 0;
123 }
124 return TCL_OK;
125 }
126
127
128 /*
129 ** Usage: btree_begin_transaction ID
130 **
131 ** Start a new transaction
132 */
btree_begin_transaction(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)133 static int btree_begin_transaction(
134 void *NotUsed,
135 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
136 int argc, /* Number of arguments */
137 const char **argv /* Text of each argument */
138 ){
139 Btree *pBt;
140 int rc;
141 if( argc!=2 ){
142 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
143 " ID\"", 0);
144 return TCL_ERROR;
145 }
146 pBt = sqlite3TestTextToPtr(argv[1]);
147 sqlite3BtreeEnter(pBt);
148 rc = sqlite3BtreeBeginTrans(pBt, 1);
149 sqlite3BtreeLeave(pBt);
150 if( rc!=SQLITE_OK ){
151 Tcl_AppendResult(interp, errorName(rc), 0);
152 return TCL_ERROR;
153 }
154 return TCL_OK;
155 }
156
157 /*
158 ** Usage: btree_pager_stats ID
159 **
160 ** Returns pager statistics
161 */
btree_pager_stats(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)162 static int btree_pager_stats(
163 void *NotUsed,
164 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
165 int argc, /* Number of arguments */
166 const char **argv /* Text of each argument */
167 ){
168 Btree *pBt;
169 int i;
170 int *a;
171
172 if( argc!=2 ){
173 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
174 " ID\"", 0);
175 return TCL_ERROR;
176 }
177 pBt = sqlite3TestTextToPtr(argv[1]);
178
179 /* Normally in this file, with a b-tree handle opened using the
180 ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
181 ** But this function is sometimes called with a btree handle obtained
182 ** from an open SQLite connection (using [btree_from_db]). In this case
183 ** we need to obtain the mutex for the controlling SQLite handle before
184 ** it is safe to call sqlite3BtreeEnter().
185 */
186 sqlite3_mutex_enter(pBt->db->mutex);
187
188 sqlite3BtreeEnter(pBt);
189 a = sqlite3PagerStats(sqlite3BtreePager(pBt));
190 for(i=0; i<11; i++){
191 static char *zName[] = {
192 "ref", "page", "max", "size", "state", "err",
193 "hit", "miss", "ovfl", "read", "write"
194 };
195 char zBuf[100];
196 Tcl_AppendElement(interp, zName[i]);
197 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
198 Tcl_AppendElement(interp, zBuf);
199 }
200 sqlite3BtreeLeave(pBt);
201
202 /* Release the mutex on the SQLite handle that controls this b-tree */
203 sqlite3_mutex_leave(pBt->db->mutex);
204 return TCL_OK;
205 }
206
207 /*
208 ** Usage: btree_cursor ID TABLENUM WRITEABLE
209 **
210 ** Create a new cursor. Return the ID for the cursor.
211 */
btree_cursor(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)212 static int btree_cursor(
213 void *NotUsed,
214 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
215 int argc, /* Number of arguments */
216 const char **argv /* Text of each argument */
217 ){
218 Btree *pBt;
219 int iTable;
220 BtCursor *pCur;
221 int rc = SQLITE_OK;
222 int wrFlag;
223 char zBuf[30];
224
225 if( argc!=4 ){
226 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
227 " ID TABLENUM WRITEABLE\"", 0);
228 return TCL_ERROR;
229 }
230 pBt = sqlite3TestTextToPtr(argv[1]);
231 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
232 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
233 pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
234 memset(pCur, 0, sqlite3BtreeCursorSize());
235 sqlite3BtreeEnter(pBt);
236 #ifndef SQLITE_OMIT_SHARED_CACHE
237 rc = sqlite3BtreeLockTable(pBt, iTable, wrFlag);
238 #endif
239 if( rc==SQLITE_OK ){
240 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
241 }
242 sqlite3BtreeLeave(pBt);
243 if( rc ){
244 ckfree((char *)pCur);
245 Tcl_AppendResult(interp, errorName(rc), 0);
246 return TCL_ERROR;
247 }
248 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
249 Tcl_AppendResult(interp, zBuf, 0);
250 return SQLITE_OK;
251 }
252
253 /*
254 ** Usage: btree_close_cursor ID
255 **
256 ** Close a cursor opened using btree_cursor.
257 */
btree_close_cursor(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)258 static int btree_close_cursor(
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 BtCursor *pCur;
265 Btree *pBt;
266 int rc;
267
268 if( argc!=2 ){
269 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
270 " ID\"", 0);
271 return TCL_ERROR;
272 }
273 pCur = sqlite3TestTextToPtr(argv[1]);
274 pBt = pCur->pBtree;
275 sqlite3BtreeEnter(pBt);
276 rc = sqlite3BtreeCloseCursor(pCur);
277 sqlite3BtreeLeave(pBt);
278 ckfree((char *)pCur);
279 if( rc ){
280 Tcl_AppendResult(interp, errorName(rc), 0);
281 return TCL_ERROR;
282 }
283 return SQLITE_OK;
284 }
285
286 /*
287 ** Usage: btree_next ID
288 **
289 ** Move the cursor to the next entry in the table. Return 0 on success
290 ** or 1 if the cursor was already on the last entry in the table or if
291 ** the table is empty.
292 */
btree_next(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)293 static int btree_next(
294 void *NotUsed,
295 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
296 int argc, /* Number of arguments */
297 const char **argv /* Text of each argument */
298 ){
299 BtCursor *pCur;
300 int rc;
301 int res = 0;
302 char zBuf[100];
303
304 if( argc!=2 ){
305 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
306 " ID\"", 0);
307 return TCL_ERROR;
308 }
309 pCur = sqlite3TestTextToPtr(argv[1]);
310 sqlite3BtreeEnter(pCur->pBtree);
311 rc = sqlite3BtreeNext(pCur, &res);
312 sqlite3BtreeLeave(pCur->pBtree);
313 if( rc ){
314 Tcl_AppendResult(interp, errorName(rc), 0);
315 return TCL_ERROR;
316 }
317 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
318 Tcl_AppendResult(interp, zBuf, 0);
319 return SQLITE_OK;
320 }
321
322 /*
323 ** Usage: btree_first ID
324 **
325 ** Move the cursor to the first entry in the table. Return 0 if the
326 ** cursor was left point to something and 1 if the table is empty.
327 */
btree_first(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)328 static int btree_first(
329 void *NotUsed,
330 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
331 int argc, /* Number of arguments */
332 const char **argv /* Text of each argument */
333 ){
334 BtCursor *pCur;
335 int rc;
336 int res = 0;
337 char zBuf[100];
338
339 if( argc!=2 ){
340 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
341 " ID\"", 0);
342 return TCL_ERROR;
343 }
344 pCur = sqlite3TestTextToPtr(argv[1]);
345 sqlite3BtreeEnter(pCur->pBtree);
346 rc = sqlite3BtreeFirst(pCur, &res);
347 sqlite3BtreeLeave(pCur->pBtree);
348 if( rc ){
349 Tcl_AppendResult(interp, errorName(rc), 0);
350 return TCL_ERROR;
351 }
352 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
353 Tcl_AppendResult(interp, zBuf, 0);
354 return SQLITE_OK;
355 }
356
357 /*
358 ** Usage: btree_eof ID
359 **
360 ** Return TRUE if the given cursor is not pointing at a valid entry.
361 ** Return FALSE if the cursor does point to a valid entry.
362 */
btree_eof(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)363 static int btree_eof(
364 void *NotUsed,
365 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
366 int argc, /* Number of arguments */
367 const char **argv /* Text of each argument */
368 ){
369 BtCursor *pCur;
370 int rc;
371 char zBuf[50];
372
373 if( argc!=2 ){
374 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
375 " ID\"", 0);
376 return TCL_ERROR;
377 }
378 pCur = sqlite3TestTextToPtr(argv[1]);
379 sqlite3BtreeEnter(pCur->pBtree);
380 rc = sqlite3BtreeEof(pCur);
381 sqlite3BtreeLeave(pCur->pBtree);
382 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
383 Tcl_AppendResult(interp, zBuf, 0);
384 return SQLITE_OK;
385 }
386
387 /*
388 ** Usage: btree_payload_size ID
389 **
390 ** Return the number of bytes of payload
391 */
btree_payload_size(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)392 static int btree_payload_size(
393 void *NotUsed,
394 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
395 int argc, /* Number of arguments */
396 const char **argv /* Text of each argument */
397 ){
398 BtCursor *pCur;
399 int n2;
400 u64 n1;
401 char zBuf[50];
402
403 if( argc!=2 ){
404 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
405 " ID\"", 0);
406 return TCL_ERROR;
407 }
408 pCur = sqlite3TestTextToPtr(argv[1]);
409 sqlite3BtreeEnter(pCur->pBtree);
410
411 /* The cursor may be in "require-seek" state. If this is the case, the
412 ** call to BtreeDataSize() will fix it. */
413 sqlite3BtreeDataSize(pCur, (u32*)&n2);
414 if( pCur->apPage[pCur->iPage]->intKey ){
415 n1 = 0;
416 }else{
417 sqlite3BtreeKeySize(pCur, (i64*)&n1);
418 }
419 sqlite3BtreeLeave(pCur->pBtree);
420 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
421 Tcl_AppendResult(interp, zBuf, 0);
422 return SQLITE_OK;
423 }
424
425 /*
426 ** usage: varint_test START MULTIPLIER COUNT INCREMENT
427 **
428 ** This command tests the putVarint() and getVarint()
429 ** routines, both for accuracy and for speed.
430 **
431 ** An integer is written using putVarint() and read back with
432 ** getVarint() and varified to be unchanged. This repeats COUNT
433 ** times. The first integer is START*MULTIPLIER. Each iteration
434 ** increases the integer by INCREMENT.
435 **
436 ** This command returns nothing if it works. It returns an error message
437 ** if something goes wrong.
438 */
btree_varint_test(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)439 static int btree_varint_test(
440 void *NotUsed,
441 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
442 int argc, /* Number of arguments */
443 const char **argv /* Text of each argument */
444 ){
445 u32 start, mult, count, incr;
446 u64 in, out;
447 int n1, n2, i, j;
448 unsigned char zBuf[100];
449 if( argc!=5 ){
450 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
451 " START MULTIPLIER COUNT INCREMENT\"", 0);
452 return TCL_ERROR;
453 }
454 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
455 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
456 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
457 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
458 in = start;
459 in *= mult;
460 for(i=0; i<count; i++){
461 char zErr[200];
462 n1 = putVarint(zBuf, in);
463 if( n1>9 || n1<1 ){
464 sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
465 Tcl_AppendResult(interp, zErr, 0);
466 return TCL_ERROR;
467 }
468 n2 = getVarint(zBuf, &out);
469 if( n1!=n2 ){
470 sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
471 Tcl_AppendResult(interp, zErr, 0);
472 return TCL_ERROR;
473 }
474 if( in!=out ){
475 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
476 Tcl_AppendResult(interp, zErr, 0);
477 return TCL_ERROR;
478 }
479 if( (in & 0xffffffff)==in ){
480 u32 out32;
481 n2 = getVarint32(zBuf, out32);
482 out = out32;
483 if( n1!=n2 ){
484 sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d",
485 n1, n2);
486 Tcl_AppendResult(interp, zErr, 0);
487 return TCL_ERROR;
488 }
489 if( in!=out ){
490 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
491 in, out);
492 Tcl_AppendResult(interp, zErr, 0);
493 return TCL_ERROR;
494 }
495 }
496
497 /* In order to get realistic timings, run getVarint 19 more times.
498 ** This is because getVarint is called about 20 times more often
499 ** than putVarint.
500 */
501 for(j=0; j<19; j++){
502 getVarint(zBuf, &out);
503 }
504 in += incr;
505 }
506 return TCL_OK;
507 }
508
509 /*
510 ** usage: btree_from_db DB-HANDLE
511 **
512 ** This command returns the btree handle for the main database associated
513 ** with the database-handle passed as the argument. Example usage:
514 **
515 ** sqlite3 db test.db
516 ** set bt [btree_from_db db]
517 */
btree_from_db(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)518 static int btree_from_db(
519 void *NotUsed,
520 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
521 int argc, /* Number of arguments */
522 const char **argv /* Text of each argument */
523 ){
524 char zBuf[100];
525 Tcl_CmdInfo info;
526 sqlite3 *db;
527 Btree *pBt;
528 int iDb = 0;
529
530 if( argc!=2 && argc!=3 ){
531 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
532 " DB-HANDLE ?N?\"", 0);
533 return TCL_ERROR;
534 }
535
536 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
537 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
538 return TCL_ERROR;
539 }
540 if( argc==3 ){
541 iDb = atoi(argv[2]);
542 }
543
544 db = *((sqlite3 **)info.objClientData);
545 assert( db );
546
547 pBt = db->aDb[iDb].pBt;
548 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
549 Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
550 return TCL_OK;
551 }
552
553 /*
554 ** Usage: btree_ismemdb ID
555 **
556 ** Return true if the B-Tree is in-memory.
557 */
btree_ismemdb(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)558 static int btree_ismemdb(
559 void *NotUsed,
560 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
561 int argc, /* Number of arguments */
562 const char **argv /* Text of each argument */
563 ){
564 Btree *pBt;
565 int res;
566
567 if( argc!=2 ){
568 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
569 " ID\"", 0);
570 return TCL_ERROR;
571 }
572 pBt = sqlite3TestTextToPtr(argv[1]);
573 sqlite3_mutex_enter(pBt->db->mutex);
574 sqlite3BtreeEnter(pBt);
575 res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt));
576 sqlite3BtreeLeave(pBt);
577 sqlite3_mutex_leave(pBt->db->mutex);
578 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
579 return SQLITE_OK;
580 }
581
582 /*
583 ** usage: btree_set_cache_size ID NCACHE
584 **
585 ** Set the size of the cache used by btree $ID.
586 */
btree_set_cache_size(void * NotUsed,Tcl_Interp * interp,int argc,const char ** argv)587 static int btree_set_cache_size(
588 void *NotUsed,
589 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
590 int argc, /* Number of arguments */
591 const char **argv /* Text of each argument */
592 ){
593 int nCache;
594 Btree *pBt;
595
596 if( argc!=3 ){
597 Tcl_AppendResult(
598 interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0);
599 return TCL_ERROR;
600 }
601 pBt = sqlite3TestTextToPtr(argv[1]);
602 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
603
604 sqlite3_mutex_enter(pBt->db->mutex);
605 sqlite3BtreeEnter(pBt);
606 sqlite3BtreeSetCacheSize(pBt, nCache);
607 sqlite3BtreeLeave(pBt);
608 sqlite3_mutex_leave(pBt->db->mutex);
609 return TCL_OK;
610 }
611
612
613
614 /*
615 ** Register commands with the TCL interpreter.
616 */
Sqlitetest3_Init(Tcl_Interp * interp)617 int Sqlitetest3_Init(Tcl_Interp *interp){
618 static struct {
619 char *zName;
620 Tcl_CmdProc *xProc;
621 } aCmd[] = {
622 { "btree_open", (Tcl_CmdProc*)btree_open },
623 { "btree_close", (Tcl_CmdProc*)btree_close },
624 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction },
625 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats },
626 { "btree_cursor", (Tcl_CmdProc*)btree_cursor },
627 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor },
628 { "btree_next", (Tcl_CmdProc*)btree_next },
629 { "btree_eof", (Tcl_CmdProc*)btree_eof },
630 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
631 { "btree_first", (Tcl_CmdProc*)btree_first },
632 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test },
633 { "btree_from_db", (Tcl_CmdProc*)btree_from_db },
634 { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb },
635 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }
636 };
637 int i;
638
639 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
640 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
641 }
642
643 return TCL_OK;
644 }
645