blob: e460c42e46c092ae67572eeb59dce1bd2cc0d7ce [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];
drhc02a43a2012-01-10 23:18:38 +000069 int n;
70 char *zFilename;
drh75c014c2010-08-30 15:02:28 +000071 if( argc!=3 ){
drh5c4d9702001-08-20 00:33:58 +000072 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drh23e11ca2004-05-04 17:27:28 +000073 " FILENAME NCACHE FLAGS\"", 0);
drh5c4d9702001-08-20 00:33:58 +000074 return TCL_ERROR;
75 }
drh23e11ca2004-05-04 17:27:28 +000076 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
drha2451e22007-08-20 23:50:24 +000077 nRefSqlite3++;
78 if( nRefSqlite3==1 ){
79 sDb.pVfs = sqlite3_vfs_find(0);
danielk197759f8c082008-06-18 17:09:10 +000080 sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
drh27641702007-08-22 02:56:42 +000081 sqlite3_mutex_enter(sDb.mutex);
drha2451e22007-08-20 23:50:24 +000082 }
drh83cc1392012-04-19 18:04:28 +000083 n = (int)strlen(argv[1]);
drhc02a43a2012-01-10 23:18:38 +000084 zFilename = sqlite3_malloc( n+2 );
85 if( zFilename==0 ) return TCL_ERROR;
86 memcpy(zFilename, argv[1], n+1);
87 zFilename[n+1] = 0;
88 rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0,
drh33f4e022007-09-03 15:19:34 +000089 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
drhc02a43a2012-01-10 23:18:38 +000090 sqlite3_free(zFilename);
drh5c4d9702001-08-20 00:33:58 +000091 if( rc!=SQLITE_OK ){
92 Tcl_AppendResult(interp, errorName(rc), 0);
93 return TCL_ERROR;
94 }
drh90f5ecb2004-07-22 01:19:35 +000095 sqlite3BtreeSetCacheSize(pBt, nCache);
drhfe63d1c2004-09-08 20:13:04 +000096 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
drh5c4d9702001-08-20 00:33:58 +000097 Tcl_AppendResult(interp, zBuf, 0);
98 return TCL_OK;
99}
100
101/*
102** Usage: btree_close ID
103**
104** Close the given database.
105*/
106static int btree_close(
107 void *NotUsed,
108 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
109 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000110 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000111){
112 Btree *pBt;
113 int rc;
114 if( argc!=2 ){
115 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
116 " ID\"", 0);
117 return TCL_ERROR;
118 }
drhe8f52c52008-07-12 14:52:20 +0000119 pBt = sqlite3TestTextToPtr(argv[1]);
drh23e11ca2004-05-04 17:27:28 +0000120 rc = sqlite3BtreeClose(pBt);
drh5c4d9702001-08-20 00:33:58 +0000121 if( rc!=SQLITE_OK ){
122 Tcl_AppendResult(interp, errorName(rc), 0);
123 return TCL_ERROR;
124 }
drha2451e22007-08-20 23:50:24 +0000125 nRefSqlite3--;
126 if( nRefSqlite3==0 ){
drh27641702007-08-22 02:56:42 +0000127 sqlite3_mutex_leave(sDb.mutex);
drha2451e22007-08-20 23:50:24 +0000128 sqlite3_mutex_free(sDb.mutex);
129 sDb.mutex = 0;
drha2451e22007-08-20 23:50:24 +0000130 sDb.pVfs = 0;
131 }
drh5c4d9702001-08-20 00:33:58 +0000132 return TCL_OK;
133}
134
drh27641702007-08-22 02:56:42 +0000135
drh5c4d9702001-08-20 00:33:58 +0000136/*
137** Usage: btree_begin_transaction ID
138**
139** Start a new transaction
140*/
141static int btree_begin_transaction(
142 void *NotUsed,
143 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
144 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000145 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000146){
147 Btree *pBt;
148 int rc;
149 if( argc!=2 ){
150 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
151 " ID\"", 0);
152 return TCL_ERROR;
153 }
drhe8f52c52008-07-12 14:52:20 +0000154 pBt = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000155 sqlite3BtreeEnter(pBt);
danielk197740b38dc2004-06-26 08:38:24 +0000156 rc = sqlite3BtreeBeginTrans(pBt, 1);
drhff0587c2007-08-29 17:43:19 +0000157 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000158 if( rc!=SQLITE_OK ){
159 Tcl_AppendResult(interp, errorName(rc), 0);
160 return TCL_ERROR;
161 }
162 return TCL_OK;
163}
164
165/*
drh5c4d9702001-08-20 00:33:58 +0000166** Usage: btree_pager_stats ID
167**
168** Returns pager statistics
169*/
170static int btree_pager_stats(
171 void *NotUsed,
172 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
173 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000174 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000175){
176 Btree *pBt;
177 int i;
178 int *a;
179
180 if( argc!=2 ){
181 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
182 " ID\"", 0);
183 return TCL_ERROR;
184 }
drhe8f52c52008-07-12 14:52:20 +0000185 pBt = sqlite3TestTextToPtr(argv[1]);
danielk1977f3c62652007-08-30 08:27:39 +0000186
187 /* Normally in this file, with a b-tree handle opened using the
188 ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
189 ** But this function is sometimes called with a btree handle obtained
190 ** from an open SQLite connection (using [btree_from_db]). In this case
191 ** we need to obtain the mutex for the controlling SQLite handle before
192 ** it is safe to call sqlite3BtreeEnter().
193 */
drhe5fe6902007-12-07 18:55:28 +0000194 sqlite3_mutex_enter(pBt->db->mutex);
danielk1977f3c62652007-08-30 08:27:39 +0000195
drh27641702007-08-22 02:56:42 +0000196 sqlite3BtreeEnter(pBt);
danielk19773b8a05f2007-03-19 17:44:26 +0000197 a = sqlite3PagerStats(sqlite3BtreePager(pBt));
danielk197742741be2005-01-08 12:42:39 +0000198 for(i=0; i<11; i++){
drh5c4d9702001-08-20 00:33:58 +0000199 static char *zName[] = {
200 "ref", "page", "max", "size", "state", "err",
danielk197742741be2005-01-08 12:42:39 +0000201 "hit", "miss", "ovfl", "read", "write"
drh5c4d9702001-08-20 00:33:58 +0000202 };
203 char zBuf[100];
204 Tcl_AppendElement(interp, zName[i]);
drhfe63d1c2004-09-08 20:13:04 +0000205 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
drh5c4d9702001-08-20 00:33:58 +0000206 Tcl_AppendElement(interp, zBuf);
207 }
drh27641702007-08-22 02:56:42 +0000208 sqlite3BtreeLeave(pBt);
danielk1977f3c62652007-08-30 08:27:39 +0000209
210 /* Release the mutex on the SQLite handle that controls this b-tree */
drhe5fe6902007-12-07 18:55:28 +0000211 sqlite3_mutex_leave(pBt->db->mutex);
drh5c4d9702001-08-20 00:33:58 +0000212 return TCL_OK;
213}
214
215/*
drhecdc7532001-09-23 02:35:53 +0000216** Usage: btree_cursor ID TABLENUM WRITEABLE
drh5c4d9702001-08-20 00:33:58 +0000217**
218** Create a new cursor. Return the ID for the cursor.
219*/
220static int btree_cursor(
221 void *NotUsed,
222 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
223 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000224 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000225){
226 Btree *pBt;
227 int iTable;
228 BtCursor *pCur;
dan93a696f2010-01-07 11:27:30 +0000229 int rc = SQLITE_OK;
drhecdc7532001-09-23 02:35:53 +0000230 int wrFlag;
drh5c4d9702001-08-20 00:33:58 +0000231 char zBuf[30];
232
drhecdc7532001-09-23 02:35:53 +0000233 if( argc!=4 ){
drh5c4d9702001-08-20 00:33:58 +0000234 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drhecdc7532001-09-23 02:35:53 +0000235 " ID TABLENUM WRITEABLE\"", 0);
drh5c4d9702001-08-20 00:33:58 +0000236 return TCL_ERROR;
237 }
drhe8f52c52008-07-12 14:52:20 +0000238 pBt = sqlite3TestTextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000239 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
drhecdc7532001-09-23 02:35:53 +0000240 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
danielk1977cd3e8f72008-03-25 09:47:35 +0000241 pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
242 memset(pCur, 0, sqlite3BtreeCursorSize());
drhff0587c2007-08-29 17:43:19 +0000243 sqlite3BtreeEnter(pBt);
dan93a696f2010-01-07 11:27:30 +0000244#ifndef SQLITE_OMIT_SHARED_CACHE
danielk197796d48e92009-06-29 06:00:37 +0000245 rc = sqlite3BtreeLockTable(pBt, iTable, wrFlag);
dan93a696f2010-01-07 11:27:30 +0000246#endif
danielk197796d48e92009-06-29 06:00:37 +0000247 if( rc==SQLITE_OK ){
248 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
249 }
drhff0587c2007-08-29 17:43:19 +0000250 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000251 if( rc ){
danielk1977cd3e8f72008-03-25 09:47:35 +0000252 ckfree((char *)pCur);
drh5c4d9702001-08-20 00:33:58 +0000253 Tcl_AppendResult(interp, errorName(rc), 0);
254 return TCL_ERROR;
255 }
drhfe63d1c2004-09-08 20:13:04 +0000256 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
drh5c4d9702001-08-20 00:33:58 +0000257 Tcl_AppendResult(interp, zBuf, 0);
258 return SQLITE_OK;
259}
260
261/*
262** Usage: btree_close_cursor ID
263**
264** Close a cursor opened using btree_cursor.
265*/
266static int btree_close_cursor(
267 void *NotUsed,
268 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
269 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000270 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000271){
272 BtCursor *pCur;
drhff0587c2007-08-29 17:43:19 +0000273 Btree *pBt;
drh5c4d9702001-08-20 00:33:58 +0000274 int rc;
275
276 if( argc!=2 ){
277 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
278 " ID\"", 0);
279 return TCL_ERROR;
280 }
drhe8f52c52008-07-12 14:52:20 +0000281 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000282 pBt = pCur->pBtree;
283 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000284 rc = sqlite3BtreeCloseCursor(pCur);
drhff0587c2007-08-29 17:43:19 +0000285 sqlite3BtreeLeave(pBt);
danielk1977cd3e8f72008-03-25 09:47:35 +0000286 ckfree((char *)pCur);
drh5c4d9702001-08-20 00:33:58 +0000287 if( rc ){
288 Tcl_AppendResult(interp, errorName(rc), 0);
289 return TCL_ERROR;
290 }
291 return SQLITE_OK;
292}
293
294/*
drh5c4d9702001-08-20 00:33:58 +0000295** Usage: btree_next ID
296**
drh2dcc9aa2002-12-04 13:40:25 +0000297** Move the cursor to the next entry in the table. Return 0 on success
298** or 1 if the cursor was already on the last entry in the table or if
299** the table is empty.
drh5c4d9702001-08-20 00:33:58 +0000300*/
301static int btree_next(
302 void *NotUsed,
303 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
304 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000305 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000306){
307 BtCursor *pCur;
308 int rc;
drh0de8c112002-07-06 16:32:14 +0000309 int res = 0;
310 char zBuf[100];
drh5c4d9702001-08-20 00:33:58 +0000311
312 if( argc!=2 ){
313 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
314 " ID\"", 0);
315 return TCL_ERROR;
316 }
drhe8f52c52008-07-12 14:52:20 +0000317 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000318 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000319 rc = sqlite3BtreeNext(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000320 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000321 if( rc ){
322 Tcl_AppendResult(interp, errorName(rc), 0);
323 return TCL_ERROR;
324 }
drhfe63d1c2004-09-08 20:13:04 +0000325 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000326 Tcl_AppendResult(interp, zBuf, 0);
327 return SQLITE_OK;
328}
329
330/*
331** Usage: btree_first ID
332**
drh2dcc9aa2002-12-04 13:40:25 +0000333** Move the cursor to the first entry in the table. Return 0 if the
334** cursor was left point to something and 1 if the table is empty.
drh0de8c112002-07-06 16:32:14 +0000335*/
336static int btree_first(
337 void *NotUsed,
338 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
339 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000340 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +0000341){
342 BtCursor *pCur;
343 int rc;
344 int res = 0;
345 char zBuf[100];
346
347 if( argc!=2 ){
348 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
349 " ID\"", 0);
350 return TCL_ERROR;
351 }
drhe8f52c52008-07-12 14:52:20 +0000352 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000353 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000354 rc = sqlite3BtreeFirst(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000355 sqlite3BtreeLeave(pCur->pBtree);
drh0de8c112002-07-06 16:32:14 +0000356 if( rc ){
357 Tcl_AppendResult(interp, errorName(rc), 0);
358 return TCL_ERROR;
359 }
drhfe63d1c2004-09-08 20:13:04 +0000360 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000361 Tcl_AppendResult(interp, zBuf, 0);
drh5c4d9702001-08-20 00:33:58 +0000362 return SQLITE_OK;
363}
364
365/*
drhc39e0002004-05-07 23:50:57 +0000366** Usage: btree_eof ID
367**
368** Return TRUE if the given cursor is not pointing at a valid entry.
369** Return FALSE if the cursor does point to a valid entry.
370*/
371static int btree_eof(
372 void *NotUsed,
373 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
374 int argc, /* Number of arguments */
375 const char **argv /* Text of each argument */
376){
377 BtCursor *pCur;
drhff0587c2007-08-29 17:43:19 +0000378 int rc;
drhc39e0002004-05-07 23:50:57 +0000379 char zBuf[50];
380
381 if( argc!=2 ){
382 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
383 " ID\"", 0);
384 return TCL_ERROR;
385 }
drhe8f52c52008-07-12 14:52:20 +0000386 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000387 sqlite3BtreeEnter(pCur->pBtree);
388 rc = sqlite3BtreeEof(pCur);
389 sqlite3BtreeLeave(pCur->pBtree);
390 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
drhc39e0002004-05-07 23:50:57 +0000391 Tcl_AppendResult(interp, zBuf, 0);
392 return SQLITE_OK;
393}
394
395/*
drh0de8c112002-07-06 16:32:14 +0000396** Usage: btree_payload_size ID
397**
398** Return the number of bytes of payload
399*/
400static int btree_payload_size(
401 void *NotUsed,
402 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
403 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000404 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +0000405){
406 BtCursor *pCur;
drh4fc0fb42004-05-07 02:26:28 +0000407 int n2;
drha34b6762004-05-07 13:30:42 +0000408 u64 n1;
drh0de8c112002-07-06 16:32:14 +0000409 char zBuf[50];
410
411 if( argc!=2 ){
412 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
413 " ID\"", 0);
414 return TCL_ERROR;
415 }
drhe8f52c52008-07-12 14:52:20 +0000416 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000417 sqlite3BtreeEnter(pCur->pBtree);
danielk197730548662009-07-09 05:07:37 +0000418
419 /* The cursor may be in "require-seek" state. If this is the case, the
420 ** call to BtreeDataSize() will fix it. */
421 sqlite3BtreeDataSize(pCur, (u32*)&n2);
shanecbcadd42009-07-09 03:20:46 +0000422 if( pCur->apPage[pCur->iPage]->intKey ){
drha34b6762004-05-07 13:30:42 +0000423 n1 = 0;
424 }else{
drh03d847e2005-12-09 20:21:58 +0000425 sqlite3BtreeKeySize(pCur, (i64*)&n1);
drha34b6762004-05-07 13:30:42 +0000426 }
drhff0587c2007-08-29 17:43:19 +0000427 sqlite3BtreeLeave(pCur->pBtree);
drhfe63d1c2004-09-08 20:13:04 +0000428 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
drh0de8c112002-07-06 16:32:14 +0000429 Tcl_AppendResult(interp, zBuf, 0);
drh0de8c112002-07-06 16:32:14 +0000430 return SQLITE_OK;
431}
432
433/*
drh6d2fb152004-05-14 16:50:06 +0000434** usage: varint_test START MULTIPLIER COUNT INCREMENT
435**
shane3f8d5cf2008-04-24 19:15:09 +0000436** This command tests the putVarint() and getVarint()
drh6d2fb152004-05-14 16:50:06 +0000437** routines, both for accuracy and for speed.
438**
shane3f8d5cf2008-04-24 19:15:09 +0000439** An integer is written using putVarint() and read back with
440** getVarint() and varified to be unchanged. This repeats COUNT
drh6d2fb152004-05-14 16:50:06 +0000441** times. The first integer is START*MULTIPLIER. Each iteration
442** increases the integer by INCREMENT.
443**
444** This command returns nothing if it works. It returns an error message
445** if something goes wrong.
446*/
447static int btree_varint_test(
448 void *NotUsed,
449 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
450 int argc, /* Number of arguments */
451 const char **argv /* Text of each argument */
452){
453 u32 start, mult, count, incr;
454 u64 in, out;
drhd8820e82004-05-18 15:57:42 +0000455 int n1, n2, i, j;
drh6d2fb152004-05-14 16:50:06 +0000456 unsigned char zBuf[100];
457 if( argc!=5 ){
458 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
459 " START MULTIPLIER COUNT INCREMENT\"", 0);
460 return TCL_ERROR;
461 }
462 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
463 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
464 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
465 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
466 in = start;
467 in *= mult;
drh7da5fcb2012-03-30 14:59:43 +0000468 for(i=0; i<(int)count; i++){
drhd8820e82004-05-18 15:57:42 +0000469 char zErr[200];
shane3f8d5cf2008-04-24 19:15:09 +0000470 n1 = putVarint(zBuf, in);
drh6d2fb152004-05-14 16:50:06 +0000471 if( n1>9 || n1<1 ){
shane3f8d5cf2008-04-24 19:15:09 +0000472 sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
drhd8820e82004-05-18 15:57:42 +0000473 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000474 return TCL_ERROR;
475 }
shane3f8d5cf2008-04-24 19:15:09 +0000476 n2 = getVarint(zBuf, &out);
drh6d2fb152004-05-14 16:50:06 +0000477 if( n1!=n2 ){
shane3f8d5cf2008-04-24 19:15:09 +0000478 sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
drhd8820e82004-05-18 15:57:42 +0000479 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000480 return TCL_ERROR;
481 }
482 if( in!=out ){
drhd8820e82004-05-18 15:57:42 +0000483 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
484 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000485 return TCL_ERROR;
486 }
drh9d213ef2004-06-30 04:02:11 +0000487 if( (in & 0xffffffff)==in ){
488 u32 out32;
shane3f8d5cf2008-04-24 19:15:09 +0000489 n2 = getVarint32(zBuf, out32);
drh9d213ef2004-06-30 04:02:11 +0000490 out = out32;
491 if( n1!=n2 ){
shane3f8d5cf2008-04-24 19:15:09 +0000492 sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d",
drh9d213ef2004-06-30 04:02:11 +0000493 n1, n2);
494 Tcl_AppendResult(interp, zErr, 0);
495 return TCL_ERROR;
496 }
497 if( in!=out ){
498 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
499 in, out);
500 Tcl_AppendResult(interp, zErr, 0);
501 return TCL_ERROR;
502 }
503 }
drhd8820e82004-05-18 15:57:42 +0000504
505 /* In order to get realistic timings, run getVarint 19 more times.
506 ** This is because getVarint is called about 20 times more often
507 ** than putVarint.
508 */
509 for(j=0; j<19; j++){
shane3f8d5cf2008-04-24 19:15:09 +0000510 getVarint(zBuf, &out);
drhd8820e82004-05-18 15:57:42 +0000511 }
drh6d2fb152004-05-14 16:50:06 +0000512 in += incr;
513 }
514 return TCL_OK;
515}
drh9b171272004-05-08 02:03:22 +0000516
517/*
danielk197742741be2005-01-08 12:42:39 +0000518** usage: btree_from_db DB-HANDLE
519**
520** This command returns the btree handle for the main database associated
521** with the database-handle passed as the argument. Example usage:
522**
523** sqlite3 db test.db
524** set bt [btree_from_db db]
525*/
526static int btree_from_db(
527 void *NotUsed,
528 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
529 int argc, /* Number of arguments */
530 const char **argv /* Text of each argument */
531){
532 char zBuf[100];
533 Tcl_CmdInfo info;
534 sqlite3 *db;
535 Btree *pBt;
danielk197763c64f32007-05-17 14:45:12 +0000536 int iDb = 0;
danielk197742741be2005-01-08 12:42:39 +0000537
danielk197763c64f32007-05-17 14:45:12 +0000538 if( argc!=2 && argc!=3 ){
danielk197742741be2005-01-08 12:42:39 +0000539 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
danielk197763c64f32007-05-17 14:45:12 +0000540 " DB-HANDLE ?N?\"", 0);
danielk197742741be2005-01-08 12:42:39 +0000541 return TCL_ERROR;
542 }
543
544 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
545 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
546 return TCL_ERROR;
547 }
danielk197763c64f32007-05-17 14:45:12 +0000548 if( argc==3 ){
549 iDb = atoi(argv[2]);
550 }
551
danielk197742741be2005-01-08 12:42:39 +0000552 db = *((sqlite3 **)info.objClientData);
553 assert( db );
554
danielk197763c64f32007-05-17 14:45:12 +0000555 pBt = db->aDb[iDb].pBt;
danielk197742741be2005-01-08 12:42:39 +0000556 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
557 Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
558 return TCL_OK;
559}
560
danielk197717b90b52008-06-06 11:11:25 +0000561/*
562** Usage: btree_ismemdb ID
563**
564** Return true if the B-Tree is in-memory.
565*/
566static int btree_ismemdb(
567 void *NotUsed,
568 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
569 int argc, /* Number of arguments */
570 const char **argv /* Text of each argument */
571){
572 Btree *pBt;
573 int res;
574
575 if( argc!=2 ){
576 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
577 " ID\"", 0);
578 return TCL_ERROR;
579 }
drhe8f52c52008-07-12 14:52:20 +0000580 pBt = sqlite3TestTextToPtr(argv[1]);
danielk197717b90b52008-06-06 11:11:25 +0000581 sqlite3_mutex_enter(pBt->db->mutex);
582 sqlite3BtreeEnter(pBt);
583 res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt));
584 sqlite3BtreeLeave(pBt);
585 sqlite3_mutex_leave(pBt->db->mutex);
586 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
587 return SQLITE_OK;
588}
589
danielk197730548662009-07-09 05:07:37 +0000590/*
591** usage: btree_set_cache_size ID NCACHE
592**
593** Set the size of the cache used by btree $ID.
594*/
595static int btree_set_cache_size(
596 void *NotUsed,
597 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
598 int argc, /* Number of arguments */
599 const char **argv /* Text of each argument */
600){
601 int nCache;
602 Btree *pBt;
603
604 if( argc!=3 ){
605 Tcl_AppendResult(
606 interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0);
607 return TCL_ERROR;
608 }
609 pBt = sqlite3TestTextToPtr(argv[1]);
610 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
611
612 sqlite3_mutex_enter(pBt->db->mutex);
613 sqlite3BtreeEnter(pBt);
614 sqlite3BtreeSetCacheSize(pBt, nCache);
615 sqlite3BtreeLeave(pBt);
616 sqlite3_mutex_leave(pBt->db->mutex);
617 return TCL_OK;
618}
619
620
danielk19771ad7f642005-01-20 05:24:32 +0000621
danielk197742741be2005-01-08 12:42:39 +0000622/*
drh5c4d9702001-08-20 00:33:58 +0000623** Register commands with the TCL interpreter.
624*/
625int Sqlitetest3_Init(Tcl_Interp *interp){
drhc2eef3b2002-08-31 18:53:06 +0000626 static struct {
627 char *zName;
628 Tcl_CmdProc *xProc;
629 } aCmd[] = {
630 { "btree_open", (Tcl_CmdProc*)btree_open },
631 { "btree_close", (Tcl_CmdProc*)btree_close },
632 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction },
drhc2eef3b2002-08-31 18:53:06 +0000633 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats },
drhc2eef3b2002-08-31 18:53:06 +0000634 { "btree_cursor", (Tcl_CmdProc*)btree_cursor },
635 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor },
drhc2eef3b2002-08-31 18:53:06 +0000636 { "btree_next", (Tcl_CmdProc*)btree_next },
drhc39e0002004-05-07 23:50:57 +0000637 { "btree_eof", (Tcl_CmdProc*)btree_eof },
drhc2eef3b2002-08-31 18:53:06 +0000638 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
639 { "btree_first", (Tcl_CmdProc*)btree_first },
drh6d2fb152004-05-14 16:50:06 +0000640 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test },
danielk197742741be2005-01-08 12:42:39 +0000641 { "btree_from_db", (Tcl_CmdProc*)btree_from_db },
danielk197730548662009-07-09 05:07:37 +0000642 { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb },
643 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }
drhc2eef3b2002-08-31 18:53:06 +0000644 };
645 int i;
646
647 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
648 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
649 }
danielk1977312d6b32004-06-29 13:18:23 +0000650
drh5c4d9702001-08-20 00:33:58 +0000651 return TCL_OK;
652}