blob: 0d915f3cb56ed5f340d2fd94f8d8300bb4f64d99 [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.
15**
danielk1977c7af4842008-10-27 13:59:33 +000016** $Id: test3.c,v 1.102 2008/10/27 13:59:34 danielk1977 Exp $
drh5c4d9702001-08-20 00:33:58 +000017*/
18#include "sqliteInt.h"
danielk1977a1644fd2007-08-29 12:31:25 +000019#include "btreeInt.h"
drh5c4d9702001-08-20 00:33:58 +000020#include "tcl.h"
21#include <stdlib.h>
22#include <string.h>
23
24/*
25** Interpret an SQLite error number
26*/
27static char *errorName(int rc){
28 char *zName;
29 switch( rc ){
30 case SQLITE_OK: zName = "SQLITE_OK"; break;
31 case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
drh5c4d9702001-08-20 00:33:58 +000032 case SQLITE_PERM: zName = "SQLITE_PERM"; break;
33 case SQLITE_ABORT: zName = "SQLITE_ABORT"; break;
34 case SQLITE_BUSY: zName = "SQLITE_BUSY"; break;
35 case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break;
36 case SQLITE_READONLY: zName = "SQLITE_READONLY"; break;
37 case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break;
38 case SQLITE_IOERR: zName = "SQLITE_IOERR"; break;
39 case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break;
drh5c4d9702001-08-20 00:33:58 +000040 case SQLITE_FULL: zName = "SQLITE_FULL"; break;
41 case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break;
42 case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break;
drh24cd67e2004-05-10 16:18:47 +000043 case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break;
danielk1977e6efa742004-11-10 11:55:10 +000044 case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break;
drh5c4d9702001-08-20 00:33:58 +000045 default: zName = "SQLITE_Unknown"; break;
46 }
47 return zName;
48}
49
50/*
drha2451e22007-08-20 23:50:24 +000051** A bogus sqlite3 connection structure for use in the btree
52** tests.
53*/
54static sqlite3 sDb;
55static int nRefSqlite3 = 0;
56
57/*
drh23e11ca2004-05-04 17:27:28 +000058** Usage: btree_open FILENAME NCACHE FLAGS
drh5c4d9702001-08-20 00:33:58 +000059**
60** Open a new database
61*/
62static int btree_open(
63 void *NotUsed,
64 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
65 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +000066 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +000067){
68 Btree *pBt;
drh23e11ca2004-05-04 17:27:28 +000069 int rc, nCache, flags;
drh5c4d9702001-08-20 00:33:58 +000070 char zBuf[100];
drh23e11ca2004-05-04 17:27:28 +000071 if( argc!=4 ){
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;
77 if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR;
drha2451e22007-08-20 23:50:24 +000078 nRefSqlite3++;
79 if( nRefSqlite3==1 ){
80 sDb.pVfs = sqlite3_vfs_find(0);
danielk197759f8c082008-06-18 17:09:10 +000081 sDb.mutex = sqlite3MutexAlloc(SQLITE_MUTEX_RECURSIVE);
drh27641702007-08-22 02:56:42 +000082 sqlite3_mutex_enter(sDb.mutex);
drha2451e22007-08-20 23:50:24 +000083 }
drh33f4e022007-09-03 15:19:34 +000084 rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, flags,
85 SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB);
drh5c4d9702001-08-20 00:33:58 +000086 if( rc!=SQLITE_OK ){
87 Tcl_AppendResult(interp, errorName(rc), 0);
88 return TCL_ERROR;
89 }
drh90f5ecb2004-07-22 01:19:35 +000090 sqlite3BtreeSetCacheSize(pBt, nCache);
drhfe63d1c2004-09-08 20:13:04 +000091 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt);
drh5c4d9702001-08-20 00:33:58 +000092 Tcl_AppendResult(interp, zBuf, 0);
93 return TCL_OK;
94}
95
96/*
97** Usage: btree_close ID
98**
99** Close the given database.
100*/
101static int btree_close(
102 void *NotUsed,
103 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
104 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000105 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000106){
107 Btree *pBt;
108 int rc;
109 if( argc!=2 ){
110 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
111 " ID\"", 0);
112 return TCL_ERROR;
113 }
drhe8f52c52008-07-12 14:52:20 +0000114 pBt = sqlite3TestTextToPtr(argv[1]);
drh23e11ca2004-05-04 17:27:28 +0000115 rc = sqlite3BtreeClose(pBt);
drh5c4d9702001-08-20 00:33:58 +0000116 if( rc!=SQLITE_OK ){
117 Tcl_AppendResult(interp, errorName(rc), 0);
118 return TCL_ERROR;
119 }
drha2451e22007-08-20 23:50:24 +0000120 nRefSqlite3--;
121 if( nRefSqlite3==0 ){
drh27641702007-08-22 02:56:42 +0000122 sqlite3_mutex_leave(sDb.mutex);
drha2451e22007-08-20 23:50:24 +0000123 sqlite3_mutex_free(sDb.mutex);
124 sDb.mutex = 0;
drha2451e22007-08-20 23:50:24 +0000125 sDb.pVfs = 0;
126 }
drh5c4d9702001-08-20 00:33:58 +0000127 return TCL_OK;
128}
129
drh27641702007-08-22 02:56:42 +0000130
drh5c4d9702001-08-20 00:33:58 +0000131/*
132** Usage: btree_begin_transaction ID
133**
134** Start a new transaction
135*/
136static int btree_begin_transaction(
137 void *NotUsed,
138 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
139 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000140 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000141){
142 Btree *pBt;
143 int rc;
144 if( argc!=2 ){
145 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
146 " ID\"", 0);
147 return TCL_ERROR;
148 }
drhe8f52c52008-07-12 14:52:20 +0000149 pBt = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000150 sqlite3BtreeEnter(pBt);
danielk197740b38dc2004-06-26 08:38:24 +0000151 rc = sqlite3BtreeBeginTrans(pBt, 1);
drhff0587c2007-08-29 17:43:19 +0000152 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000153 if( rc!=SQLITE_OK ){
154 Tcl_AppendResult(interp, errorName(rc), 0);
155 return TCL_ERROR;
156 }
157 return TCL_OK;
158}
159
160/*
161** Usage: btree_rollback ID
162**
163** Rollback changes
164*/
165static int btree_rollback(
166 void *NotUsed,
167 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
168 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000169 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000170){
171 Btree *pBt;
172 int rc;
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]);
drhff0587c2007-08-29 17:43:19 +0000179 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000180 rc = sqlite3BtreeRollback(pBt);
drhff0587c2007-08-29 17:43:19 +0000181 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000182 if( rc!=SQLITE_OK ){
183 Tcl_AppendResult(interp, errorName(rc), 0);
184 return TCL_ERROR;
185 }
186 return TCL_OK;
187}
188
189/*
190** Usage: btree_commit ID
191**
192** Commit all changes
193*/
194static int btree_commit(
195 void *NotUsed,
196 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
197 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000198 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000199){
200 Btree *pBt;
201 int rc;
202 if( argc!=2 ){
203 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
204 " ID\"", 0);
205 return TCL_ERROR;
206 }
drhe8f52c52008-07-12 14:52:20 +0000207 pBt = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000208 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000209 rc = sqlite3BtreeCommit(pBt);
drhff0587c2007-08-29 17:43:19 +0000210 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000211 if( rc!=SQLITE_OK ){
212 Tcl_AppendResult(interp, errorName(rc), 0);
213 return TCL_ERROR;
214 }
215 return TCL_OK;
216}
217
218/*
danielk19771d850a72004-05-31 08:26:49 +0000219** Usage: btree_begin_statement ID
220**
221** Start a new statement transaction
222*/
223static int btree_begin_statement(
224 void *NotUsed,
225 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
226 int argc, /* Number of arguments */
227 const char **argv /* Text of each argument */
228){
229 Btree *pBt;
230 int rc;
231 if( argc!=2 ){
232 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
233 " ID\"", 0);
234 return TCL_ERROR;
235 }
drhe8f52c52008-07-12 14:52:20 +0000236 pBt = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000237 sqlite3BtreeEnter(pBt);
danielk19771d850a72004-05-31 08:26:49 +0000238 rc = sqlite3BtreeBeginStmt(pBt);
drhff0587c2007-08-29 17:43:19 +0000239 sqlite3BtreeLeave(pBt);
danielk19771d850a72004-05-31 08:26:49 +0000240 if( rc!=SQLITE_OK ){
241 Tcl_AppendResult(interp, errorName(rc), 0);
242 return TCL_ERROR;
243 }
244 return TCL_OK;
245}
246
247/*
248** Usage: btree_rollback_statement ID
249**
250** Rollback changes
251*/
252static int btree_rollback_statement(
253 void *NotUsed,
254 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
255 int argc, /* Number of arguments */
256 const char **argv /* Text of each argument */
257){
258 Btree *pBt;
259 int rc;
260 if( argc!=2 ){
261 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
262 " ID\"", 0);
263 return TCL_ERROR;
264 }
drhe8f52c52008-07-12 14:52:20 +0000265 pBt = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000266 sqlite3BtreeEnter(pBt);
danielk19771d850a72004-05-31 08:26:49 +0000267 rc = sqlite3BtreeRollbackStmt(pBt);
drhff0587c2007-08-29 17:43:19 +0000268 sqlite3BtreeLeave(pBt);
danielk19771d850a72004-05-31 08:26:49 +0000269 if( rc!=SQLITE_OK ){
270 Tcl_AppendResult(interp, errorName(rc), 0);
271 return TCL_ERROR;
272 }
273 return TCL_OK;
274}
275
276/*
277** Usage: btree_commit_statement ID
278**
279** Commit all changes
280*/
281static int btree_commit_statement(
282 void *NotUsed,
283 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
284 int argc, /* Number of arguments */
285 const char **argv /* Text of each argument */
286){
287 Btree *pBt;
288 int rc;
289 if( argc!=2 ){
290 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
291 " ID\"", 0);
292 return TCL_ERROR;
293 }
drhe8f52c52008-07-12 14:52:20 +0000294 pBt = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000295 sqlite3BtreeEnter(pBt);
danielk19771d850a72004-05-31 08:26:49 +0000296 rc = sqlite3BtreeCommitStmt(pBt);
drhff0587c2007-08-29 17:43:19 +0000297 sqlite3BtreeLeave(pBt);
danielk19771d850a72004-05-31 08:26:49 +0000298 if( rc!=SQLITE_OK ){
299 Tcl_AppendResult(interp, errorName(rc), 0);
300 return TCL_ERROR;
301 }
302 return TCL_OK;
303}
304
305/*
drh23e11ca2004-05-04 17:27:28 +0000306** Usage: btree_create_table ID FLAGS
drh5c4d9702001-08-20 00:33:58 +0000307**
308** Create a new table in the database
309*/
310static int btree_create_table(
311 void *NotUsed,
312 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
313 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000314 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000315){
316 Btree *pBt;
drh23e11ca2004-05-04 17:27:28 +0000317 int rc, iTable, flags;
drh5c4d9702001-08-20 00:33:58 +0000318 char zBuf[30];
drh23e11ca2004-05-04 17:27:28 +0000319 if( argc!=3 ){
drh5c4d9702001-08-20 00:33:58 +0000320 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drh23e11ca2004-05-04 17:27:28 +0000321 " ID FLAGS\"", 0);
drh5c4d9702001-08-20 00:33:58 +0000322 return TCL_ERROR;
323 }
drhe8f52c52008-07-12 14:52:20 +0000324 pBt = sqlite3TestTextToPtr(argv[1]);
drh23e11ca2004-05-04 17:27:28 +0000325 if( Tcl_GetInt(interp, argv[2], &flags) ) return TCL_ERROR;
drhff0587c2007-08-29 17:43:19 +0000326 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000327 rc = sqlite3BtreeCreateTable(pBt, &iTable, flags);
drhff0587c2007-08-29 17:43:19 +0000328 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000329 if( rc!=SQLITE_OK ){
330 Tcl_AppendResult(interp, errorName(rc), 0);
331 return TCL_ERROR;
332 }
drhfe63d1c2004-09-08 20:13:04 +0000333 sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iTable);
drh5c4d9702001-08-20 00:33:58 +0000334 Tcl_AppendResult(interp, zBuf, 0);
335 return TCL_OK;
336}
337
338/*
339** Usage: btree_drop_table ID TABLENUM
340**
341** Delete an entire table from the database
342*/
343static int btree_drop_table(
344 void *NotUsed,
345 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
346 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000347 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000348){
349 Btree *pBt;
350 int iTable;
351 int rc;
drh205f48e2004-11-05 00:43:11 +0000352 int notUsed1;
drh5c4d9702001-08-20 00:33:58 +0000353 if( argc!=3 ){
354 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
355 " ID TABLENUM\"", 0);
356 return TCL_ERROR;
357 }
drhe8f52c52008-07-12 14:52:20 +0000358 pBt = sqlite3TestTextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000359 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
drhff0587c2007-08-29 17:43:19 +0000360 sqlite3BtreeEnter(pBt);
drh205f48e2004-11-05 00:43:11 +0000361 rc = sqlite3BtreeDropTable(pBt, iTable, &notUsed1);
drhff0587c2007-08-29 17:43:19 +0000362 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000363 if( rc!=SQLITE_OK ){
364 Tcl_AppendResult(interp, errorName(rc), 0);
365 return TCL_ERROR;
366 }
367 return TCL_OK;
368}
369
370/*
371** Usage: btree_clear_table ID TABLENUM
372**
373** Remove all entries from the given table but keep the table around.
374*/
375static int btree_clear_table(
376 void *NotUsed,
377 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
378 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000379 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000380){
381 Btree *pBt;
382 int iTable;
383 int rc;
384 if( argc!=3 ){
385 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
386 " ID TABLENUM\"", 0);
387 return TCL_ERROR;
388 }
drhe8f52c52008-07-12 14:52:20 +0000389 pBt = sqlite3TestTextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000390 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
drhff0587c2007-08-29 17:43:19 +0000391 sqlite3BtreeEnter(pBt);
danielk1977c7af4842008-10-27 13:59:33 +0000392 rc = sqlite3BtreeClearTable(pBt, iTable, 0);
drhff0587c2007-08-29 17:43:19 +0000393 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000394 if( rc!=SQLITE_OK ){
395 Tcl_AppendResult(interp, errorName(rc), 0);
396 return TCL_ERROR;
397 }
398 return TCL_OK;
399}
400
401/*
402** Usage: btree_get_meta ID
403**
404** Return meta data
405*/
406static int btree_get_meta(
407 void *NotUsed,
408 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
409 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000410 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000411){
412 Btree *pBt;
413 int rc;
414 int i;
drh5c4d9702001-08-20 00:33:58 +0000415 if( argc!=2 ){
416 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
417 " ID\"", 0);
418 return TCL_ERROR;
419 }
drhe8f52c52008-07-12 14:52:20 +0000420 pBt = sqlite3TestTextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000421 for(i=0; i<SQLITE_N_BTREE_META; i++){
422 char zBuf[30];
shane1ca0ed42008-05-27 20:17:00 +0000423 u32 v;
drhff0587c2007-08-29 17:43:19 +0000424 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000425 rc = sqlite3BtreeGetMeta(pBt, i, &v);
drhff0587c2007-08-29 17:43:19 +0000426 sqlite3BtreeLeave(pBt);
drh23e11ca2004-05-04 17:27:28 +0000427 if( rc!=SQLITE_OK ){
428 Tcl_AppendResult(interp, errorName(rc), 0);
429 return TCL_ERROR;
430 }
drhfe63d1c2004-09-08 20:13:04 +0000431 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",v);
drh5c4d9702001-08-20 00:33:58 +0000432 Tcl_AppendElement(interp, zBuf);
433 }
434 return TCL_OK;
435}
436
437/*
438** Usage: btree_update_meta ID METADATA...
439**
440** Return meta data
441*/
442static int btree_update_meta(
443 void *NotUsed,
444 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
445 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000446 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000447){
448 Btree *pBt;
449 int rc;
450 int i;
drhde647132004-05-07 17:57:49 +0000451 int aMeta[SQLITE_N_BTREE_META];
drh5c4d9702001-08-20 00:33:58 +0000452
danielk1977d09b5922004-06-17 00:01:21 +0000453 if( argc!=2+SQLITE_N_BTREE_META ){
drh5c4d9702001-08-20 00:33:58 +0000454 char zBuf[30];
drhfe63d1c2004-09-08 20:13:04 +0000455 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",SQLITE_N_BTREE_META);
drh5c4d9702001-08-20 00:33:58 +0000456 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
457 " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0);
458 return TCL_ERROR;
459 }
drhe8f52c52008-07-12 14:52:20 +0000460 pBt = sqlite3TestTextToPtr(argv[1]);
drhde647132004-05-07 17:57:49 +0000461 for(i=1; i<SQLITE_N_BTREE_META; i++){
danielk197793cd0392004-06-30 02:35:51 +0000462 if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR;
drh5c4d9702001-08-20 00:33:58 +0000463 }
drhde647132004-05-07 17:57:49 +0000464 for(i=1; i<SQLITE_N_BTREE_META; i++){
drhff0587c2007-08-29 17:43:19 +0000465 sqlite3BtreeEnter(pBt);
drhde647132004-05-07 17:57:49 +0000466 rc = sqlite3BtreeUpdateMeta(pBt, i, aMeta[i]);
drhff0587c2007-08-29 17:43:19 +0000467 sqlite3BtreeLeave(pBt);
drh23e11ca2004-05-04 17:27:28 +0000468 if( rc!=SQLITE_OK ){
469 Tcl_AppendResult(interp, errorName(rc), 0);
470 return TCL_ERROR;
471 }
drh5c4d9702001-08-20 00:33:58 +0000472 }
473 return TCL_OK;
474}
475
476/*
drh5c4d9702001-08-20 00:33:58 +0000477** Usage: btree_pager_stats ID
478**
479** Returns pager statistics
480*/
481static int btree_pager_stats(
482 void *NotUsed,
483 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
484 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000485 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000486){
487 Btree *pBt;
488 int i;
489 int *a;
490
491 if( argc!=2 ){
492 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
493 " ID\"", 0);
494 return TCL_ERROR;
495 }
drhe8f52c52008-07-12 14:52:20 +0000496 pBt = sqlite3TestTextToPtr(argv[1]);
danielk1977f3c62652007-08-30 08:27:39 +0000497
498 /* Normally in this file, with a b-tree handle opened using the
499 ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
500 ** But this function is sometimes called with a btree handle obtained
501 ** from an open SQLite connection (using [btree_from_db]). In this case
502 ** we need to obtain the mutex for the controlling SQLite handle before
503 ** it is safe to call sqlite3BtreeEnter().
504 */
drhe5fe6902007-12-07 18:55:28 +0000505 sqlite3_mutex_enter(pBt->db->mutex);
danielk1977f3c62652007-08-30 08:27:39 +0000506
drh27641702007-08-22 02:56:42 +0000507 sqlite3BtreeEnter(pBt);
danielk19773b8a05f2007-03-19 17:44:26 +0000508 a = sqlite3PagerStats(sqlite3BtreePager(pBt));
danielk197742741be2005-01-08 12:42:39 +0000509 for(i=0; i<11; i++){
drh5c4d9702001-08-20 00:33:58 +0000510 static char *zName[] = {
511 "ref", "page", "max", "size", "state", "err",
danielk197742741be2005-01-08 12:42:39 +0000512 "hit", "miss", "ovfl", "read", "write"
drh5c4d9702001-08-20 00:33:58 +0000513 };
514 char zBuf[100];
515 Tcl_AppendElement(interp, zName[i]);
drhfe63d1c2004-09-08 20:13:04 +0000516 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
drh5c4d9702001-08-20 00:33:58 +0000517 Tcl_AppendElement(interp, zBuf);
518 }
drh27641702007-08-22 02:56:42 +0000519 sqlite3BtreeLeave(pBt);
danielk1977f3c62652007-08-30 08:27:39 +0000520
521 /* Release the mutex on the SQLite handle that controls this b-tree */
drhe5fe6902007-12-07 18:55:28 +0000522 sqlite3_mutex_leave(pBt->db->mutex);
drh5c4d9702001-08-20 00:33:58 +0000523 return TCL_OK;
524}
525
526/*
drhaaab5722002-02-19 13:39:21 +0000527** Usage: btree_integrity_check ID ROOT ...
drh5c4d9702001-08-20 00:33:58 +0000528**
529** Look through every page of the given BTree file to verify correct
530** formatting and linkage. Return a line of text for each problem found.
531** Return an empty string if everything worked.
532*/
drhaaab5722002-02-19 13:39:21 +0000533static int btree_integrity_check(
drh5c4d9702001-08-20 00:33:58 +0000534 void *NotUsed,
535 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
536 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000537 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000538){
539 Btree *pBt;
drh5c4d9702001-08-20 00:33:58 +0000540 int nRoot;
541 int *aRoot;
542 int i;
drh1dcdbc02007-01-27 02:24:54 +0000543 int nErr;
drh40e016e2004-11-04 14:47:11 +0000544 char *zResult;
drh5c4d9702001-08-20 00:33:58 +0000545
546 if( argc<3 ){
547 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
548 " ID ROOT ...\"", 0);
549 return TCL_ERROR;
550 }
drhe8f52c52008-07-12 14:52:20 +0000551 pBt = sqlite3TestTextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000552 nRoot = argc-2;
drh17435752007-08-16 04:30:38 +0000553 aRoot = (int*)sqlite3_malloc( sizeof(int)*(argc-2) );
drh5c4d9702001-08-20 00:33:58 +0000554 for(i=0; i<argc-2; i++){
555 if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
556 }
drhb7f91642004-10-31 02:22:47 +0000557#ifndef SQLITE_OMIT_INTEGRITY_CHECK
drhff0587c2007-08-29 17:43:19 +0000558 sqlite3BtreeEnter(pBt);
drh1dcdbc02007-01-27 02:24:54 +0000559 zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
drhff0587c2007-08-29 17:43:19 +0000560 sqlite3BtreeLeave(pBt);
drhb7f91642004-10-31 02:22:47 +0000561#else
drh40e016e2004-11-04 14:47:11 +0000562 zResult = 0;
drhb7f91642004-10-31 02:22:47 +0000563#endif
drh17435752007-08-16 04:30:38 +0000564 sqlite3_free((void*)aRoot);
drh5c4d9702001-08-20 00:33:58 +0000565 if( zResult ){
566 Tcl_AppendResult(interp, zResult, 0);
danielk19771e536952007-08-16 10:09:01 +0000567 sqlite3_free(zResult);
drh5c4d9702001-08-20 00:33:58 +0000568 }
569 return TCL_OK;
570}
571
572/*
drhc8629a12004-05-08 20:07:40 +0000573** Usage: btree_cursor_list ID
574**
575** Print information about all cursors to standard output for debugging.
576*/
577static int btree_cursor_list(
578 void *NotUsed,
579 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
580 int argc, /* Number of arguments */
581 const char **argv /* Text of each argument */
582){
583 Btree *pBt;
584
585 if( argc!=2 ){
586 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
587 " ID\"", 0);
588 return TCL_ERROR;
589 }
drhe8f52c52008-07-12 14:52:20 +0000590 pBt = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000591 sqlite3BtreeEnter(pBt);
drhc8629a12004-05-08 20:07:40 +0000592 sqlite3BtreeCursorList(pBt);
drhff0587c2007-08-29 17:43:19 +0000593 sqlite3BtreeLeave(pBt);
drhc8629a12004-05-08 20:07:40 +0000594 return SQLITE_OK;
595}
596
597/*
drhecdc7532001-09-23 02:35:53 +0000598** Usage: btree_cursor ID TABLENUM WRITEABLE
drh5c4d9702001-08-20 00:33:58 +0000599**
600** Create a new cursor. Return the ID for the cursor.
601*/
602static int btree_cursor(
603 void *NotUsed,
604 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
605 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000606 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000607){
608 Btree *pBt;
609 int iTable;
610 BtCursor *pCur;
611 int rc;
drhecdc7532001-09-23 02:35:53 +0000612 int wrFlag;
drh5c4d9702001-08-20 00:33:58 +0000613 char zBuf[30];
614
drhecdc7532001-09-23 02:35:53 +0000615 if( argc!=4 ){
drh5c4d9702001-08-20 00:33:58 +0000616 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drhecdc7532001-09-23 02:35:53 +0000617 " ID TABLENUM WRITEABLE\"", 0);
drh5c4d9702001-08-20 00:33:58 +0000618 return TCL_ERROR;
619 }
drhe8f52c52008-07-12 14:52:20 +0000620 pBt = sqlite3TestTextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000621 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
drhecdc7532001-09-23 02:35:53 +0000622 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
danielk1977cd3e8f72008-03-25 09:47:35 +0000623 pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize());
624 memset(pCur, 0, sqlite3BtreeCursorSize());
drhff0587c2007-08-29 17:43:19 +0000625 sqlite3BtreeEnter(pBt);
danielk1977cd3e8f72008-03-25 09:47:35 +0000626 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur);
drhff0587c2007-08-29 17:43:19 +0000627 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000628 if( rc ){
danielk1977cd3e8f72008-03-25 09:47:35 +0000629 ckfree((char *)pCur);
drh5c4d9702001-08-20 00:33:58 +0000630 Tcl_AppendResult(interp, errorName(rc), 0);
631 return TCL_ERROR;
632 }
drhfe63d1c2004-09-08 20:13:04 +0000633 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
drh5c4d9702001-08-20 00:33:58 +0000634 Tcl_AppendResult(interp, zBuf, 0);
635 return SQLITE_OK;
636}
637
638/*
639** Usage: btree_close_cursor ID
640**
641** Close a cursor opened using btree_cursor.
642*/
643static int btree_close_cursor(
644 void *NotUsed,
645 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
646 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000647 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000648){
649 BtCursor *pCur;
drhff0587c2007-08-29 17:43:19 +0000650 Btree *pBt;
drh5c4d9702001-08-20 00:33:58 +0000651 int rc;
652
653 if( argc!=2 ){
654 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
655 " ID\"", 0);
656 return TCL_ERROR;
657 }
drhe8f52c52008-07-12 14:52:20 +0000658 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000659 pBt = pCur->pBtree;
660 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000661 rc = sqlite3BtreeCloseCursor(pCur);
drhff0587c2007-08-29 17:43:19 +0000662 sqlite3BtreeLeave(pBt);
danielk1977cd3e8f72008-03-25 09:47:35 +0000663 ckfree((char *)pCur);
drh5c4d9702001-08-20 00:33:58 +0000664 if( rc ){
665 Tcl_AppendResult(interp, errorName(rc), 0);
666 return TCL_ERROR;
667 }
668 return SQLITE_OK;
669}
670
671/*
672** Usage: btree_move_to ID KEY
673**
674** Move the cursor to the entry with the given key.
675*/
676static int btree_move_to(
677 void *NotUsed,
678 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
679 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000680 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000681){
682 BtCursor *pCur;
683 int rc;
684 int res;
685 char zBuf[20];
686
687 if( argc!=3 ){
688 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
689 " ID KEY\"", 0);
690 return TCL_ERROR;
691 }
drhe8f52c52008-07-12 14:52:20 +0000692 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000693 sqlite3BtreeEnter(pCur->pBtree);
drhde647132004-05-07 17:57:49 +0000694 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
695 int iKey;
drhff0587c2007-08-29 17:43:19 +0000696 if( Tcl_GetInt(interp, argv[2], &iKey) ){
697 sqlite3BtreeLeave(pCur->pBtree);
698 return TCL_ERROR;
699 }
drhe63d9992008-08-13 19:11:48 +0000700 rc = sqlite3BtreeMovetoUnpacked(pCur, 0, iKey, 0, &res);
drhde647132004-05-07 17:57:49 +0000701 }else{
drhe63d9992008-08-13 19:11:48 +0000702 rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res);
drhde647132004-05-07 17:57:49 +0000703 }
drhff0587c2007-08-29 17:43:19 +0000704 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000705 if( rc ){
706 Tcl_AppendResult(interp, errorName(rc), 0);
707 return TCL_ERROR;
708 }
drhce927062001-11-09 13:41:09 +0000709 if( res<0 ) res = -1;
710 if( res>0 ) res = 1;
drhfe63d1c2004-09-08 20:13:04 +0000711 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",res);
drh5c4d9702001-08-20 00:33:58 +0000712 Tcl_AppendResult(interp, zBuf, 0);
713 return SQLITE_OK;
714}
715
716/*
717** Usage: btree_delete ID
718**
719** Delete the entry that the cursor is pointing to
720*/
721static int btree_delete(
722 void *NotUsed,
723 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
724 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000725 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000726){
727 BtCursor *pCur;
728 int rc;
729
730 if( argc!=2 ){
731 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
732 " ID\"", 0);
733 return TCL_ERROR;
734 }
drhe8f52c52008-07-12 14:52:20 +0000735 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000736 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000737 rc = sqlite3BtreeDelete(pCur);
drhff0587c2007-08-29 17:43:19 +0000738 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000739 if( rc ){
740 Tcl_AppendResult(interp, errorName(rc), 0);
741 return TCL_ERROR;
742 }
743 return SQLITE_OK;
744}
745
746/*
drhb026e052007-05-02 01:34:31 +0000747** Usage: btree_insert ID KEY DATA ?NZERO?
drh5c4d9702001-08-20 00:33:58 +0000748**
749** Create a new entry with the given key and data. If an entry already
750** exists with the same key the old entry is overwritten.
751*/
752static int btree_insert(
danielk1977312d6b32004-06-29 13:18:23 +0000753 void * clientData,
754 Tcl_Interp *interp,
755 int objc,
756 Tcl_Obj *CONST objv[]
drh5c4d9702001-08-20 00:33:58 +0000757){
758 BtCursor *pCur;
759 int rc;
drhb026e052007-05-02 01:34:31 +0000760 int nZero;
drh5c4d9702001-08-20 00:33:58 +0000761
drhb026e052007-05-02 01:34:31 +0000762 if( objc!=4 && objc!=5 ){
763 Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA ?NZERO?");
drh5c4d9702001-08-20 00:33:58 +0000764 return TCL_ERROR;
765 }
drhe8f52c52008-07-12 14:52:20 +0000766 pCur = sqlite3TestTextToPtr(Tcl_GetString(objv[1]));
drhb026e052007-05-02 01:34:31 +0000767 if( objc==5 ){
768 if( Tcl_GetIntFromObj(interp, objv[4], &nZero) ) return TCL_ERROR;
769 }else{
770 nZero = 0;
771 }
drhff0587c2007-08-29 17:43:19 +0000772 sqlite3BtreeEnter(pCur->pBtree);
danielk1977312d6b32004-06-29 13:18:23 +0000773 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
774 i64 iKey;
775 int len;
776 unsigned char *pBuf;
drhff0587c2007-08-29 17:43:19 +0000777 if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ){
778 sqlite3BtreeLeave(pCur->pBtree);
779 return TCL_ERROR;
780 }
danielk1977312d6b32004-06-29 13:18:23 +0000781 pBuf = Tcl_GetByteArrayFromObj(objv[3], &len);
drhb026e052007-05-02 01:34:31 +0000782 rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0);
drhde647132004-05-07 17:57:49 +0000783 }else{
danielk1977312d6b32004-06-29 13:18:23 +0000784 int keylen;
785 int dlen;
786 unsigned char *pKBuf;
787 unsigned char *pDBuf;
788 pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen);
789 pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen);
drhb026e052007-05-02 01:34:31 +0000790 rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, nZero, 0);
drhde647132004-05-07 17:57:49 +0000791 }
drhff0587c2007-08-29 17:43:19 +0000792 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000793 if( rc ){
794 Tcl_AppendResult(interp, errorName(rc), 0);
795 return TCL_ERROR;
796 }
797 return SQLITE_OK;
798}
799
800/*
801** Usage: btree_next ID
802**
drh2dcc9aa2002-12-04 13:40:25 +0000803** Move the cursor to the next entry in the table. Return 0 on success
804** or 1 if the cursor was already on the last entry in the table or if
805** the table is empty.
drh5c4d9702001-08-20 00:33:58 +0000806*/
807static int btree_next(
808 void *NotUsed,
809 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
810 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000811 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000812){
813 BtCursor *pCur;
814 int rc;
drh0de8c112002-07-06 16:32:14 +0000815 int res = 0;
816 char zBuf[100];
drh5c4d9702001-08-20 00:33:58 +0000817
818 if( argc!=2 ){
819 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
820 " ID\"", 0);
821 return TCL_ERROR;
822 }
drhe8f52c52008-07-12 14:52:20 +0000823 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000824 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000825 rc = sqlite3BtreeNext(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000826 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000827 if( rc ){
828 Tcl_AppendResult(interp, errorName(rc), 0);
829 return TCL_ERROR;
830 }
drhfe63d1c2004-09-08 20:13:04 +0000831 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000832 Tcl_AppendResult(interp, zBuf, 0);
833 return SQLITE_OK;
834}
835
836/*
drh2dcc9aa2002-12-04 13:40:25 +0000837** Usage: btree_prev ID
838**
839** Move the cursor to the previous entry in the table. Return 0 on
840** success and 1 if the cursor was already on the first entry in
841** the table or if the table was empty.
842*/
843static int btree_prev(
844 void *NotUsed,
845 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
846 int argc, /* Number of arguments */
847 const char **argv /* Text of each argument */
848){
849 BtCursor *pCur;
850 int rc;
851 int res = 0;
852 char zBuf[100];
853
854 if( argc!=2 ){
855 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
856 " ID\"", 0);
857 return TCL_ERROR;
858 }
drhe8f52c52008-07-12 14:52:20 +0000859 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000860 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000861 rc = sqlite3BtreePrevious(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000862 sqlite3BtreeLeave(pCur->pBtree);
drh2dcc9aa2002-12-04 13:40:25 +0000863 if( rc ){
864 Tcl_AppendResult(interp, errorName(rc), 0);
865 return TCL_ERROR;
866 }
drhfe63d1c2004-09-08 20:13:04 +0000867 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh2dcc9aa2002-12-04 13:40:25 +0000868 Tcl_AppendResult(interp, zBuf, 0);
869 return SQLITE_OK;
870}
871
872/*
drh0de8c112002-07-06 16:32:14 +0000873** Usage: btree_first ID
874**
drh2dcc9aa2002-12-04 13:40:25 +0000875** Move the cursor to the first entry in the table. Return 0 if the
876** cursor was left point to something and 1 if the table is empty.
drh0de8c112002-07-06 16:32:14 +0000877*/
878static int btree_first(
879 void *NotUsed,
880 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
881 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000882 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +0000883){
884 BtCursor *pCur;
885 int rc;
886 int res = 0;
887 char zBuf[100];
888
889 if( argc!=2 ){
890 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
891 " ID\"", 0);
892 return TCL_ERROR;
893 }
drhe8f52c52008-07-12 14:52:20 +0000894 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000895 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000896 rc = sqlite3BtreeFirst(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000897 sqlite3BtreeLeave(pCur->pBtree);
drh0de8c112002-07-06 16:32:14 +0000898 if( rc ){
899 Tcl_AppendResult(interp, errorName(rc), 0);
900 return TCL_ERROR;
901 }
drhfe63d1c2004-09-08 20:13:04 +0000902 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000903 Tcl_AppendResult(interp, zBuf, 0);
drh5c4d9702001-08-20 00:33:58 +0000904 return SQLITE_OK;
905}
906
907/*
drh2dcc9aa2002-12-04 13:40:25 +0000908** Usage: btree_last ID
909**
910** Move the cursor to the last entry in the table. Return 0 if the
911** cursor was left point to something and 1 if the table is empty.
912*/
913static int btree_last(
914 void *NotUsed,
915 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
916 int argc, /* Number of arguments */
917 const char **argv /* Text of each argument */
918){
919 BtCursor *pCur;
920 int rc;
921 int res = 0;
922 char zBuf[100];
923
924 if( argc!=2 ){
925 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
926 " ID\"", 0);
927 return TCL_ERROR;
928 }
drhe8f52c52008-07-12 14:52:20 +0000929 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000930 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000931 rc = sqlite3BtreeLast(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000932 sqlite3BtreeLeave(pCur->pBtree);
drh2dcc9aa2002-12-04 13:40:25 +0000933 if( rc ){
934 Tcl_AppendResult(interp, errorName(rc), 0);
935 return TCL_ERROR;
936 }
drhfe63d1c2004-09-08 20:13:04 +0000937 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh2dcc9aa2002-12-04 13:40:25 +0000938 Tcl_AppendResult(interp, zBuf, 0);
939 return SQLITE_OK;
940}
941
942/*
drhc39e0002004-05-07 23:50:57 +0000943** Usage: btree_eof ID
944**
945** Return TRUE if the given cursor is not pointing at a valid entry.
946** Return FALSE if the cursor does point to a valid entry.
947*/
948static int btree_eof(
949 void *NotUsed,
950 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
951 int argc, /* Number of arguments */
952 const char **argv /* Text of each argument */
953){
954 BtCursor *pCur;
drhff0587c2007-08-29 17:43:19 +0000955 int rc;
drhc39e0002004-05-07 23:50:57 +0000956 char zBuf[50];
957
958 if( argc!=2 ){
959 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
960 " ID\"", 0);
961 return TCL_ERROR;
962 }
drhe8f52c52008-07-12 14:52:20 +0000963 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000964 sqlite3BtreeEnter(pCur->pBtree);
965 rc = sqlite3BtreeEof(pCur);
966 sqlite3BtreeLeave(pCur->pBtree);
967 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
drhc39e0002004-05-07 23:50:57 +0000968 Tcl_AppendResult(interp, zBuf, 0);
969 return SQLITE_OK;
970}
971
972/*
drh4fc0fb42004-05-07 02:26:28 +0000973** Usage: btree_keysize ID
974**
drh0e1c19e2004-05-11 00:58:56 +0000975** Return the number of bytes of key. For an INTKEY table, this
976** returns the key itself.
drh4fc0fb42004-05-07 02:26:28 +0000977*/
978static int btree_keysize(
979 void *NotUsed,
980 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
981 int argc, /* Number of arguments */
982 const char **argv /* Text of each argument */
983){
984 BtCursor *pCur;
drha34b6762004-05-07 13:30:42 +0000985 u64 n;
drh4fc0fb42004-05-07 02:26:28 +0000986 char zBuf[50];
987
988 if( argc!=2 ){
989 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
990 " ID\"", 0);
991 return TCL_ERROR;
992 }
drhe8f52c52008-07-12 14:52:20 +0000993 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000994 sqlite3BtreeEnter(pCur->pBtree);
drh03d847e2005-12-09 20:21:58 +0000995 sqlite3BtreeKeySize(pCur, (i64*)&n);
drhff0587c2007-08-29 17:43:19 +0000996 sqlite3BtreeLeave(pCur->pBtree);
drhfe63d1c2004-09-08 20:13:04 +0000997 sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n);
drh4fc0fb42004-05-07 02:26:28 +0000998 Tcl_AppendResult(interp, zBuf, 0);
999 return SQLITE_OK;
1000}
1001
1002/*
drh5c4d9702001-08-20 00:33:58 +00001003** Usage: btree_key ID
1004**
1005** Return the key for the entry at which the cursor is pointing.
1006*/
1007static int btree_key(
1008 void *NotUsed,
1009 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1010 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +00001011 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +00001012){
1013 BtCursor *pCur;
1014 int rc;
drh4fc0fb42004-05-07 02:26:28 +00001015 u64 n;
drh5c4d9702001-08-20 00:33:58 +00001016 char *zBuf;
1017
1018 if( argc!=2 ){
1019 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1020 " ID\"", 0);
1021 return TCL_ERROR;
1022 }
drhe8f52c52008-07-12 14:52:20 +00001023 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +00001024 sqlite3BtreeEnter(pCur->pBtree);
drh03d847e2005-12-09 20:21:58 +00001025 sqlite3BtreeKeySize(pCur, (i64*)&n);
drha34b6762004-05-07 13:30:42 +00001026 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
1027 char zBuf2[60];
drhf7a83622004-09-17 19:39:23 +00001028 sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n);
drha34b6762004-05-07 13:30:42 +00001029 Tcl_AppendResult(interp, zBuf2, 0);
1030 }else{
drh17435752007-08-16 04:30:38 +00001031 zBuf = sqlite3_malloc( n+1 );
drha34b6762004-05-07 13:30:42 +00001032 rc = sqlite3BtreeKey(pCur, 0, n, zBuf);
drhde647132004-05-07 17:57:49 +00001033 if( rc ){
drhff0587c2007-08-29 17:43:19 +00001034 sqlite3BtreeLeave(pCur->pBtree);
drhde647132004-05-07 17:57:49 +00001035 Tcl_AppendResult(interp, errorName(rc), 0);
drha34b6762004-05-07 13:30:42 +00001036 return TCL_ERROR;
1037 }
1038 zBuf[n] = 0;
1039 Tcl_AppendResult(interp, zBuf, 0);
drh17435752007-08-16 04:30:38 +00001040 sqlite3_free(zBuf);
drh5c4d9702001-08-20 00:33:58 +00001041 }
drhff0587c2007-08-29 17:43:19 +00001042 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +00001043 return SQLITE_OK;
1044}
1045
1046/*
danielk19777701e812005-01-10 12:59:51 +00001047** Usage: btree_data ID ?N?
drh5c4d9702001-08-20 00:33:58 +00001048**
1049** Return the data for the entry at which the cursor is pointing.
1050*/
1051static int btree_data(
1052 void *NotUsed,
1053 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1054 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +00001055 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +00001056){
1057 BtCursor *pCur;
1058 int rc;
drha34b6762004-05-07 13:30:42 +00001059 u32 n;
drh5c4d9702001-08-20 00:33:58 +00001060 char *zBuf;
1061
danielk19777701e812005-01-10 12:59:51 +00001062 if( argc!=2 && argc!=3 ){
drh5c4d9702001-08-20 00:33:58 +00001063 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1064 " ID\"", 0);
1065 return TCL_ERROR;
1066 }
drhe8f52c52008-07-12 14:52:20 +00001067 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +00001068 sqlite3BtreeEnter(pCur->pBtree);
danielk19777701e812005-01-10 12:59:51 +00001069 if( argc==2 ){
1070 sqlite3BtreeDataSize(pCur, &n);
1071 }else{
1072 n = atoi(argv[2]);
1073 }
drh17435752007-08-16 04:30:38 +00001074 zBuf = sqlite3_malloc( n+1 );
drh4fc0fb42004-05-07 02:26:28 +00001075 rc = sqlite3BtreeData(pCur, 0, n, zBuf);
drhff0587c2007-08-29 17:43:19 +00001076 sqlite3BtreeLeave(pCur->pBtree);
drhde647132004-05-07 17:57:49 +00001077 if( rc ){
1078 Tcl_AppendResult(interp, errorName(rc), 0);
danielk197731dad9d2007-08-16 11:36:15 +00001079 sqlite3_free(zBuf);
drh5c4d9702001-08-20 00:33:58 +00001080 return TCL_ERROR;
1081 }
1082 zBuf[n] = 0;
1083 Tcl_AppendResult(interp, zBuf, 0);
drh17435752007-08-16 04:30:38 +00001084 sqlite3_free(zBuf);
drh5c4d9702001-08-20 00:33:58 +00001085 return SQLITE_OK;
1086}
1087
1088/*
drh0e1c19e2004-05-11 00:58:56 +00001089** Usage: btree_fetch_key ID AMT
1090**
1091** Use the sqlite3BtreeKeyFetch() routine to get AMT bytes of the key.
1092** If sqlite3BtreeKeyFetch() fails, return an empty string.
1093*/
1094static int btree_fetch_key(
1095 void *NotUsed,
1096 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1097 int argc, /* Number of arguments */
1098 const char **argv /* Text of each argument */
1099){
1100 BtCursor *pCur;
1101 int n;
drhe51c44f2004-05-30 20:46:09 +00001102 int amt;
drh0e1c19e2004-05-11 00:58:56 +00001103 u64 nKey;
1104 const char *zBuf;
1105 char zStatic[1000];
1106
1107 if( argc!=3 ){
1108 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1109 " ID AMT\"", 0);
1110 return TCL_ERROR;
1111 }
drhe8f52c52008-07-12 14:52:20 +00001112 pCur = sqlite3TestTextToPtr(argv[1]);
drh0e1c19e2004-05-11 00:58:56 +00001113 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
drhff0587c2007-08-29 17:43:19 +00001114 sqlite3BtreeEnter(pCur->pBtree);
drh03d847e2005-12-09 20:21:58 +00001115 sqlite3BtreeKeySize(pCur, (i64*)&nKey);
drhe51c44f2004-05-30 20:46:09 +00001116 zBuf = sqlite3BtreeKeyFetch(pCur, &amt);
1117 if( zBuf && amt>=n ){
drh0e1c19e2004-05-11 00:58:56 +00001118 assert( nKey<sizeof(zStatic) );
1119 if( n>0 ) nKey = n;
1120 memcpy(zStatic, zBuf, (int)nKey);
1121 zStatic[nKey] = 0;
1122 Tcl_AppendResult(interp, zStatic, 0);
1123 }
drhff0587c2007-08-29 17:43:19 +00001124 sqlite3BtreeLeave(pCur->pBtree);
drh0e1c19e2004-05-11 00:58:56 +00001125 return TCL_OK;
1126}
1127
1128/*
1129** Usage: btree_fetch_data ID AMT
1130**
1131** Use the sqlite3BtreeDataFetch() routine to get AMT bytes of the key.
1132** If sqlite3BtreeDataFetch() fails, return an empty string.
1133*/
1134static int btree_fetch_data(
1135 void *NotUsed,
1136 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1137 int argc, /* Number of arguments */
1138 const char **argv /* Text of each argument */
1139){
1140 BtCursor *pCur;
1141 int n;
drhe51c44f2004-05-30 20:46:09 +00001142 int amt;
drh0e1c19e2004-05-11 00:58:56 +00001143 u32 nData;
1144 const char *zBuf;
1145 char zStatic[1000];
1146
1147 if( argc!=3 ){
1148 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drhe51c44f2004-05-30 20:46:09 +00001149 " ID AMT\"", 0);
drh0e1c19e2004-05-11 00:58:56 +00001150 return TCL_ERROR;
1151 }
drhe8f52c52008-07-12 14:52:20 +00001152 pCur = sqlite3TestTextToPtr(argv[1]);
drh0e1c19e2004-05-11 00:58:56 +00001153 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
drhff0587c2007-08-29 17:43:19 +00001154 sqlite3BtreeEnter(pCur->pBtree);
drh0e1c19e2004-05-11 00:58:56 +00001155 sqlite3BtreeDataSize(pCur, &nData);
drhe51c44f2004-05-30 20:46:09 +00001156 zBuf = sqlite3BtreeDataFetch(pCur, &amt);
1157 if( zBuf && amt>=n ){
drh0e1c19e2004-05-11 00:58:56 +00001158 assert( nData<sizeof(zStatic) );
1159 if( n>0 ) nData = n;
1160 memcpy(zStatic, zBuf, (int)nData);
1161 zStatic[nData] = 0;
1162 Tcl_AppendResult(interp, zStatic, 0);
1163 }
drhff0587c2007-08-29 17:43:19 +00001164 sqlite3BtreeLeave(pCur->pBtree);
drh0e1c19e2004-05-11 00:58:56 +00001165 return TCL_OK;
1166}
1167
1168/*
drh0de8c112002-07-06 16:32:14 +00001169** Usage: btree_payload_size ID
1170**
1171** Return the number of bytes of payload
1172*/
1173static int btree_payload_size(
1174 void *NotUsed,
1175 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1176 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +00001177 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +00001178){
1179 BtCursor *pCur;
drh4fc0fb42004-05-07 02:26:28 +00001180 int n2;
drha34b6762004-05-07 13:30:42 +00001181 u64 n1;
drh0de8c112002-07-06 16:32:14 +00001182 char zBuf[50];
1183
1184 if( argc!=2 ){
1185 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1186 " ID\"", 0);
1187 return TCL_ERROR;
1188 }
drhe8f52c52008-07-12 14:52:20 +00001189 pCur = sqlite3TestTextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +00001190 sqlite3BtreeEnter(pCur->pBtree);
drha34b6762004-05-07 13:30:42 +00001191 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
1192 n1 = 0;
1193 }else{
drh03d847e2005-12-09 20:21:58 +00001194 sqlite3BtreeKeySize(pCur, (i64*)&n1);
drha34b6762004-05-07 13:30:42 +00001195 }
drh03d847e2005-12-09 20:21:58 +00001196 sqlite3BtreeDataSize(pCur, (u32*)&n2);
drhff0587c2007-08-29 17:43:19 +00001197 sqlite3BtreeLeave(pCur->pBtree);
drhfe63d1c2004-09-08 20:13:04 +00001198 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
drh0de8c112002-07-06 16:32:14 +00001199 Tcl_AppendResult(interp, zBuf, 0);
drh0de8c112002-07-06 16:32:14 +00001200 return SQLITE_OK;
1201}
1202
1203/*
drh3e27c022004-07-23 00:01:38 +00001204** Usage: btree_cursor_info ID ?UP-CNT?
drh5c4d9702001-08-20 00:33:58 +00001205**
drh3e27c022004-07-23 00:01:38 +00001206** Return integers containing information about the entry the
drh5c4d9702001-08-20 00:33:58 +00001207** cursor is pointing to:
1208**
1209** aResult[0] = The page number
1210** aResult[1] = The entry number
1211** aResult[2] = Total number of entries on this page
drh3e27c022004-07-23 00:01:38 +00001212** aResult[3] = Cell size (local payload + header)
drh5c4d9702001-08-20 00:33:58 +00001213** aResult[4] = Number of free bytes on this page
1214** aResult[5] = Number of free blocks on the page
drh3e27c022004-07-23 00:01:38 +00001215** aResult[6] = Total payload size (local + overflow)
1216** aResult[7] = Header size in bytes
1217** aResult[8] = Local payload size
1218** aResult[9] = Parent page number
drh50c67062007-02-10 19:22:35 +00001219** aResult[10]= Page number of the first overflow page
drh5c4d9702001-08-20 00:33:58 +00001220*/
drhc12fc0d2004-05-09 00:40:52 +00001221static int btree_cursor_info(
drh5c4d9702001-08-20 00:33:58 +00001222 void *NotUsed,
1223 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1224 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +00001225 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +00001226){
1227 BtCursor *pCur;
1228 int rc;
1229 int i, j;
drh3e27c022004-07-23 00:01:38 +00001230 int up;
drh50c67062007-02-10 19:22:35 +00001231 int aResult[11];
drh5c4d9702001-08-20 00:33:58 +00001232 char zBuf[400];
1233
drh3e27c022004-07-23 00:01:38 +00001234 if( argc!=2 && argc!=3 ){
drh5c4d9702001-08-20 00:33:58 +00001235 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drh3e27c022004-07-23 00:01:38 +00001236 " ID ?UP-CNT?\"", 0);
drh5c4d9702001-08-20 00:33:58 +00001237 return TCL_ERROR;
1238 }
drhe8f52c52008-07-12 14:52:20 +00001239 pCur = sqlite3TestTextToPtr(argv[1]);
drh3e27c022004-07-23 00:01:38 +00001240 if( argc==3 ){
1241 if( Tcl_GetInt(interp, argv[2], &up) ) return TCL_ERROR;
1242 }else{
1243 up = 0;
1244 }
drhff0587c2007-08-29 17:43:19 +00001245 sqlite3BtreeEnter(pCur->pBtree);
drh3e27c022004-07-23 00:01:38 +00001246 rc = sqlite3BtreeCursorInfo(pCur, aResult, up);
drh5c4d9702001-08-20 00:33:58 +00001247 if( rc ){
1248 Tcl_AppendResult(interp, errorName(rc), 0);
drhff0587c2007-08-29 17:43:19 +00001249 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +00001250 return TCL_ERROR;
1251 }
1252 j = 0;
1253 for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){
drhfe63d1c2004-09-08 20:13:04 +00001254 sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]);
drh5c4d9702001-08-20 00:33:58 +00001255 j += strlen(&zBuf[j]);
1256 }
drhff0587c2007-08-29 17:43:19 +00001257 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +00001258 Tcl_AppendResult(interp, &zBuf[1], 0);
1259 return SQLITE_OK;
1260}
1261
1262/*
drh50c67062007-02-10 19:22:35 +00001263** Copied from btree.c:
1264*/
drh4f0c5872007-03-26 22:05:01 +00001265static u32 t4Get4byte(unsigned char *p){
drh50c67062007-02-10 19:22:35 +00001266 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
1267}
1268
1269/*
1270** btree_ovfl_info BTREE CURSOR
1271**
1272** Given a cursor, return the sequence of pages number that form the
1273** overflow pages for the data of the entry that the cursor is point
1274** to.
1275*/
1276static int btree_ovfl_info(
1277 void *NotUsed,
1278 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1279 int argc, /* Number of arguments */
1280 const char **argv /* Text of each argument */
1281){
1282 Btree *pBt;
1283 BtCursor *pCur;
1284 Pager *pPager;
1285 int rc;
1286 int n;
1287 int dataSize;
1288 u32 pgno;
1289 void *pPage;
1290 int aResult[11];
1291 char zElem[100];
1292 Tcl_DString str;
1293
1294 if( argc!=3 ){
1295 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1296 " BTREE CURSOR", 0);
1297 return TCL_ERROR;
1298 }
drhe8f52c52008-07-12 14:52:20 +00001299 pBt = sqlite3TestTextToPtr(argv[1]);
1300 pCur = sqlite3TestTextToPtr(argv[2]);
drh50c67062007-02-10 19:22:35 +00001301 if( (*(void**)pCur) != (void*)pBt ){
1302 Tcl_AppendResult(interp, "Cursor ", argv[2], " does not belong to btree ",
1303 argv[1], 0);
1304 return TCL_ERROR;
1305 }
drhff0587c2007-08-29 17:43:19 +00001306 sqlite3BtreeEnter(pBt);
drh50c67062007-02-10 19:22:35 +00001307 pPager = sqlite3BtreePager(pBt);
1308 rc = sqlite3BtreeCursorInfo(pCur, aResult, 0);
1309 if( rc ){
1310 Tcl_AppendResult(interp, errorName(rc), 0);
drhff0587c2007-08-29 17:43:19 +00001311 sqlite3BtreeLeave(pBt);
drh50c67062007-02-10 19:22:35 +00001312 return TCL_ERROR;
1313 }
danielk19774152e672007-09-12 17:01:45 +00001314 dataSize = pBt->pBt->usableSize;
drh50c67062007-02-10 19:22:35 +00001315 Tcl_DStringInit(&str);
1316 n = aResult[6] - aResult[8];
1317 n = (n + dataSize - 1)/dataSize;
1318 pgno = (u32)aResult[10];
1319 while( pgno && n-- ){
danielk19773b8a05f2007-03-19 17:44:26 +00001320 DbPage *pDbPage;
drh50c67062007-02-10 19:22:35 +00001321 sprintf(zElem, "%d", pgno);
1322 Tcl_DStringAppendElement(&str, zElem);
danielk19773b8a05f2007-03-19 17:44:26 +00001323 if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){
drh50c67062007-02-10 19:22:35 +00001324 Tcl_DStringFree(&str);
1325 Tcl_AppendResult(interp, "unable to get page ", zElem, 0);
drhff0587c2007-08-29 17:43:19 +00001326 sqlite3BtreeLeave(pBt);
drh50c67062007-02-10 19:22:35 +00001327 return TCL_ERROR;
1328 }
danielk19773b8a05f2007-03-19 17:44:26 +00001329 pPage = sqlite3PagerGetData(pDbPage);
drh4f0c5872007-03-26 22:05:01 +00001330 pgno = t4Get4byte((unsigned char*)pPage);
danielk19773b8a05f2007-03-19 17:44:26 +00001331 sqlite3PagerUnref(pDbPage);
drh50c67062007-02-10 19:22:35 +00001332 }
drhff0587c2007-08-29 17:43:19 +00001333 sqlite3BtreeLeave(pBt);
drh50c67062007-02-10 19:22:35 +00001334 Tcl_DStringResult(interp, &str);
1335 return SQLITE_OK;
1336}
1337
1338/*
drh9b171272004-05-08 02:03:22 +00001339** The command is provided for the purpose of setting breakpoints.
1340** in regression test scripts.
1341**
1342** By setting a GDB breakpoint on this procedure and executing the
1343** btree_breakpoint command in a test script, we can stop GDB at
1344** the point in the script where the btree_breakpoint command is
1345** inserted. This is useful for debugging.
1346*/
1347static int btree_breakpoint(
1348 void *NotUsed,
1349 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1350 int argc, /* Number of arguments */
1351 const char **argv /* Text of each argument */
1352){
1353 return TCL_OK;
1354}
1355
drh6d2fb152004-05-14 16:50:06 +00001356/*
1357** usage: varint_test START MULTIPLIER COUNT INCREMENT
1358**
shane3f8d5cf2008-04-24 19:15:09 +00001359** This command tests the putVarint() and getVarint()
drh6d2fb152004-05-14 16:50:06 +00001360** routines, both for accuracy and for speed.
1361**
shane3f8d5cf2008-04-24 19:15:09 +00001362** An integer is written using putVarint() and read back with
1363** getVarint() and varified to be unchanged. This repeats COUNT
drh6d2fb152004-05-14 16:50:06 +00001364** times. The first integer is START*MULTIPLIER. Each iteration
1365** increases the integer by INCREMENT.
1366**
1367** This command returns nothing if it works. It returns an error message
1368** if something goes wrong.
1369*/
1370static int btree_varint_test(
1371 void *NotUsed,
1372 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1373 int argc, /* Number of arguments */
1374 const char **argv /* Text of each argument */
1375){
1376 u32 start, mult, count, incr;
1377 u64 in, out;
drhd8820e82004-05-18 15:57:42 +00001378 int n1, n2, i, j;
drh6d2fb152004-05-14 16:50:06 +00001379 unsigned char zBuf[100];
1380 if( argc!=5 ){
1381 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1382 " START MULTIPLIER COUNT INCREMENT\"", 0);
1383 return TCL_ERROR;
1384 }
1385 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
1386 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
1387 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
1388 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
1389 in = start;
1390 in *= mult;
1391 for(i=0; i<count; i++){
drhd8820e82004-05-18 15:57:42 +00001392 char zErr[200];
shane3f8d5cf2008-04-24 19:15:09 +00001393 n1 = putVarint(zBuf, in);
drh6d2fb152004-05-14 16:50:06 +00001394 if( n1>9 || n1<1 ){
shane3f8d5cf2008-04-24 19:15:09 +00001395 sprintf(zErr, "putVarint returned %d - should be between 1 and 9", n1);
drhd8820e82004-05-18 15:57:42 +00001396 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +00001397 return TCL_ERROR;
1398 }
shane3f8d5cf2008-04-24 19:15:09 +00001399 n2 = getVarint(zBuf, &out);
drh6d2fb152004-05-14 16:50:06 +00001400 if( n1!=n2 ){
shane3f8d5cf2008-04-24 19:15:09 +00001401 sprintf(zErr, "putVarint returned %d and getVarint returned %d", n1, n2);
drhd8820e82004-05-18 15:57:42 +00001402 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +00001403 return TCL_ERROR;
1404 }
1405 if( in!=out ){
drhd8820e82004-05-18 15:57:42 +00001406 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
1407 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +00001408 return TCL_ERROR;
1409 }
drh9d213ef2004-06-30 04:02:11 +00001410 if( (in & 0xffffffff)==in ){
1411 u32 out32;
shane3f8d5cf2008-04-24 19:15:09 +00001412 n2 = getVarint32(zBuf, out32);
drh9d213ef2004-06-30 04:02:11 +00001413 out = out32;
1414 if( n1!=n2 ){
shane3f8d5cf2008-04-24 19:15:09 +00001415 sprintf(zErr, "putVarint returned %d and GetVarint32 returned %d",
drh9d213ef2004-06-30 04:02:11 +00001416 n1, n2);
1417 Tcl_AppendResult(interp, zErr, 0);
1418 return TCL_ERROR;
1419 }
1420 if( in!=out ){
1421 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
1422 in, out);
1423 Tcl_AppendResult(interp, zErr, 0);
1424 return TCL_ERROR;
1425 }
1426 }
drhd8820e82004-05-18 15:57:42 +00001427
1428 /* In order to get realistic timings, run getVarint 19 more times.
1429 ** This is because getVarint is called about 20 times more often
1430 ** than putVarint.
1431 */
1432 for(j=0; j<19; j++){
shane3f8d5cf2008-04-24 19:15:09 +00001433 getVarint(zBuf, &out);
drhd8820e82004-05-18 15:57:42 +00001434 }
drh6d2fb152004-05-14 16:50:06 +00001435 in += incr;
1436 }
1437 return TCL_OK;
1438}
drh9b171272004-05-08 02:03:22 +00001439
1440/*
danielk197742741be2005-01-08 12:42:39 +00001441** usage: btree_from_db DB-HANDLE
1442**
1443** This command returns the btree handle for the main database associated
1444** with the database-handle passed as the argument. Example usage:
1445**
1446** sqlite3 db test.db
1447** set bt [btree_from_db db]
1448*/
1449static int btree_from_db(
1450 void *NotUsed,
1451 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1452 int argc, /* Number of arguments */
1453 const char **argv /* Text of each argument */
1454){
1455 char zBuf[100];
1456 Tcl_CmdInfo info;
1457 sqlite3 *db;
1458 Btree *pBt;
danielk197763c64f32007-05-17 14:45:12 +00001459 int iDb = 0;
danielk197742741be2005-01-08 12:42:39 +00001460
danielk197763c64f32007-05-17 14:45:12 +00001461 if( argc!=2 && argc!=3 ){
danielk197742741be2005-01-08 12:42:39 +00001462 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
danielk197763c64f32007-05-17 14:45:12 +00001463 " DB-HANDLE ?N?\"", 0);
danielk197742741be2005-01-08 12:42:39 +00001464 return TCL_ERROR;
1465 }
1466
1467 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
1468 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
1469 return TCL_ERROR;
1470 }
danielk197763c64f32007-05-17 14:45:12 +00001471 if( argc==3 ){
1472 iDb = atoi(argv[2]);
1473 }
1474
danielk197742741be2005-01-08 12:42:39 +00001475 db = *((sqlite3 **)info.objClientData);
1476 assert( db );
1477
danielk197763c64f32007-05-17 14:45:12 +00001478 pBt = db->aDb[iDb].pBt;
danielk197742741be2005-01-08 12:42:39 +00001479 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
1480 Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
1481 return TCL_OK;
1482}
1483
danielk19771ad7f642005-01-20 05:24:32 +00001484
1485/*
1486** usage: btree_set_cache_size ID NCACHE
1487**
1488** Set the size of the cache used by btree $ID.
1489*/
1490static int btree_set_cache_size(
1491 void *NotUsed,
1492 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1493 int argc, /* Number of arguments */
1494 const char **argv /* Text of each argument */
1495){
1496 int nCache;
1497 Btree *pBt;
1498
1499 if( argc!=3 ){
1500 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1501 " BT NCACHE\"", 0);
1502 return TCL_ERROR;
1503 }
drhe8f52c52008-07-12 14:52:20 +00001504 pBt = sqlite3TestTextToPtr(argv[1]);
danielk19771ad7f642005-01-20 05:24:32 +00001505 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
danielk1977a1644fd2007-08-29 12:31:25 +00001506
drhe5fe6902007-12-07 18:55:28 +00001507 sqlite3_mutex_enter(pBt->db->mutex);
drhff0587c2007-08-29 17:43:19 +00001508 sqlite3BtreeEnter(pBt);
danielk19771ad7f642005-01-20 05:24:32 +00001509 sqlite3BtreeSetCacheSize(pBt, nCache);
drhff0587c2007-08-29 17:43:19 +00001510 sqlite3BtreeLeave(pBt);
drhe5fe6902007-12-07 18:55:28 +00001511 sqlite3_mutex_leave(pBt->db->mutex);
danielk1977a1644fd2007-08-29 12:31:25 +00001512
danielk19771ad7f642005-01-20 05:24:32 +00001513 return TCL_OK;
1514}
1515
danielk197717b90b52008-06-06 11:11:25 +00001516/*
1517** Usage: btree_ismemdb ID
1518**
1519** Return true if the B-Tree is in-memory.
1520*/
1521static int btree_ismemdb(
1522 void *NotUsed,
1523 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1524 int argc, /* Number of arguments */
1525 const char **argv /* Text of each argument */
1526){
1527 Btree *pBt;
1528 int res;
1529
1530 if( argc!=2 ){
1531 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1532 " ID\"", 0);
1533 return TCL_ERROR;
1534 }
drhe8f52c52008-07-12 14:52:20 +00001535 pBt = sqlite3TestTextToPtr(argv[1]);
danielk197717b90b52008-06-06 11:11:25 +00001536 sqlite3_mutex_enter(pBt->db->mutex);
1537 sqlite3BtreeEnter(pBt);
1538 res = sqlite3PagerIsMemdb(sqlite3BtreePager(pBt));
1539 sqlite3BtreeLeave(pBt);
1540 sqlite3_mutex_leave(pBt->db->mutex);
1541 Tcl_SetObjResult(interp, Tcl_NewBooleanObj(res));
1542 return SQLITE_OK;
1543}
1544
danielk19771ad7f642005-01-20 05:24:32 +00001545
danielk197742741be2005-01-08 12:42:39 +00001546/*
drh5c4d9702001-08-20 00:33:58 +00001547** Register commands with the TCL interpreter.
1548*/
1549int Sqlitetest3_Init(Tcl_Interp *interp){
drhc2eef3b2002-08-31 18:53:06 +00001550 static struct {
1551 char *zName;
1552 Tcl_CmdProc *xProc;
1553 } aCmd[] = {
1554 { "btree_open", (Tcl_CmdProc*)btree_open },
1555 { "btree_close", (Tcl_CmdProc*)btree_close },
1556 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction },
1557 { "btree_commit", (Tcl_CmdProc*)btree_commit },
1558 { "btree_rollback", (Tcl_CmdProc*)btree_rollback },
1559 { "btree_create_table", (Tcl_CmdProc*)btree_create_table },
1560 { "btree_drop_table", (Tcl_CmdProc*)btree_drop_table },
1561 { "btree_clear_table", (Tcl_CmdProc*)btree_clear_table },
1562 { "btree_get_meta", (Tcl_CmdProc*)btree_get_meta },
1563 { "btree_update_meta", (Tcl_CmdProc*)btree_update_meta },
drhc2eef3b2002-08-31 18:53:06 +00001564 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats },
drhc2eef3b2002-08-31 18:53:06 +00001565 { "btree_cursor", (Tcl_CmdProc*)btree_cursor },
1566 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor },
1567 { "btree_move_to", (Tcl_CmdProc*)btree_move_to },
1568 { "btree_delete", (Tcl_CmdProc*)btree_delete },
drhc2eef3b2002-08-31 18:53:06 +00001569 { "btree_next", (Tcl_CmdProc*)btree_next },
drh2dcc9aa2002-12-04 13:40:25 +00001570 { "btree_prev", (Tcl_CmdProc*)btree_prev },
drhc39e0002004-05-07 23:50:57 +00001571 { "btree_eof", (Tcl_CmdProc*)btree_eof },
drha34b6762004-05-07 13:30:42 +00001572 { "btree_keysize", (Tcl_CmdProc*)btree_keysize },
drhc2eef3b2002-08-31 18:53:06 +00001573 { "btree_key", (Tcl_CmdProc*)btree_key },
1574 { "btree_data", (Tcl_CmdProc*)btree_data },
drh0e1c19e2004-05-11 00:58:56 +00001575 { "btree_fetch_key", (Tcl_CmdProc*)btree_fetch_key },
1576 { "btree_fetch_data", (Tcl_CmdProc*)btree_fetch_data },
drhc2eef3b2002-08-31 18:53:06 +00001577 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
1578 { "btree_first", (Tcl_CmdProc*)btree_first },
drh2dcc9aa2002-12-04 13:40:25 +00001579 { "btree_last", (Tcl_CmdProc*)btree_last },
drhc2eef3b2002-08-31 18:53:06 +00001580 { "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check },
drh9b171272004-05-08 02:03:22 +00001581 { "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint },
drh6d2fb152004-05-14 16:50:06 +00001582 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test },
danielk19771d850a72004-05-31 08:26:49 +00001583 { "btree_begin_statement", (Tcl_CmdProc*)btree_begin_statement },
1584 { "btree_commit_statement", (Tcl_CmdProc*)btree_commit_statement },
1585 { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
danielk197742741be2005-01-08 12:42:39 +00001586 { "btree_from_db", (Tcl_CmdProc*)btree_from_db },
danielk19771ad7f642005-01-20 05:24:32 +00001587 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size },
danielk197707cb5602006-01-20 10:55:05 +00001588 { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info },
drh50c67062007-02-10 19:22:35 +00001589 { "btree_ovfl_info", (Tcl_CmdProc*)btree_ovfl_info },
danielk197707cb5602006-01-20 10:55:05 +00001590 { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
danielk197717b90b52008-06-06 11:11:25 +00001591 { "btree_ismemdb", (Tcl_CmdProc*)btree_ismemdb },
drhc2eef3b2002-08-31 18:53:06 +00001592 };
1593 int i;
1594
1595 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
1596 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
1597 }
danielk1977312d6b32004-06-29 13:18:23 +00001598
1599 /* The btree_insert command is implemented using the tcl 'object'
1600 ** interface, not the string interface like the other commands in this
1601 ** file. This is so binary data can be inserted into btree tables.
1602 */
1603 Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0);
drh5c4d9702001-08-20 00:33:58 +00001604 return TCL_OK;
1605}