blob: 6995684c29f5650081f94f665403489ae9683c3e [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"
mistachkin52b1dbb2016-07-28 14:37:04 +000018#if defined(INCLUDE_SQLITE_TCL_H)
19# include "sqlite_tcl.h"
20#else
21# include "tcl.h"
22#endif
drh5c4d9702001-08-20 00:33:58 +000023#include <stdlib.h>
24#include <string.h>
25
mistachkine84d8d32013-04-29 03:09:10 +000026extern const char *sqlite3ErrName(int);
drh5c4d9702001-08-20 00:33:58 +000027
28/*
drha2451e22007-08-20 23:50:24 +000029** A bogus sqlite3 connection structure for use in the btree
30** tests.
31*/
32static sqlite3 sDb;
33static int nRefSqlite3 = 0;
34
35/*
drh75c014c2010-08-30 15:02:28 +000036** Usage: btree_open FILENAME NCACHE
drh5c4d9702001-08-20 00:33:58 +000037**
38** Open a new database
39*/
mistachkin7617e4a2016-07-28 17:11:20 +000040static int SQLITE_TCLAPI btree_open(
drh5c4d9702001-08-20 00:33:58 +000041 void *NotUsed,
42 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
43 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +000044 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +000045){
46 Btree *pBt;
drh75c014c2010-08-30 15:02:28 +000047 int rc, nCache;
drh5c4d9702001-08-20 00:33:58 +000048 char zBuf[100];
drhc02a43a2012-01-10 23:18:38 +000049 int n;
50 char *zFilename;
drh75c014c2010-08-30 15:02:28 +000051 if( argc!=3 ){
drh5c4d9702001-08-20 00:33:58 +000052 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drh23e11ca2004-05-04 17:27:28 +000053 " FILENAME NCACHE FLAGS\"", 0);
drh5c4d9702001-08-20 00:33:58 +000054 return TCL_ERROR;
55 }
drh23e11ca2004-05-04 17:27:28 +000056 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
drha2451e22007-08-20 23:50:24 +000057 nRefSqlite3++;
58 if( nRefSqlite3==1 ){
59 sDb.pVfs = sqlite3_vfs_find(0);
danielk197759f8c082008-06-18 17:09:10 +000060 sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
drh27641702007-08-22 02:56:42 +000061 sqlite3_mutex_enter(sDb.mutex);
drha2451e22007-08-20 23:50:24 +000062 }
drh83cc1392012-04-19 18:04:28 +000063 n = (int)strlen(argv[1]);
drhc02a43a2012-01-10 23:18:38 +000064 zFilename = sqlite3_malloc( n+2 );
65 if( zFilename==0 ) return TCL_ERROR;
66 memcpy(zFilename, argv[1], n+1);
67 zFilename[n+1] = 0;
68 rc = sqlite3BtreeOpen(sDb.pVfs, zFilename, &sDb, &pBt, 0,
drh33f4e022007-09-03 15:19:34 +000069 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
drhc02a43a2012-01-10 23:18:38 +000070 sqlite3_free(zFilename);
drh5c4d9702001-08-20 00:33:58 +000071 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +000072 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +000073 return TCL_ERROR;
74 }
drh90f5ecb2004-07-22 01:19:35 +000075 sqlite3BtreeSetCacheSize(pBt, nCache);
drhfe63d1c2004-09-08 20:13:04 +000076 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
drh5c4d9702001-08-20 00:33:58 +000077 Tcl_AppendResult(interp, zBuf, 0);
78 return TCL_OK;
79}
80
81/*
82** Usage: btree_close ID
83**
84** Close the given database.
85*/
mistachkin7617e4a2016-07-28 17:11:20 +000086static int SQLITE_TCLAPI btree_close(
drh5c4d9702001-08-20 00:33:58 +000087 void *NotUsed,
88 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
89 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +000090 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +000091){
92 Btree *pBt;
93 int rc;
94 if( argc!=2 ){
95 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
96 " ID\"", 0);
97 return TCL_ERROR;
98 }
drhe8f52c52008-07-12 14:52:20 +000099 pBt = sqlite3TestTextToPtr(argv[1]);
drh23e11ca2004-05-04 17:27:28 +0000100 rc = sqlite3BtreeClose(pBt);
drh5c4d9702001-08-20 00:33:58 +0000101 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +0000102 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +0000103 return TCL_ERROR;
104 }
drha2451e22007-08-20 23:50:24 +0000105 nRefSqlite3--;
106 if( nRefSqlite3==0 ){
drh27641702007-08-22 02:56:42 +0000107 sqlite3_mutex_leave(sDb.mutex);
drha2451e22007-08-20 23:50:24 +0000108 sqlite3_mutex_free(sDb.mutex);
109 sDb.mutex = 0;
drha2451e22007-08-20 23:50:24 +0000110 sDb.pVfs = 0;
111 }
drh5c4d9702001-08-20 00:33:58 +0000112 return TCL_OK;
113}
114
drh27641702007-08-22 02:56:42 +0000115
drh5c4d9702001-08-20 00:33:58 +0000116/*
117** Usage: btree_begin_transaction ID
118**
119** Start a new transaction
120*/
mistachkin7617e4a2016-07-28 17:11:20 +0000121static int SQLITE_TCLAPI btree_begin_transaction(
drh5c4d9702001-08-20 00:33:58 +0000122 void *NotUsed,
123 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
124 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000125 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000126){
127 Btree *pBt;
128 int rc;
129 if( argc!=2 ){
130 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
131 " ID\"", 0);
132 return TCL_ERROR;
133 }
drhe8f52c52008-07-12 14:52:20 +0000134 pBt = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000135 sqlite3BtreeEnter(pBt);
danielk197740b38dc2004-06-26 08:38:24 +0000136 rc = sqlite3BtreeBeginTrans(pBt, 1);
drhff0587c2007-08-29 17:43:19 +0000137 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000138 if( rc!=SQLITE_OK ){
mistachkine84d8d32013-04-29 03:09:10 +0000139 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +0000140 return TCL_ERROR;
141 }
142 return TCL_OK;
143}
144
145/*
drh5c4d9702001-08-20 00:33:58 +0000146** Usage: btree_pager_stats ID
147**
148** Returns pager statistics
149*/
mistachkin7617e4a2016-07-28 17:11:20 +0000150static int SQLITE_TCLAPI btree_pager_stats(
drh5c4d9702001-08-20 00:33:58 +0000151 void *NotUsed,
152 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
153 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000154 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000155){
156 Btree *pBt;
157 int i;
158 int *a;
159
160 if( argc!=2 ){
161 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
162 " ID\"", 0);
163 return TCL_ERROR;
164 }
drhe8f52c52008-07-12 14:52:20 +0000165 pBt = sqlite3TestTextToPtr(argv[1]);
danielk1977f3c62652007-08-30 08:27:39 +0000166
167 /* Normally in this file, with a b-tree handle opened using the
168 ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
169 ** But this function is sometimes called with a btree handle obtained
170 ** from an open SQLite connection (using [btree_from_db]). In this case
171 ** we need to obtain the mutex for the controlling SQLite handle before
172 ** it is safe to call sqlite3BtreeEnter().
173 */
drhe5fe6902007-12-07 18:55:28 +0000174 sqlite3_mutex_enter(pBt->db->mutex);
danielk1977f3c62652007-08-30 08:27:39 +0000175
drh27641702007-08-22 02:56:42 +0000176 sqlite3BtreeEnter(pBt);
danielk19773b8a05f2007-03-19 17:44:26 +0000177 a = sqlite3PagerStats(sqlite3BtreePager(pBt));
danielk197742741be2005-01-08 12:42:39 +0000178 for(i=0; i<11; i++){
drh5c4d9702001-08-20 00:33:58 +0000179 static char *zName[] = {
180 "ref", "page", "max", "size", "state", "err",
danielk197742741be2005-01-08 12:42:39 +0000181 "hit", "miss", "ovfl", "read", "write"
drh5c4d9702001-08-20 00:33:58 +0000182 };
183 char zBuf[100];
184 Tcl_AppendElement(interp, zName[i]);
drhfe63d1c2004-09-08 20:13:04 +0000185 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
drh5c4d9702001-08-20 00:33:58 +0000186 Tcl_AppendElement(interp, zBuf);
187 }
drh27641702007-08-22 02:56:42 +0000188 sqlite3BtreeLeave(pBt);
danielk1977f3c62652007-08-30 08:27:39 +0000189
190 /* Release the mutex on the SQLite handle that controls this b-tree */
drhe5fe6902007-12-07 18:55:28 +0000191 sqlite3_mutex_leave(pBt->db->mutex);
drh5c4d9702001-08-20 00:33:58 +0000192 return TCL_OK;
193}
194
195/*
drhecdc7532001-09-23 02:35:53 +0000196** Usage: btree_cursor ID TABLENUM WRITEABLE
drh5c4d9702001-08-20 00:33:58 +0000197**
198** Create a new cursor. Return the ID for the cursor.
199*/
mistachkin7617e4a2016-07-28 17:11:20 +0000200static int SQLITE_TCLAPI btree_cursor(
drh5c4d9702001-08-20 00:33:58 +0000201 void *NotUsed,
202 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
203 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000204 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000205){
206 Btree *pBt;
207 int iTable;
208 BtCursor *pCur;
dan93a696f2010-01-07 11:27:30 +0000209 int rc = SQLITE_OK;
drhecdc7532001-09-23 02:35:53 +0000210 int wrFlag;
drh5c4d9702001-08-20 00:33:58 +0000211 char zBuf[30];
212
drhecdc7532001-09-23 02:35:53 +0000213 if( argc!=4 ){
drh5c4d9702001-08-20 00:33:58 +0000214 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drhecdc7532001-09-23 02:35:53 +0000215 " ID TABLENUM WRITEABLE\"", 0);
drh5c4d9702001-08-20 00:33:58 +0000216 return TCL_ERROR;
217 }
drhe8f52c52008-07-12 14:52:20 +0000218 pBt = sqlite3TestTextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000219 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
drhecdc7532001-09-23 02:35:53 +0000220 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
danfd261ec2015-10-22 20:54:33 +0000221 if( wrFlag ) wrFlag = BTREE_WRCSR;
danielk1977cd3e8f72008-03-25 09:47:35 +0000222 pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
223 memset(pCur, 0, sqlite3BtreeCursorSize());
dan6a75c8a2015-10-30 20:54:25 +0000224 sqlite3_mutex_enter(pBt->db->mutex);
drhff0587c2007-08-29 17:43:19 +0000225 sqlite3BtreeEnter(pBt);
dan93a696f2010-01-07 11:27:30 +0000226#ifndef SQLITE_OMIT_SHARED_CACHE
dan6b513642015-10-26 16:31:18 +0000227 rc = sqlite3BtreeLockTable(pBt, iTable, !!wrFlag);
dan93a696f2010-01-07 11:27:30 +0000228#endif
danielk197796d48e92009-06-29 06:00:37 +0000229 if( rc==SQLITE_OK ){
230 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
231 }
drhff0587c2007-08-29 17:43:19 +0000232 sqlite3BtreeLeave(pBt);
dan6a75c8a2015-10-30 20:54:25 +0000233 sqlite3_mutex_leave(pBt->db->mutex);
drh5c4d9702001-08-20 00:33:58 +0000234 if( rc ){
danielk1977cd3e8f72008-03-25 09:47:35 +0000235 ckfree((char *)pCur);
mistachkine84d8d32013-04-29 03:09:10 +0000236 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +0000237 return TCL_ERROR;
238 }
drhfe63d1c2004-09-08 20:13:04 +0000239 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
drh5c4d9702001-08-20 00:33:58 +0000240 Tcl_AppendResult(interp, zBuf, 0);
241 return SQLITE_OK;
242}
243
244/*
245** Usage: btree_close_cursor ID
246**
247** Close a cursor opened using btree_cursor.
248*/
mistachkin7617e4a2016-07-28 17:11:20 +0000249static int SQLITE_TCLAPI btree_close_cursor(
drh5c4d9702001-08-20 00:33:58 +0000250 void *NotUsed,
251 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
252 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000253 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000254){
255 BtCursor *pCur;
drhff0587c2007-08-29 17:43:19 +0000256 Btree *pBt;
drh5c4d9702001-08-20 00:33:58 +0000257 int rc;
258
259 if( argc!=2 ){
260 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
261 " ID\"", 0);
262 return TCL_ERROR;
263 }
drhe8f52c52008-07-12 14:52:20 +0000264 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000265 pBt = pCur->pBtree;
dan6a75c8a2015-10-30 20:54:25 +0000266 sqlite3_mutex_enter(pBt->db->mutex);
drhff0587c2007-08-29 17:43:19 +0000267 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000268 rc = sqlite3BtreeCloseCursor(pCur);
drhff0587c2007-08-29 17:43:19 +0000269 sqlite3BtreeLeave(pBt);
dan6a75c8a2015-10-30 20:54:25 +0000270 sqlite3_mutex_leave(pBt->db->mutex);
danielk1977cd3e8f72008-03-25 09:47:35 +0000271 ckfree((char *)pCur);
drh5c4d9702001-08-20 00:33:58 +0000272 if( rc ){
mistachkine84d8d32013-04-29 03:09:10 +0000273 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +0000274 return TCL_ERROR;
275 }
276 return SQLITE_OK;
277}
278
279/*
drh5c4d9702001-08-20 00:33:58 +0000280** Usage: btree_next ID
281**
drh2dcc9aa2002-12-04 13:40:25 +0000282** Move the cursor to the next entry in the table. Return 0 on success
283** or 1 if the cursor was already on the last entry in the table or if
284** the table is empty.
drh5c4d9702001-08-20 00:33:58 +0000285*/
mistachkin7617e4a2016-07-28 17:11:20 +0000286static int SQLITE_TCLAPI btree_next(
drh5c4d9702001-08-20 00:33:58 +0000287 void *NotUsed,
288 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
289 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000290 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000291){
292 BtCursor *pCur;
293 int rc;
drh0de8c112002-07-06 16:32:14 +0000294 int res = 0;
295 char zBuf[100];
drh5c4d9702001-08-20 00:33:58 +0000296
297 if( argc!=2 ){
298 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
299 " ID\"", 0);
300 return TCL_ERROR;
301 }
drhe8f52c52008-07-12 14:52:20 +0000302 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000303 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000304 rc = sqlite3BtreeNext(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000305 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000306 if( rc ){
mistachkine84d8d32013-04-29 03:09:10 +0000307 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh5c4d9702001-08-20 00:33:58 +0000308 return TCL_ERROR;
309 }
drhfe63d1c2004-09-08 20:13:04 +0000310 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000311 Tcl_AppendResult(interp, zBuf, 0);
312 return SQLITE_OK;
313}
314
315/*
316** Usage: btree_first ID
317**
drh2dcc9aa2002-12-04 13:40:25 +0000318** Move the cursor to the first entry in the table. Return 0 if the
319** cursor was left point to something and 1 if the table is empty.
drh0de8c112002-07-06 16:32:14 +0000320*/
mistachkin7617e4a2016-07-28 17:11:20 +0000321static int SQLITE_TCLAPI btree_first(
drh0de8c112002-07-06 16:32:14 +0000322 void *NotUsed,
323 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
324 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000325 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +0000326){
327 BtCursor *pCur;
328 int rc;
329 int res = 0;
330 char zBuf[100];
331
332 if( argc!=2 ){
333 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
334 " ID\"", 0);
335 return TCL_ERROR;
336 }
drhe8f52c52008-07-12 14:52:20 +0000337 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000338 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000339 rc = sqlite3BtreeFirst(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000340 sqlite3BtreeLeave(pCur->pBtree);
drh0de8c112002-07-06 16:32:14 +0000341 if( rc ){
mistachkine84d8d32013-04-29 03:09:10 +0000342 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
drh0de8c112002-07-06 16:32:14 +0000343 return TCL_ERROR;
344 }
drhfe63d1c2004-09-08 20:13:04 +0000345 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000346 Tcl_AppendResult(interp, zBuf, 0);
drh5c4d9702001-08-20 00:33:58 +0000347 return SQLITE_OK;
348}
349
350/*
drhc39e0002004-05-07 23:50:57 +0000351** Usage: btree_eof ID
352**
353** Return TRUE if the given cursor is not pointing at a valid entry.
354** Return FALSE if the cursor does point to a valid entry.
355*/
mistachkin7617e4a2016-07-28 17:11:20 +0000356static int SQLITE_TCLAPI btree_eof(
drhc39e0002004-05-07 23:50:57 +0000357 void *NotUsed,
358 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
359 int argc, /* Number of arguments */
360 const char **argv /* Text of each argument */
361){
362 BtCursor *pCur;
drhff0587c2007-08-29 17:43:19 +0000363 int rc;
drhc39e0002004-05-07 23:50:57 +0000364 char zBuf[50];
365
366 if( argc!=2 ){
367 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
368 " ID\"", 0);
369 return TCL_ERROR;
370 }
drhe8f52c52008-07-12 14:52:20 +0000371 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000372 sqlite3BtreeEnter(pCur->pBtree);
373 rc = sqlite3BtreeEof(pCur);
374 sqlite3BtreeLeave(pCur->pBtree);
375 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
drhc39e0002004-05-07 23:50:57 +0000376 Tcl_AppendResult(interp, zBuf, 0);
377 return SQLITE_OK;
378}
379
380/*
drh0de8c112002-07-06 16:32:14 +0000381** Usage: btree_payload_size ID
382**
383** Return the number of bytes of payload
384*/
mistachkin7617e4a2016-07-28 17:11:20 +0000385static int SQLITE_TCLAPI btree_payload_size(
drh0de8c112002-07-06 16:32:14 +0000386 void *NotUsed,
387 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
388 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000389 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +0000390){
391 BtCursor *pCur;
drha7c90c42016-06-04 20:37:10 +0000392 u32 n;
drh0de8c112002-07-06 16:32:14 +0000393 char zBuf[50];
394
395 if( argc!=2 ){
396 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
397 " ID\"", 0);
398 return TCL_ERROR;
399 }
drhe8f52c52008-07-12 14:52:20 +0000400 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000401 sqlite3BtreeEnter(pCur->pBtree);
drha7c90c42016-06-04 20:37:10 +0000402 n = sqlite3BtreePayloadSize(pCur);
drhff0587c2007-08-29 17:43:19 +0000403 sqlite3BtreeLeave(pCur->pBtree);
drha7c90c42016-06-04 20:37:10 +0000404 sqlite3_snprintf(sizeof(zBuf),zBuf, "%u", n);
drh0de8c112002-07-06 16:32:14 +0000405 Tcl_AppendResult(interp, zBuf, 0);
drh0de8c112002-07-06 16:32:14 +0000406 return SQLITE_OK;
407}
408
409/*
drh6d2fb152004-05-14 16:50:06 +0000410** usage: varint_test START MULTIPLIER COUNT INCREMENT
411**
shane3f8d5cf2008-04-24 19:15:09 +0000412** This command tests the putVarint() and getVarint()
drh6d2fb152004-05-14 16:50:06 +0000413** routines, both for accuracy and for speed.
414**
shane3f8d5cf2008-04-24 19:15:09 +0000415** An integer is written using putVarint() and read back with
416** getVarint() and varified to be unchanged. This repeats COUNT
drh6d2fb152004-05-14 16:50:06 +0000417** times. The first integer is START*MULTIPLIER. Each iteration
418** increases the integer by INCREMENT.
419**
420** This command returns nothing if it works. It returns an error message
421** if something goes wrong.
422*/
mistachkin7617e4a2016-07-28 17:11:20 +0000423static int SQLITE_TCLAPI btree_varint_test(
drh6d2fb152004-05-14 16:50:06 +0000424 void *NotUsed,
425 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
426 int argc, /* Number of arguments */
427 const char **argv /* Text of each argument */
428){
429 u32 start, mult, count, incr;
430 u64 in, out;
drhd8820e82004-05-18 15:57:42 +0000431 int n1, n2, i, j;
drh6d2fb152004-05-14 16:50:06 +0000432 unsigned char zBuf[100];
433 if( argc!=5 ){
434 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
435 " START MULTIPLIER COUNT INCREMENT\"", 0);
436 return TCL_ERROR;
437 }
438 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
439 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
440 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
441 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
442 in = start;
443 in *= mult;
drh7da5fcb2012-03-30 14:59:43 +0000444 for(i=0; i<(int)count; i++){
drhd8820e82004-05-18 15:57:42 +0000445 char zErr[200];
shane3f8d5cf2008-04-24 19:15:09 +0000446 n1 = putVarint(zBuf, in);
drh6d2fb152004-05-14 16:50:06 +0000447 if( n1>9 || n1<1 ){
drh65545b52015-01-19 00:35:53 +0000448 sqlite3_snprintf(sizeof(zErr), zErr,
449 "putVarint returned %d - should be between 1 and 9", n1);
drhd8820e82004-05-18 15:57:42 +0000450 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000451 return TCL_ERROR;
452 }
shane3f8d5cf2008-04-24 19:15:09 +0000453 n2 = getVarint(zBuf, &out);
drh6d2fb152004-05-14 16:50:06 +0000454 if( n1!=n2 ){
drh65545b52015-01-19 00:35:53 +0000455 sqlite3_snprintf(sizeof(zErr), zErr,
456 "putVarint returned %d and getVarint returned %d", n1, n2);
drhd8820e82004-05-18 15:57:42 +0000457 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000458 return TCL_ERROR;
459 }
460 if( in!=out ){
drh65545b52015-01-19 00:35:53 +0000461 sqlite3_snprintf(sizeof(zErr), zErr,
462 "Wrote 0x%016llx and got back 0x%016llx", in, out);
drhd8820e82004-05-18 15:57:42 +0000463 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +0000464 return TCL_ERROR;
465 }
drh9d213ef2004-06-30 04:02:11 +0000466 if( (in & 0xffffffff)==in ){
467 u32 out32;
shane3f8d5cf2008-04-24 19:15:09 +0000468 n2 = getVarint32(zBuf, out32);
drh9d213ef2004-06-30 04:02:11 +0000469 out = out32;
470 if( n1!=n2 ){
drh65545b52015-01-19 00:35:53 +0000471 sqlite3_snprintf(sizeof(zErr), zErr,
472 "putVarint returned %d and GetVarint32 returned %d",
drh9d213ef2004-06-30 04:02:11 +0000473 n1, n2);
474 Tcl_AppendResult(interp, zErr, 0);
475 return TCL_ERROR;
476 }
477 if( in!=out ){
drh65545b52015-01-19 00:35:53 +0000478 sqlite3_snprintf(sizeof(zErr), zErr,
479 "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
drh9d213ef2004-06-30 04:02:11 +0000480 in, out);
481 Tcl_AppendResult(interp, zErr, 0);
482 return TCL_ERROR;
483 }
484 }
drhd8820e82004-05-18 15:57:42 +0000485
486 /* In order to get realistic timings, run getVarint 19 more times.
487 ** This is because getVarint is called about 20 times more often
488 ** than putVarint.
489 */
490 for(j=0; j<19; j++){
shane3f8d5cf2008-04-24 19:15:09 +0000491 getVarint(zBuf, &out);
drhd8820e82004-05-18 15:57:42 +0000492 }
drh6d2fb152004-05-14 16:50:06 +0000493 in += incr;
494 }
495 return TCL_OK;
496}
drh9b171272004-05-08 02:03:22 +0000497
498/*
danielk197742741be2005-01-08 12:42:39 +0000499** usage: btree_from_db DB-HANDLE
500**
501** This command returns the btree handle for the main database associated
502** with the database-handle passed as the argument. Example usage:
503**
504** sqlite3 db test.db
505** set bt [btree_from_db db]
506*/
mistachkin7617e4a2016-07-28 17:11:20 +0000507static int SQLITE_TCLAPI btree_from_db(
danielk197742741be2005-01-08 12:42:39 +0000508 void *NotUsed,
509 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
510 int argc, /* Number of arguments */
511 const char **argv /* Text of each argument */
512){
513 char zBuf[100];
514 Tcl_CmdInfo info;
515 sqlite3 *db;
516 Btree *pBt;
danielk197763c64f32007-05-17 14:45:12 +0000517 int iDb = 0;
danielk197742741be2005-01-08 12:42:39 +0000518
danielk197763c64f32007-05-17 14:45:12 +0000519 if( argc!=2 && argc!=3 ){
danielk197742741be2005-01-08 12:42:39 +0000520 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
danielk197763c64f32007-05-17 14:45:12 +0000521 " DB-HANDLE ?N?\"", 0);
danielk197742741be2005-01-08 12:42:39 +0000522 return TCL_ERROR;
523 }
524
525 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
526 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
527 return TCL_ERROR;
528 }
danielk197763c64f32007-05-17 14:45:12 +0000529 if( argc==3 ){
530 iDb = atoi(argv[2]);
531 }
532
danielk197742741be2005-01-08 12:42:39 +0000533 db = *((sqlite3 **)info.objClientData);
534 assert( db );
535
danielk197763c64f32007-05-17 14:45:12 +0000536 pBt = db->aDb[iDb].pBt;
danielk197742741be2005-01-08 12:42:39 +0000537 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
538 Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
539 return TCL_OK;
540}
541
danielk197717b90b52008-06-06 11:11:25 +0000542/*
543** Usage: btree_ismemdb ID
544**
dan9131ab92016-04-06 18:20:51 +0000545** Return true if the B-Tree is currently stored entirely in memory.
danielk197717b90b52008-06-06 11:11:25 +0000546*/
mistachkin7617e4a2016-07-28 17:11:20 +0000547static int SQLITE_TCLAPI btree_ismemdb(
danielk197717b90b52008-06-06 11:11:25 +0000548 void *NotUsed,
549 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
550 int argc, /* Number of arguments */
551 const char **argv /* Text of each argument */
552){
553 Btree *pBt;
554 int res;
dan9131ab92016-04-06 18:20:51 +0000555 sqlite3_file *pFile;
danielk197717b90b52008-06-06 11:11:25 +0000556
557 if( argc!=2 ){
558 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
559 " ID\"", 0);
560 return TCL_ERROR;
561 }
drhe8f52c52008-07-12 14:52:20 +0000562 pBt = sqlite3TestTextToPtr(argv[1]);
danielk197717b90b52008-06-06 11:11:25 +0000563 sqlite3_mutex_enter(pBt->db->mutex);
564 sqlite3BtreeEnter(pBt);
dan9131ab92016-04-06 18:20:51 +0000565 pFile = sqlite3PagerFile(sqlite3BtreePager(pBt));
566 res = (pFile->pMethods==0);
danielk197717b90b52008-06-06 11:11:25 +0000567 sqlite3BtreeLeave(pBt);
568 sqlite3_mutex_leave(pBt->db->mutex);
569 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
570 return SQLITE_OK;
571}
572
danielk197730548662009-07-09 05:07:37 +0000573/*
574** usage: btree_set_cache_size ID NCACHE
575**
576** Set the size of the cache used by btree $ID.
577*/
mistachkin7617e4a2016-07-28 17:11:20 +0000578static int SQLITE_TCLAPI btree_set_cache_size(
danielk197730548662009-07-09 05:07:37 +0000579 void *NotUsed,
580 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
581 int argc, /* Number of arguments */
582 const char **argv /* Text of each argument */
583){
584 int nCache;
585 Btree *pBt;
586
587 if( argc!=3 ){
588 Tcl_AppendResult(
589 interp, "wrong # args: should be \"", argv[0], " BT NCACHE\"", 0);
590 return TCL_ERROR;
591 }
592 pBt = sqlite3TestTextToPtr(argv[1]);
593 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
594
595 sqlite3_mutex_enter(pBt->db->mutex);
596 sqlite3BtreeEnter(pBt);
597 sqlite3BtreeSetCacheSize(pBt, nCache);
598 sqlite3BtreeLeave(pBt);
599 sqlite3_mutex_leave(pBt->db->mutex);
600 return TCL_OK;
601}
602
dan6b513642015-10-26 16:31:18 +0000603/*
604** usage: btree_insert CSR ?KEY? VALUE
605**
606** Set the size of the cache used by btree $ID.
607*/
mistachkin7617e4a2016-07-28 17:11:20 +0000608static int SQLITE_TCLAPI btree_insert(
dan6b513642015-10-26 16:31:18 +0000609 ClientData clientData,
610 Tcl_Interp *interp,
611 int objc,
612 Tcl_Obj *const objv[]
613){
614 BtCursor *pCur;
615 int rc;
drh8eeb4462016-05-21 20:03:42 +0000616 BtreePayload x;
dan6b513642015-10-26 16:31:18 +0000617
618 if( objc!=4 && objc!=3 ){
619 Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE");
620 return TCL_ERROR;
621 }
622
drh8eeb4462016-05-21 20:03:42 +0000623 memset(&x, 0, sizeof(x));
dan6b513642015-10-26 16:31:18 +0000624 if( objc==4 ){
drh8eeb4462016-05-21 20:03:42 +0000625 if( Tcl_GetIntFromObj(interp, objv[2], &rc) ) return TCL_ERROR;
626 x.nKey = rc;
627 x.pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &x.nData);
dan6b513642015-10-26 16:31:18 +0000628 }else{
drh8eeb4462016-05-21 20:03:42 +0000629 x.pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &rc);
630 x.nKey = rc;
dan6b513642015-10-26 16:31:18 +0000631 }
632 pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
633
dan6a75c8a2015-10-30 20:54:25 +0000634 sqlite3_mutex_enter(pCur->pBtree->db->mutex);
dan6b513642015-10-26 16:31:18 +0000635 sqlite3BtreeEnter(pCur->pBtree);
drh8eeb4462016-05-21 20:03:42 +0000636 rc = sqlite3BtreeInsert(pCur, &x, 0, 0);
dan6b513642015-10-26 16:31:18 +0000637 sqlite3BtreeLeave(pCur->pBtree);
dan6a75c8a2015-10-30 20:54:25 +0000638 sqlite3_mutex_leave(pCur->pBtree->db->mutex);
dan6b513642015-10-26 16:31:18 +0000639
640 Tcl_ResetResult(interp);
641 if( rc ){
642 Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
643 return TCL_ERROR;
644 }
645 return TCL_OK;
646}
danielk197730548662009-07-09 05:07:37 +0000647
danielk19771ad7f642005-01-20 05:24:32 +0000648
danielk197742741be2005-01-08 12:42:39 +0000649/*
drh5c4d9702001-08-20 00:33:58 +0000650** Register commands with the TCL interpreter.
651*/
652int Sqlitetest3_Init(Tcl_Interp *interp){
drhc2eef3b2002-08-31 18:53:06 +0000653 static struct {
654 char *zName;
655 Tcl_CmdProc *xProc;
656 } aCmd[] = {
657 { "btree_open", (Tcl_CmdProc*)btree_open },
658 { "btree_close", (Tcl_CmdProc*)btree_close },
659 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction },
drhc2eef3b2002-08-31 18:53:06 +0000660 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats },
drhc2eef3b2002-08-31 18:53:06 +0000661 { "btree_cursor", (Tcl_CmdProc*)btree_cursor },
662 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor },
drhc2eef3b2002-08-31 18:53:06 +0000663 { "btree_next", (Tcl_CmdProc*)btree_next },
drhc39e0002004-05-07 23:50:57 +0000664 { "btree_eof", (Tcl_CmdProc*)btree_eof },
drhc2eef3b2002-08-31 18:53:06 +0000665 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
666 { "btree_first", (Tcl_CmdProc*)btree_first },
drh6d2fb152004-05-14 16:50:06 +0000667 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test },
danielk197742741be2005-01-08 12:42:39 +0000668 { "btree_from_db", (Tcl_CmdProc*)btree_from_db },
danielk197730548662009-07-09 05:07:37 +0000669 { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb },
670 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }
drhc2eef3b2002-08-31 18:53:06 +0000671 };
672 int i;
673
674 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
675 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
676 }
danielk1977312d6b32004-06-29 13:18:23 +0000677
dan6b513642015-10-26 16:31:18 +0000678 Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0);
679
drh5c4d9702001-08-20 00:33:58 +0000680 return TCL_OK;
681}