blob: ef004ca7133aa239887d9532758d01d147d7a298 [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/*
drh75c014c2010-08-30 15:02:28 +000056** Usage: btree_open FILENAME NCACHE
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;
drh75c014c2010-08-30 15:02:28 +000067 int rc, nCache;
drh5c4d9702001-08-20 00:33:58 +000068 char zBuf[100];
drh75c014c2010-08-30 15:02:28 +000069 if( argc!=3 ){
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;
drha2451e22007-08-20 23:50:24 +000075 nRefSqlite3++;
76 if( nRefSqlite3==1 ){
77 sDb.pVfs = sqlite3_vfs_find(0);
danielk197759f8c082008-06-18 17:09:10 +000078 sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
drh27641702007-08-22 02:56:42 +000079 sqlite3_mutex_enter(sDb.mutex);
drha2451e22007-08-20 23:50:24 +000080 }
drh75c014c2010-08-30 15:02:28 +000081 rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, 0,
drh33f4e022007-09-03 15:19:34 +000082 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
drh5c4d9702001-08-20 00:33:58 +000083 if( rc!=SQLITE_OK ){
84 Tcl_AppendResult(interp, errorName(rc), 0);
85 return TCL_ERROR;
86 }
drh90f5ecb2004-07-22 01:19:35 +000087 sqlite3BtreeSetCacheSize(pBt, nCache);
drhfe63d1c2004-09-08 20:13:04 +000088 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
drh5c4d9702001-08-20 00:33:58 +000089 Tcl_AppendResult(interp, zBuf, 0);
90 return TCL_OK;
91}
92
93/*
94** Usage: btree_close ID
95**
96** Close the given database.
97*/
98static int btree_close(
99 void *NotUsed,
100 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
101 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000102 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000103){
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 }
drhe8f52c52008-07-12 14:52:20 +0000111 pBt = sqlite3TestTextToPtr(argv[1]);
drh23e11ca2004-05-04 17:27:28 +0000112 rc = sqlite3BtreeClose(pBt);
drh5c4d9702001-08-20 00:33:58 +0000113 if( rc!=SQLITE_OK ){
114 Tcl_AppendResult(interp, errorName(rc), 0);
115 return TCL_ERROR;
116 }
drha2451e22007-08-20 23:50:24 +0000117 nRefSqlite3--;
118 if( nRefSqlite3==0 ){
drh27641702007-08-22 02:56:42 +0000119 sqlite3_mutex_leave(sDb.mutex);
drha2451e22007-08-20 23:50:24 +0000120 sqlite3_mutex_free(sDb.mutex);
121 sDb.mutex = 0;
drha2451e22007-08-20 23:50:24 +0000122 sDb.pVfs = 0;
123 }
drh5c4d9702001-08-20 00:33:58 +0000124 return TCL_OK;
125}
126
drh27641702007-08-22 02:56:42 +0000127
drh5c4d9702001-08-20 00:33:58 +0000128/*
129** Usage: btree_begin_transaction ID
130**
131** Start a new transaction
132*/
133static int btree_begin_transaction(
134 void *NotUsed,
135 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
136 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000137 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000138){
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 }
drhe8f52c52008-07-12 14:52:20 +0000146 pBt = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000147 sqlite3BtreeEnter(pBt);
danielk197740b38dc2004-06-26 08:38:24 +0000148 rc = sqlite3BtreeBeginTrans(pBt, 1);
drhff0587c2007-08-29 17:43:19 +0000149 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000150 if( rc!=SQLITE_OK ){
151 Tcl_AppendResult(interp, errorName(rc), 0);
152 return TCL_ERROR;
153 }
154 return TCL_OK;
155}
156
157/*
drh5c4d9702001-08-20 00:33:58 +0000158** Usage: btree_pager_stats ID
159**
160** Returns pager statistics
161*/
162static int btree_pager_stats(
163 void *NotUsed,
164 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
165 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000166 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000167){
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 }
drhe8f52c52008-07-12 14:52:20 +0000177 pBt = sqlite3TestTextToPtr(argv[1]);
danielk1977f3c62652007-08-30 08:27:39 +0000178
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 */
drhe5fe6902007-12-07 18:55:28 +0000186 sqlite3_mutex_enter(pBt->db->mutex);
danielk1977f3c62652007-08-30 08:27:39 +0000187
drh27641702007-08-22 02:56:42 +0000188 sqlite3BtreeEnter(pBt);
danielk19773b8a05f2007-03-19 17:44:26 +0000189 a = sqlite3PagerStats(sqlite3BtreePager(pBt));
danielk197742741be2005-01-08 12:42:39 +0000190 for(i=0; i<11; i++){
drh5c4d9702001-08-20 00:33:58 +0000191 static char *zName[] = {
192 "ref", "page", "max", "size", "state", "err",
danielk197742741be2005-01-08 12:42:39 +0000193 "hit", "miss", "ovfl", "read", "write"
drh5c4d9702001-08-20 00:33:58 +0000194 };
195 char zBuf[100];
196 Tcl_AppendElement(interp, zName[i]);
drhfe63d1c2004-09-08 20:13:04 +0000197 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
drh5c4d9702001-08-20 00:33:58 +0000198 Tcl_AppendElement(interp, zBuf);
199 }
drh27641702007-08-22 02:56:42 +0000200 sqlite3BtreeLeave(pBt);
danielk1977f3c62652007-08-30 08:27:39 +0000201
202 /* Release the mutex on the SQLite handle that controls this b-tree */
drhe5fe6902007-12-07 18:55:28 +0000203 sqlite3_mutex_leave(pBt->db->mutex);
drh5c4d9702001-08-20 00:33:58 +0000204 return TCL_OK;
205}
206
207/*
drhecdc7532001-09-23 02:35:53 +0000208** Usage: btree_cursor ID TABLENUM WRITEABLE
drh5c4d9702001-08-20 00:33:58 +0000209**
210** Create a new cursor. Return the ID for the cursor.
211*/
212static int btree_cursor(
213 void *NotUsed,
214 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
215 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000216 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000217){
218 Btree *pBt;
219 int iTable;
220 BtCursor *pCur;
dan93a696f2010-01-07 11:27:30 +0000221 int rc = SQLITE_OK;
drhecdc7532001-09-23 02:35:53 +0000222 int wrFlag;
drh5c4d9702001-08-20 00:33:58 +0000223 char zBuf[30];
224
drhecdc7532001-09-23 02:35:53 +0000225 if( argc!=4 ){
drh5c4d9702001-08-20 00:33:58 +0000226 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drhecdc7532001-09-23 02:35:53 +0000227 " ID TABLENUM WRITEABLE\"", 0);
drh5c4d9702001-08-20 00:33:58 +0000228 return TCL_ERROR;
229 }
drhe8f52c52008-07-12 14:52:20 +0000230 pBt = sqlite3TestTextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000231 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
drhecdc7532001-09-23 02:35:53 +0000232 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
danielk1977cd3e8f72008-03-25 09:47:35 +0000233 pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
234 memset(pCur, 0, sqlite3BtreeCursorSize());
drhff0587c2007-08-29 17:43:19 +0000235 sqlite3BtreeEnter(pBt);
dan93a696f2010-01-07 11:27:30 +0000236#ifndef SQLITE_OMIT_SHARED_CACHE
danielk197796d48e92009-06-29 06:00:37 +0000237 rc = sqlite3BtreeLockTable(pBt, iTable, wrFlag);
dan93a696f2010-01-07 11:27:30 +0000238#endif
danielk197796d48e92009-06-29 06:00:37 +0000239 if( rc==SQLITE_OK ){
240 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
241 }
drhff0587c2007-08-29 17:43:19 +0000242 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000243 if( rc ){
danielk1977cd3e8f72008-03-25 09:47:35 +0000244 ckfree((char *)pCur);
drh5c4d9702001-08-20 00:33:58 +0000245 Tcl_AppendResult(interp, errorName(rc), 0);
246 return TCL_ERROR;
247 }
drhfe63d1c2004-09-08 20:13:04 +0000248 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
drh5c4d9702001-08-20 00:33:58 +0000249 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*/
258static int btree_close_cursor(
259 void *NotUsed,
260 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
261 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000262 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000263){
264 BtCursor *pCur;
drhff0587c2007-08-29 17:43:19 +0000265 Btree *pBt;
drh5c4d9702001-08-20 00:33:58 +0000266 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 }
drhe8f52c52008-07-12 14:52:20 +0000273 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000274 pBt = pCur->pBtree;
275 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000276 rc = sqlite3BtreeCloseCursor(pCur);
drhff0587c2007-08-29 17:43:19 +0000277 sqlite3BtreeLeave(pBt);
danielk1977cd3e8f72008-03-25 09:47:35 +0000278 ckfree((char *)pCur);
drh5c4d9702001-08-20 00:33:58 +0000279 if( rc ){
280 Tcl_AppendResult(interp, errorName(rc), 0);
281 return TCL_ERROR;
282 }
283 return SQLITE_OK;
284}
285
286/*
drh5c4d9702001-08-20 00:33:58 +0000287** Usage: btree_next ID
288**
drh2dcc9aa2002-12-04 13:40:25 +0000289** 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.
drh5c4d9702001-08-20 00:33:58 +0000292*/
293static int btree_next(
294 void *NotUsed,
295 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
296 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000297 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000298){
299 BtCursor *pCur;
300 int rc;
drh0de8c112002-07-06 16:32:14 +0000301 int res = 0;
302 char zBuf[100];
drh5c4d9702001-08-20 00:33:58 +0000303
304 if( argc!=2 ){
305 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
306 " ID\"", 0);
307 return TCL_ERROR;
308 }
drhe8f52c52008-07-12 14:52:20 +0000309 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000310 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000311 rc = sqlite3BtreeNext(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000312 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000313 if( rc ){
314 Tcl_AppendResult(interp, errorName(rc), 0);
315 return TCL_ERROR;
316 }
drhfe63d1c2004-09-08 20:13:04 +0000317 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000318 Tcl_AppendResult(interp, zBuf, 0);
319 return SQLITE_OK;
320}
321
322/*
323** Usage: btree_first ID
324**
drh2dcc9aa2002-12-04 13:40:25 +0000325** 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.
drh0de8c112002-07-06 16:32:14 +0000327*/
328static int btree_first(
329 void *NotUsed,
330 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
331 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000332 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +0000333){
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 }
drhe8f52c52008-07-12 14:52:20 +0000344 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000345 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000346 rc = sqlite3BtreeFirst(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000347 sqlite3BtreeLeave(pCur->pBtree);
drh0de8c112002-07-06 16:32:14 +0000348 if( rc ){
349 Tcl_AppendResult(interp, errorName(rc), 0);
350 return TCL_ERROR;
351 }
drhfe63d1c2004-09-08 20:13:04 +0000352 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000353 Tcl_AppendResult(interp, zBuf, 0);
drh5c4d9702001-08-20 00:33:58 +0000354 return SQLITE_OK;
355}
356
357/*
drhc39e0002004-05-07 23:50:57 +0000358** 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*/
363static 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;
drhff0587c2007-08-29 17:43:19 +0000370 int rc;
drhc39e0002004-05-07 23:50:57 +0000371 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 }
drhe8f52c52008-07-12 14:52:20 +0000378 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000379 sqlite3BtreeEnter(pCur->pBtree);
380 rc = sqlite3BtreeEof(pCur);
381 sqlite3BtreeLeave(pCur->pBtree);
382 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
drhc39e0002004-05-07 23:50:57 +0000383 Tcl_AppendResult(interp, zBuf, 0);
384 return SQLITE_OK;
385}
386
387/*
drh0de8c112002-07-06 16:32:14 +0000388** Usage: btree_payload_size ID
389**
390** Return the number of bytes of payload
391*/
392static int btree_payload_size(
393 void *NotUsed,
394 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
395 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000396 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +0000397){
398 BtCursor *pCur;
drh4fc0fb42004-05-07 02:26:28 +0000399 int n2;
drha34b6762004-05-07 13:30:42 +0000400 u64 n1;
drh0de8c112002-07-06 16:32:14 +0000401 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 }
drhe8f52c52008-07-12 14:52:20 +0000408 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000409 sqlite3BtreeEnter(pCur->pBtree);
danielk197730548662009-07-09 05:07:37 +0000410
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);
shanecbcadd42009-07-09 03:20:46 +0000414 if( pCur->apPage[pCur->iPage]->intKey ){
drha34b6762004-05-07 13:30:42 +0000415 n1 = 0;
416 }else{
drh03d847e2005-12-09 20:21:58 +0000417 sqlite3BtreeKeySize(pCur, (i64*)&n1);
drha34b6762004-05-07 13:30:42 +0000418 }
drhff0587c2007-08-29 17:43:19 +0000419 sqlite3BtreeLeave(pCur->pBtree);
drhfe63d1c2004-09-08 20:13:04 +0000420 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
drh0de8c112002-07-06 16:32:14 +0000421 Tcl_AppendResult(interp, zBuf, 0);
drh0de8c112002-07-06 16:32:14 +0000422 return SQLITE_OK;
423}
424
425/*
drh6d2fb152004-05-14 16:50:06 +0000426** usage: varint_test START MULTIPLIER COUNT INCREMENT
427**
shane3f8d5cf2008-04-24 19:15:09 +0000428** This command tests the putVarint() and getVarint()
drh6d2fb152004-05-14 16:50:06 +0000429** routines, both for accuracy and for speed.
430**
shane3f8d5cf2008-04-24 19:15:09 +0000431** An integer is written using putVarint() and read back with
432** getVarint() and varified to be unchanged. This repeats COUNT
drh6d2fb152004-05-14 16:50:06 +0000433** 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*/
439static 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;
drhd8820e82004-05-18 15:57:42 +0000447 int n1, n2, i, j;
drh6d2fb152004-05-14 16:50:06 +0000448 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++){
drhd8820e82004-05-18 15:57:42 +0000461 char zErr[200];
shane3f8d5cf2008-04-24 19:15:09 +0000462 n1 = putVarint(zBuf, in);
drh6d2fb152004-05-14 16:50:06 +0000463 if( n1>9 || n1<1 ){
shane3f8d5cf2008-04-24 19:15:09 +0000464 sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
drhd8820e82004-05-18 15:57:42 +0000465 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000466 return TCL_ERROR;
467 }
shane3f8d5cf2008-04-24 19:15:09 +0000468 n2 = getVarint(zBuf, &out);
drh6d2fb152004-05-14 16:50:06 +0000469 if( n1!=n2 ){
shane3f8d5cf2008-04-24 19:15:09 +0000470 sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
drhd8820e82004-05-18 15:57:42 +0000471 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000472 return TCL_ERROR;
473 }
474 if( in!=out ){
drhd8820e82004-05-18 15:57:42 +0000475 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
476 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000477 return TCL_ERROR;
478 }
drh9d213ef2004-06-30 04:02:11 +0000479 if( (in & 0xffffffff)==in ){
480 u32 out32;
shane3f8d5cf2008-04-24 19:15:09 +0000481 n2 = getVarint32(zBuf, out32);
drh9d213ef2004-06-30 04:02:11 +0000482 out = out32;
483 if( n1!=n2 ){
shane3f8d5cf2008-04-24 19:15:09 +0000484 sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d",
drh9d213ef2004-06-30 04:02:11 +0000485 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 }
drhd8820e82004-05-18 15:57:42 +0000496
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++){
shane3f8d5cf2008-04-24 19:15:09 +0000502 getVarint(zBuf, &out);
drhd8820e82004-05-18 15:57:42 +0000503 }
drh6d2fb152004-05-14 16:50:06 +0000504 in += incr;
505 }
506 return TCL_OK;
507}
drh9b171272004-05-08 02:03:22 +0000508
509/*
danielk197742741be2005-01-08 12:42:39 +0000510** 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*/
518static 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;
danielk197763c64f32007-05-17 14:45:12 +0000528 int iDb = 0;
danielk197742741be2005-01-08 12:42:39 +0000529
danielk197763c64f32007-05-17 14:45:12 +0000530 if( argc!=2 && argc!=3 ){
danielk197742741be2005-01-08 12:42:39 +0000531 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
danielk197763c64f32007-05-17 14:45:12 +0000532 " DB-HANDLE ?N?\"", 0);
danielk197742741be2005-01-08 12:42:39 +0000533 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 }
danielk197763c64f32007-05-17 14:45:12 +0000540 if( argc==3 ){
541 iDb = atoi(argv[2]);
542 }
543
danielk197742741be2005-01-08 12:42:39 +0000544 db = *((sqlite3 **)info.objClientData);
545 assert( db );
546
danielk197763c64f32007-05-17 14:45:12 +0000547 pBt = db->aDb[iDb].pBt;
danielk197742741be2005-01-08 12:42:39 +0000548 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
549 Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
550 return TCL_OK;
551}
552
danielk197717b90b52008-06-06 11:11:25 +0000553/*
554** Usage: btree_ismemdb ID
555**
556** Return true if the B-Tree is in-memory.
557*/
558static 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 }
drhe8f52c52008-07-12 14:52:20 +0000572 pBt = sqlite3TestTextToPtr(argv[1]);
danielk197717b90b52008-06-06 11:11:25 +0000573 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
danielk197730548662009-07-09 05:07:37 +0000582/*
583** usage: btree_set_cache_size ID NCACHE
584**
585** Set the size of the cache used by btree $ID.
586*/
587static 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
danielk19771ad7f642005-01-20 05:24:32 +0000613
danielk197742741be2005-01-08 12:42:39 +0000614/*
drh5c4d9702001-08-20 00:33:58 +0000615** Register commands with the TCL interpreter.
616*/
617int Sqlitetest3_Init(Tcl_Interp *interp){
drhc2eef3b2002-08-31 18:53:06 +0000618 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 },
drhc2eef3b2002-08-31 18:53:06 +0000625 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats },
drhc2eef3b2002-08-31 18:53:06 +0000626 { "btree_cursor", (Tcl_CmdProc*)btree_cursor },
627 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor },
drhc2eef3b2002-08-31 18:53:06 +0000628 { "btree_next", (Tcl_CmdProc*)btree_next },
drhc39e0002004-05-07 23:50:57 +0000629 { "btree_eof", (Tcl_CmdProc*)btree_eof },
drhc2eef3b2002-08-31 18:53:06 +0000630 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
631 { "btree_first", (Tcl_CmdProc*)btree_first },
drh6d2fb152004-05-14 16:50:06 +0000632 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test },
danielk197742741be2005-01-08 12:42:39 +0000633 { "btree_from_db", (Tcl_CmdProc*)btree_from_db },
danielk197730548662009-07-09 05:07:37 +0000634 { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb },
635 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }
drhc2eef3b2002-08-31 18:53:06 +0000636 };
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 }
danielk1977312d6b32004-06-29 13:18:23 +0000642
drh5c4d9702001-08-20 00:33:58 +0000643 return TCL_OK;
644}