blob: 68f5648a4ffc76cf9941e97fd9a5c0dd996abf6f [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.
drh5c4d9702001-08-20 00:33:58 +000015*/
16#include "sqliteInt.h"
danielk1977a1644fd2007-08-29 12:31:25 +000017#include "btreeInt.h"
drh5c4d9702001-08-20 00:33:58 +000018#include "tcl.h"
19#include <stdlib.h>
20#include <string.h>
21
22/*
23** Interpret an SQLite error number
24*/
25static 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;
drh5c4d9702001-08-20 00:33:58 +000030 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;
drh5c4d9702001-08-20 00:33:58 +000038 case SQLITE_FULL: zName = "SQLITE_FULL"; break;
39 case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
40 case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
drh24cd67e2004-05-10 16:18:47 +000041 case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
danielk1977e6efa742004-11-10 11:55:10 +000042 case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
drh5c4d9702001-08-20 00:33:58 +000043 default: zName = "SQLITE_Unknown"; break;
44 }
45 return zName;
46}
47
48/*
drha2451e22007-08-20 23:50:24 +000049** A bogus sqlite3 connection structure for use in the btree
50** tests.
51*/
52static sqlite3 sDb;
53static int nRefSqlite3 = 0;
54
55/*
drh23e11ca2004-05-04 17:27:28 +000056** Usage: btree_open FILENAME NCACHE FLAGS
drh5c4d9702001-08-20 00:33:58 +000057**
58** Open a new database
59*/
60static int btree_open(
61 void *NotUsed,
62 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
63 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +000064 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +000065){
66 Btree *pBt;
drh23e11ca2004-05-04 17:27:28 +000067 int rc, nCache, flags;
drh5c4d9702001-08-20 00:33:58 +000068 char zBuf[100];
drh23e11ca2004-05-04 17:27:28 +000069 if( argc!=4 ){
drh5c4d9702001-08-20 00:33:58 +000070 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drh23e11ca2004-05-04 17:27:28 +000071 " FILENAME NCACHE FLAGS\"", 0);
drh5c4d9702001-08-20 00:33:58 +000072 return TCL_ERROR;
73 }
drh23e11ca2004-05-04 17:27:28 +000074 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
75 if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR;
drha2451e22007-08-20 23:50:24 +000076 nRefSqlite3++;
77 if( nRefSqlite3==1 ){
78 sDb.pVfs = sqlite3_vfs_find(0);
danielk197759f8c082008-06-18 17:09:10 +000079 sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
drh27641702007-08-22 02:56:42 +000080 sqlite3_mutex_enter(sDb.mutex);
drha2451e22007-08-20 23:50:24 +000081 }
drh33f4e022007-09-03 15:19:34 +000082 rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, flags,
83 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
drh5c4d9702001-08-20 00:33:58 +000084 if( rc!=SQLITE_OK ){
85 Tcl_AppendResult(interp, errorName(rc), 0);
86 return TCL_ERROR;
87 }
drh90f5ecb2004-07-22 01:19:35 +000088 sqlite3BtreeSetCacheSize(pBt, nCache);
drhfe63d1c2004-09-08 20:13:04 +000089 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
drh5c4d9702001-08-20 00:33:58 +000090 Tcl_AppendResult(interp, zBuf, 0);
91 return TCL_OK;
92}
93
94/*
95** Usage: btree_close ID
96**
97** Close the given database.
98*/
99static int btree_close(
100 void *NotUsed,
101 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
102 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000103 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000104){
105 Btree *pBt;
106 int rc;
107 if( argc!=2 ){
108 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
109 " ID\"", 0);
110 return TCL_ERROR;
111 }
drhe8f52c52008-07-12 14:52:20 +0000112 pBt = sqlite3TestTextToPtr(argv[1]);
drh23e11ca2004-05-04 17:27:28 +0000113 rc = sqlite3BtreeClose(pBt);
drh5c4d9702001-08-20 00:33:58 +0000114 if( rc!=SQLITE_OK ){
115 Tcl_AppendResult(interp, errorName(rc), 0);
116 return TCL_ERROR;
117 }
drha2451e22007-08-20 23:50:24 +0000118 nRefSqlite3--;
119 if( nRefSqlite3==0 ){
drh27641702007-08-22 02:56:42 +0000120 sqlite3_mutex_leave(sDb.mutex);
drha2451e22007-08-20 23:50:24 +0000121 sqlite3_mutex_free(sDb.mutex);
122 sDb.mutex = 0;
drha2451e22007-08-20 23:50:24 +0000123 sDb.pVfs = 0;
124 }
drh5c4d9702001-08-20 00:33:58 +0000125 return TCL_OK;
126}
127
drh27641702007-08-22 02:56:42 +0000128
drh5c4d9702001-08-20 00:33:58 +0000129/*
130** Usage: btree_begin_transaction ID
131**
132** Start a new transaction
133*/
134static int btree_begin_transaction(
135 void *NotUsed,
136 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
137 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000138 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000139){
140 Btree *pBt;
141 int rc;
142 if( argc!=2 ){
143 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
144 " ID\"", 0);
145 return TCL_ERROR;
146 }
drhe8f52c52008-07-12 14:52:20 +0000147 pBt = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000148 sqlite3BtreeEnter(pBt);
danielk197740b38dc2004-06-26 08:38:24 +0000149 rc = sqlite3BtreeBeginTrans(pBt, 1);
drhff0587c2007-08-29 17:43:19 +0000150 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000151 if( rc!=SQLITE_OK ){
152 Tcl_AppendResult(interp, errorName(rc), 0);
153 return TCL_ERROR;
154 }
155 return TCL_OK;
156}
157
158/*
drh5c4d9702001-08-20 00:33:58 +0000159** Usage: btree_pager_stats ID
160**
161** Returns pager statistics
162*/
163static int btree_pager_stats(
164 void *NotUsed,
165 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
166 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000167 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000168){
169 Btree *pBt;
170 int i;
171 int *a;
172
173 if( argc!=2 ){
174 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
175 " ID\"", 0);
176 return TCL_ERROR;
177 }
drhe8f52c52008-07-12 14:52:20 +0000178 pBt = sqlite3TestTextToPtr(argv[1]);
danielk1977f3c62652007-08-30 08:27:39 +0000179
180 /* Normally in this file, with a b-tree handle opened using the
181 ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
182 ** But this function is sometimes called with a btree handle obtained
183 ** from an open SQLite connection (using [btree_from_db]). In this case
184 ** we need to obtain the mutex for the controlling SQLite handle before
185 ** it is safe to call sqlite3BtreeEnter().
186 */
drhe5fe6902007-12-07 18:55:28 +0000187 sqlite3_mutex_enter(pBt->db->mutex);
danielk1977f3c62652007-08-30 08:27:39 +0000188
drh27641702007-08-22 02:56:42 +0000189 sqlite3BtreeEnter(pBt);
danielk19773b8a05f2007-03-19 17:44:26 +0000190 a = sqlite3PagerStats(sqlite3BtreePager(pBt));
danielk197742741be2005-01-08 12:42:39 +0000191 for(i=0; i<11; i++){
drh5c4d9702001-08-20 00:33:58 +0000192 static char *zName[] = {
193 "ref", "page", "max", "size", "state", "err",
danielk197742741be2005-01-08 12:42:39 +0000194 "hit", "miss", "ovfl", "read", "write"
drh5c4d9702001-08-20 00:33:58 +0000195 };
196 char zBuf[100];
197 Tcl_AppendElement(interp, zName[i]);
drhfe63d1c2004-09-08 20:13:04 +0000198 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
drh5c4d9702001-08-20 00:33:58 +0000199 Tcl_AppendElement(interp, zBuf);
200 }
drh27641702007-08-22 02:56:42 +0000201 sqlite3BtreeLeave(pBt);
danielk1977f3c62652007-08-30 08:27:39 +0000202
203 /* Release the mutex on the SQLite handle that controls this b-tree */
drhe5fe6902007-12-07 18:55:28 +0000204 sqlite3_mutex_leave(pBt->db->mutex);
drh5c4d9702001-08-20 00:33:58 +0000205 return TCL_OK;
206}
207
208/*
drhecdc7532001-09-23 02:35:53 +0000209** Usage: btree_cursor ID TABLENUM WRITEABLE
drh5c4d9702001-08-20 00:33:58 +0000210**
211** Create a new cursor. Return the ID for the cursor.
212*/
213static int btree_cursor(
214 void *NotUsed,
215 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
216 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000217 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000218){
219 Btree *pBt;
220 int iTable;
221 BtCursor *pCur;
dan93a696f2010-01-07 11:27:30 +0000222 int rc = SQLITE_OK;
drhecdc7532001-09-23 02:35:53 +0000223 int wrFlag;
drh5c4d9702001-08-20 00:33:58 +0000224 char zBuf[30];
225
drhecdc7532001-09-23 02:35:53 +0000226 if( argc!=4 ){
drh5c4d9702001-08-20 00:33:58 +0000227 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drhecdc7532001-09-23 02:35:53 +0000228 " ID TABLENUM WRITEABLE\"", 0);
drh5c4d9702001-08-20 00:33:58 +0000229 return TCL_ERROR;
230 }
drhe8f52c52008-07-12 14:52:20 +0000231 pBt = sqlite3TestTextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000232 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
drhecdc7532001-09-23 02:35:53 +0000233 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
danielk1977cd3e8f72008-03-25 09:47:35 +0000234 pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
235 memset(pCur, 0, sqlite3BtreeCursorSize());
drhff0587c2007-08-29 17:43:19 +0000236 sqlite3BtreeEnter(pBt);
dan93a696f2010-01-07 11:27:30 +0000237#ifndef SQLITE_OMIT_SHARED_CACHE
danielk197796d48e92009-06-29 06:00:37 +0000238 rc = sqlite3BtreeLockTable(pBt, iTable, wrFlag);
dan93a696f2010-01-07 11:27:30 +0000239#endif
danielk197796d48e92009-06-29 06:00:37 +0000240 if( rc==SQLITE_OK ){
241 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
242 }
drhff0587c2007-08-29 17:43:19 +0000243 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000244 if( rc ){
danielk1977cd3e8f72008-03-25 09:47:35 +0000245 ckfree((char *)pCur);
drh5c4d9702001-08-20 00:33:58 +0000246 Tcl_AppendResult(interp, errorName(rc), 0);
247 return TCL_ERROR;
248 }
drhfe63d1c2004-09-08 20:13:04 +0000249 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
drh5c4d9702001-08-20 00:33:58 +0000250 Tcl_AppendResult(interp, zBuf, 0);
251 return SQLITE_OK;
252}
253
254/*
255** Usage: btree_close_cursor ID
256**
257** Close a cursor opened using btree_cursor.
258*/
259static int btree_close_cursor(
260 void *NotUsed,
261 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
262 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000263 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000264){
265 BtCursor *pCur;
drhff0587c2007-08-29 17:43:19 +0000266 Btree *pBt;
drh5c4d9702001-08-20 00:33:58 +0000267 int rc;
268
269 if( argc!=2 ){
270 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
271 " ID\"", 0);
272 return TCL_ERROR;
273 }
drhe8f52c52008-07-12 14:52:20 +0000274 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000275 pBt = pCur->pBtree;
276 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000277 rc = sqlite3BtreeCloseCursor(pCur);
drhff0587c2007-08-29 17:43:19 +0000278 sqlite3BtreeLeave(pBt);
danielk1977cd3e8f72008-03-25 09:47:35 +0000279 ckfree((char *)pCur);
drh5c4d9702001-08-20 00:33:58 +0000280 if( rc ){
281 Tcl_AppendResult(interp, errorName(rc), 0);
282 return TCL_ERROR;
283 }
284 return SQLITE_OK;
285}
286
287/*
drh5c4d9702001-08-20 00:33:58 +0000288** Usage: btree_next ID
289**
drh2dcc9aa2002-12-04 13:40:25 +0000290** Move the cursor to the next entry in the table. Return 0 on success
291** or 1 if the cursor was already on the last entry in the table or if
292** the table is empty.
drh5c4d9702001-08-20 00:33:58 +0000293*/
294static int btree_next(
295 void *NotUsed,
296 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
297 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000298 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000299){
300 BtCursor *pCur;
301 int rc;
drh0de8c112002-07-06 16:32:14 +0000302 int res = 0;
303 char zBuf[100];
drh5c4d9702001-08-20 00:33:58 +0000304
305 if( argc!=2 ){
306 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
307 " ID\"", 0);
308 return TCL_ERROR;
309 }
drhe8f52c52008-07-12 14:52:20 +0000310 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000311 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000312 rc = sqlite3BtreeNext(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000313 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000314 if( rc ){
315 Tcl_AppendResult(interp, errorName(rc), 0);
316 return TCL_ERROR;
317 }
drhfe63d1c2004-09-08 20:13:04 +0000318 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000319 Tcl_AppendResult(interp, zBuf, 0);
320 return SQLITE_OK;
321}
322
323/*
324** Usage: btree_first ID
325**
drh2dcc9aa2002-12-04 13:40:25 +0000326** Move the cursor to the first entry in the table. Return 0 if the
327** cursor was left point to something and 1 if the table is empty.
drh0de8c112002-07-06 16:32:14 +0000328*/
329static int btree_first(
330 void *NotUsed,
331 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
332 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000333 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +0000334){
335 BtCursor *pCur;
336 int rc;
337 int res = 0;
338 char zBuf[100];
339
340 if( argc!=2 ){
341 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
342 " ID\"", 0);
343 return TCL_ERROR;
344 }
drhe8f52c52008-07-12 14:52:20 +0000345 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000346 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000347 rc = sqlite3BtreeFirst(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000348 sqlite3BtreeLeave(pCur->pBtree);
drh0de8c112002-07-06 16:32:14 +0000349 if( rc ){
350 Tcl_AppendResult(interp, errorName(rc), 0);
351 return TCL_ERROR;
352 }
drhfe63d1c2004-09-08 20:13:04 +0000353 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000354 Tcl_AppendResult(interp, zBuf, 0);
drh5c4d9702001-08-20 00:33:58 +0000355 return SQLITE_OK;
356}
357
358/*
drhc39e0002004-05-07 23:50:57 +0000359** Usage: btree_eof ID
360**
361** Return TRUE if the given cursor is not pointing at a valid entry.
362** Return FALSE if the cursor does point to a valid entry.
363*/
364static int btree_eof(
365 void *NotUsed,
366 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
367 int argc, /* Number of arguments */
368 const char **argv /* Text of each argument */
369){
370 BtCursor *pCur;
drhff0587c2007-08-29 17:43:19 +0000371 int rc;
drhc39e0002004-05-07 23:50:57 +0000372 char zBuf[50];
373
374 if( argc!=2 ){
375 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
376 " ID\"", 0);
377 return TCL_ERROR;
378 }
drhe8f52c52008-07-12 14:52:20 +0000379 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000380 sqlite3BtreeEnter(pCur->pBtree);
381 rc = sqlite3BtreeEof(pCur);
382 sqlite3BtreeLeave(pCur->pBtree);
383 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
drhc39e0002004-05-07 23:50:57 +0000384 Tcl_AppendResult(interp, zBuf, 0);
385 return SQLITE_OK;
386}
387
388/*
drh0de8c112002-07-06 16:32:14 +0000389** Usage: btree_payload_size ID
390**
391** Return the number of bytes of payload
392*/
393static int btree_payload_size(
394 void *NotUsed,
395 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
396 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000397 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +0000398){
399 BtCursor *pCur;
drh4fc0fb42004-05-07 02:26:28 +0000400 int n2;
drha34b6762004-05-07 13:30:42 +0000401 u64 n1;
drh0de8c112002-07-06 16:32:14 +0000402 char zBuf[50];
403
404 if( argc!=2 ){
405 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
406 " ID\"", 0);
407 return TCL_ERROR;
408 }
drhe8f52c52008-07-12 14:52:20 +0000409 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000410 sqlite3BtreeEnter(pCur->pBtree);
danielk197730548662009-07-09 05:07:37 +0000411
412 /* The cursor may be in "require-seek" state. If this is the case, the
413 ** call to BtreeDataSize() will fix it. */
414 sqlite3BtreeDataSize(pCur, (u32*)&n2);
shanecbcadd42009-07-09 03:20:46 +0000415 if( pCur->apPage[pCur->iPage]->intKey ){
drha34b6762004-05-07 13:30:42 +0000416 n1 = 0;
417 }else{
drh03d847e2005-12-09 20:21:58 +0000418 sqlite3BtreeKeySize(pCur, (i64*)&n1);
drha34b6762004-05-07 13:30:42 +0000419 }
drhff0587c2007-08-29 17:43:19 +0000420 sqlite3BtreeLeave(pCur->pBtree);
drhfe63d1c2004-09-08 20:13:04 +0000421 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
drh0de8c112002-07-06 16:32:14 +0000422 Tcl_AppendResult(interp, zBuf, 0);
drh0de8c112002-07-06 16:32:14 +0000423 return SQLITE_OK;
424}
425
426/*
drh6d2fb152004-05-14 16:50:06 +0000427** usage: varint_test START MULTIPLIER COUNT INCREMENT
428**
shane3f8d5cf2008-04-24 19:15:09 +0000429** This command tests the putVarint() and getVarint()
drh6d2fb152004-05-14 16:50:06 +0000430** routines, both for accuracy and for speed.
431**
shane3f8d5cf2008-04-24 19:15:09 +0000432** An integer is written using putVarint() and read back with
433** getVarint() and varified to be unchanged. This repeats COUNT
drh6d2fb152004-05-14 16:50:06 +0000434** times. The first integer is START*MULTIPLIER. Each iteration
435** increases the integer by INCREMENT.
436**
437** This command returns nothing if it works. It returns an error message
438** if something goes wrong.
439*/
440static int btree_varint_test(
441 void *NotUsed,
442 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
443 int argc, /* Number of arguments */
444 const char **argv /* Text of each argument */
445){
446 u32 start, mult, count, incr;
447 u64 in, out;
drhd8820e82004-05-18 15:57:42 +0000448 int n1, n2, i, j;
drh6d2fb152004-05-14 16:50:06 +0000449 unsigned char zBuf[100];
450 if( argc!=5 ){
451 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
452 " START MULTIPLIER COUNT INCREMENT\"", 0);
453 return TCL_ERROR;
454 }
455 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
456 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
457 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
458 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
459 in = start;
460 in *= mult;
461 for(i=0; i<count; i++){
drhd8820e82004-05-18 15:57:42 +0000462 char zErr[200];
shane3f8d5cf2008-04-24 19:15:09 +0000463 n1 = putVarint(zBuf, in);
drh6d2fb152004-05-14 16:50:06 +0000464 if( n1>9 || n1<1 ){
shane3f8d5cf2008-04-24 19:15:09 +0000465 sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
drhd8820e82004-05-18 15:57:42 +0000466 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000467 return TCL_ERROR;
468 }
shane3f8d5cf2008-04-24 19:15:09 +0000469 n2 = getVarint(zBuf, &out);
drh6d2fb152004-05-14 16:50:06 +0000470 if( n1!=n2 ){
shane3f8d5cf2008-04-24 19:15:09 +0000471 sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
drhd8820e82004-05-18 15:57:42 +0000472 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000473 return TCL_ERROR;
474 }
475 if( in!=out ){
drhd8820e82004-05-18 15:57:42 +0000476 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
477 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000478 return TCL_ERROR;
479 }
drh9d213ef2004-06-30 04:02:11 +0000480 if( (in & 0xffffffff)==in ){
481 u32 out32;
shane3f8d5cf2008-04-24 19:15:09 +0000482 n2 = getVarint32(zBuf, out32);
drh9d213ef2004-06-30 04:02:11 +0000483 out = out32;
484 if( n1!=n2 ){
shane3f8d5cf2008-04-24 19:15:09 +0000485 sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d",
drh9d213ef2004-06-30 04:02:11 +0000486 n1, n2);
487 Tcl_AppendResult(interp, zErr, 0);
488 return TCL_ERROR;
489 }
490 if( in!=out ){
491 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
492 in, out);
493 Tcl_AppendResult(interp, zErr, 0);
494 return TCL_ERROR;
495 }
496 }
drhd8820e82004-05-18 15:57:42 +0000497
498 /* In order to get realistic timings, run getVarint 19 more times.
499 ** This is because getVarint is called about 20 times more often
500 ** than putVarint.
501 */
502 for(j=0; j<19; j++){
shane3f8d5cf2008-04-24 19:15:09 +0000503 getVarint(zBuf, &out);
drhd8820e82004-05-18 15:57:42 +0000504 }
drh6d2fb152004-05-14 16:50:06 +0000505 in += incr;
506 }
507 return TCL_OK;
508}
drh9b171272004-05-08 02:03:22 +0000509
510/*
danielk197742741be2005-01-08 12:42:39 +0000511** usage: btree_from_db DB-HANDLE
512**
513** This command returns the btree handle for the main database associated
514** with the database-handle passed as the argument. Example usage:
515**
516** sqlite3 db test.db
517** set bt [btree_from_db db]
518*/
519static int btree_from_db(
520 void *NotUsed,
521 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
522 int argc, /* Number of arguments */
523 const char **argv /* Text of each argument */
524){
525 char zBuf[100];
526 Tcl_CmdInfo info;
527 sqlite3 *db;
528 Btree *pBt;
danielk197763c64f32007-05-17 14:45:12 +0000529 int iDb = 0;
danielk197742741be2005-01-08 12:42:39 +0000530
danielk197763c64f32007-05-17 14:45:12 +0000531 if( argc!=2 && argc!=3 ){
danielk197742741be2005-01-08 12:42:39 +0000532 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
danielk197763c64f32007-05-17 14:45:12 +0000533 " DB-HANDLE ?N?\"", 0);
danielk197742741be2005-01-08 12:42:39 +0000534 return TCL_ERROR;
535 }
536
537 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
538 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
539 return TCL_ERROR;
540 }
danielk197763c64f32007-05-17 14:45:12 +0000541 if( argc==3 ){
542 iDb = atoi(argv[2]);
543 }
544
danielk197742741be2005-01-08 12:42:39 +0000545 db = *((sqlite3 **)info.objClientData);
546 assert( db );
547
danielk197763c64f32007-05-17 14:45:12 +0000548 pBt = db->aDb[iDb].pBt;
danielk197742741be2005-01-08 12:42:39 +0000549 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
550 Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
551 return TCL_OK;
552}
553
danielk197717b90b52008-06-06 11:11:25 +0000554/*
555** Usage: btree_ismemdb ID
556**
557** Return true if the B-Tree is in-memory.
558*/
559static int btree_ismemdb(
560 void *NotUsed,
561 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
562 int argc, /* Number of arguments */
563 const char **argv /* Text of each argument */
564){
565 Btree *pBt;
566 int res;
567
568 if( argc!=2 ){
569 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
570 " ID\"", 0);
571 return TCL_ERROR;
572 }
drhe8f52c52008-07-12 14:52:20 +0000573 pBt = sqlite3TestTextToPtr(argv[1]);
danielk197717b90b52008-06-06 11:11:25 +0000574 sqlite3_mutex_enter(pBt->db->mutex);
575 sqlite3BtreeEnter(pBt);
576 res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt));
577 sqlite3BtreeLeave(pBt);
578 sqlite3_mutex_leave(pBt->db->mutex);
579 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
580 return SQLITE_OK;
581}
582
danielk197730548662009-07-09 05:07:37 +0000583/*
584** usage: btree_set_cache_size ID NCACHE
585**
586** Set the size of the cache used by btree $ID.
587*/
588static int btree_set_cache_size(
589 void *NotUsed,
590 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
591 int argc, /* Number of arguments */
592 const char **argv /* Text of each argument */
593){
594 int nCache;
595 Btree *pBt;
596
597 if( argc!=3 ){
598 Tcl_AppendResult(
599 interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0);
600 return TCL_ERROR;
601 }
602 pBt = sqlite3TestTextToPtr(argv[1]);
603 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
604
605 sqlite3_mutex_enter(pBt->db->mutex);
606 sqlite3BtreeEnter(pBt);
607 sqlite3BtreeSetCacheSize(pBt, nCache);
608 sqlite3BtreeLeave(pBt);
609 sqlite3_mutex_leave(pBt->db->mutex);
610 return TCL_OK;
611}
612
613
danielk19771ad7f642005-01-20 05:24:32 +0000614
danielk197742741be2005-01-08 12:42:39 +0000615/*
drh5c4d9702001-08-20 00:33:58 +0000616** Register commands with the TCL interpreter.
617*/
618int Sqlitetest3_Init(Tcl_Interp *interp){
drhc2eef3b2002-08-31 18:53:06 +0000619 static struct {
620 char *zName;
621 Tcl_CmdProc *xProc;
622 } aCmd[] = {
623 { "btree_open", (Tcl_CmdProc*)btree_open },
624 { "btree_close", (Tcl_CmdProc*)btree_close },
625 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction },
drhc2eef3b2002-08-31 18:53:06 +0000626 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats },
drhc2eef3b2002-08-31 18:53:06 +0000627 { "btree_cursor", (Tcl_CmdProc*)btree_cursor },
628 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor },
drhc2eef3b2002-08-31 18:53:06 +0000629 { "btree_next", (Tcl_CmdProc*)btree_next },
drhc39e0002004-05-07 23:50:57 +0000630 { "btree_eof", (Tcl_CmdProc*)btree_eof },
drhc2eef3b2002-08-31 18:53:06 +0000631 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
632 { "btree_first", (Tcl_CmdProc*)btree_first },
drh6d2fb152004-05-14 16:50:06 +0000633 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test },
danielk197742741be2005-01-08 12:42:39 +0000634 { "btree_from_db", (Tcl_CmdProc*)btree_from_db },
danielk197730548662009-07-09 05:07:37 +0000635 { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb },
636 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }
drhc2eef3b2002-08-31 18:53:06 +0000637 };
638 int i;
639
640 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
641 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
642 }
danielk1977312d6b32004-06-29 13:18:23 +0000643
drh5c4d9702001-08-20 00:33:58 +0000644 return TCL_OK;
645}