blob: 4bf3f136906c4a3e0ee0622893fb577698126539 [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**
drhe5fe6902007-12-07 18:55:28 +000016** $Id: test3.c,v 1.88 2007/12/07 18:55:29 drh 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);
81 sDb.mutex = sqlite3_mutex_alloc(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 }
drhfe63d1c2004-09-08 20:13:04 +0000114 pBt = sqlite3TextToPtr(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 }
drhfe63d1c2004-09-08 20:13:04 +0000149 pBt = sqlite3TextToPtr(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 }
drhfe63d1c2004-09-08 20:13:04 +0000178 pBt = sqlite3TextToPtr(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 }
drhfe63d1c2004-09-08 20:13:04 +0000207 pBt = sqlite3TextToPtr(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 }
drhfe63d1c2004-09-08 20:13:04 +0000236 pBt = sqlite3TextToPtr(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 }
drhfe63d1c2004-09-08 20:13:04 +0000265 pBt = sqlite3TextToPtr(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 }
drhfe63d1c2004-09-08 20:13:04 +0000294 pBt = sqlite3TextToPtr(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 }
drhfe63d1c2004-09-08 20:13:04 +0000324 pBt = sqlite3TextToPtr(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 }
drhfe63d1c2004-09-08 20:13:04 +0000358 pBt = sqlite3TextToPtr(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 }
drhfe63d1c2004-09-08 20:13:04 +0000389 pBt = sqlite3TextToPtr(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);
drh23e11ca2004-05-04 17:27:28 +0000392 rc = sqlite3BtreeClearTable(pBt, iTable);
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 }
drhfe63d1c2004-09-08 20:13:04 +0000420 pBt = sqlite3TextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000421 for(i=0; i<SQLITE_N_BTREE_META; i++){
422 char zBuf[30];
drh23e11ca2004-05-04 17:27:28 +0000423 unsigned int 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 }
drhfe63d1c2004-09-08 20:13:04 +0000460 pBt = sqlite3TextToPtr(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/*
477** Usage: btree_page_dump ID PAGENUM
478**
479** Print a disassembly of a page on standard output
480*/
481static int btree_page_dump(
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 iPage;
489 int rc;
490
491 if( argc!=3 ){
492 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
493 " ID\"", 0);
494 return TCL_ERROR;
495 }
drhfe63d1c2004-09-08 20:13:04 +0000496 pBt = sqlite3TextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000497 if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR;
drhff0587c2007-08-29 17:43:19 +0000498 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000499 rc = sqlite3BtreePageDump(pBt, iPage, 0);
drhff0587c2007-08-29 17:43:19 +0000500 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000501 if( rc!=SQLITE_OK ){
502 Tcl_AppendResult(interp, errorName(rc), 0);
503 return TCL_ERROR;
504 }
505 return TCL_OK;
506}
507
508/*
509** Usage: btree_tree_dump ID PAGENUM
510**
511** Print a disassembly of a page and all its child pages on standard output
512*/
513static int btree_tree_dump(
514 void *NotUsed,
515 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
516 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000517 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000518){
519 Btree *pBt;
520 int iPage;
521 int rc;
522
523 if( argc!=3 ){
524 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
525 " ID\"", 0);
526 return TCL_ERROR;
527 }
drhfe63d1c2004-09-08 20:13:04 +0000528 pBt = sqlite3TextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000529 if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR;
drhff0587c2007-08-29 17:43:19 +0000530 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000531 rc = sqlite3BtreePageDump(pBt, iPage, 1);
drhff0587c2007-08-29 17:43:19 +0000532 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000533 if( rc!=SQLITE_OK ){
534 Tcl_AppendResult(interp, errorName(rc), 0);
535 return TCL_ERROR;
536 }
537 return TCL_OK;
538}
539
540/*
541** Usage: btree_pager_stats ID
542**
543** Returns pager statistics
544*/
545static int btree_pager_stats(
546 void *NotUsed,
547 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
548 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000549 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000550){
551 Btree *pBt;
552 int i;
553 int *a;
554
555 if( argc!=2 ){
556 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
557 " ID\"", 0);
558 return TCL_ERROR;
559 }
drhfe63d1c2004-09-08 20:13:04 +0000560 pBt = sqlite3TextToPtr(argv[1]);
danielk1977f3c62652007-08-30 08:27:39 +0000561
562 /* Normally in this file, with a b-tree handle opened using the
563 ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly.
564 ** But this function is sometimes called with a btree handle obtained
565 ** from an open SQLite connection (using [btree_from_db]). In this case
566 ** we need to obtain the mutex for the controlling SQLite handle before
567 ** it is safe to call sqlite3BtreeEnter().
568 */
drhe5fe6902007-12-07 18:55:28 +0000569 sqlite3_mutex_enter(pBt->db->mutex);
danielk1977f3c62652007-08-30 08:27:39 +0000570
drh27641702007-08-22 02:56:42 +0000571 sqlite3BtreeEnter(pBt);
danielk19773b8a05f2007-03-19 17:44:26 +0000572 a = sqlite3PagerStats(sqlite3BtreePager(pBt));
danielk197742741be2005-01-08 12:42:39 +0000573 for(i=0; i<11; i++){
drh5c4d9702001-08-20 00:33:58 +0000574 static char *zName[] = {
575 "ref", "page", "max", "size", "state", "err",
danielk197742741be2005-01-08 12:42:39 +0000576 "hit", "miss", "ovfl", "read", "write"
drh5c4d9702001-08-20 00:33:58 +0000577 };
578 char zBuf[100];
579 Tcl_AppendElement(interp, zName[i]);
drhfe63d1c2004-09-08 20:13:04 +0000580 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]);
drh5c4d9702001-08-20 00:33:58 +0000581 Tcl_AppendElement(interp, zBuf);
582 }
drh27641702007-08-22 02:56:42 +0000583 sqlite3BtreeLeave(pBt);
danielk1977f3c62652007-08-30 08:27:39 +0000584
585 /* Release the mutex on the SQLite handle that controls this b-tree */
drhe5fe6902007-12-07 18:55:28 +0000586 sqlite3_mutex_leave(pBt->db->mutex);
drh5c4d9702001-08-20 00:33:58 +0000587 return TCL_OK;
588}
589
590/*
591** Usage: btree_pager_ref_dump ID
592**
593** Print out all outstanding pages.
594*/
595static int btree_pager_ref_dump(
596 void *NotUsed,
597 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
598 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000599 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000600){
601 Btree *pBt;
602
603 if( argc!=2 ){
604 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
605 " ID\"", 0);
606 return TCL_ERROR;
607 }
drhfe63d1c2004-09-08 20:13:04 +0000608 pBt = sqlite3TextToPtr(argv[1]);
danielk197793758c82005-01-21 08:13:14 +0000609#ifdef SQLITE_DEBUG
drhff0587c2007-08-29 17:43:19 +0000610 sqlite3BtreeEnter(pBt);
danielk19773b8a05f2007-03-19 17:44:26 +0000611 sqlite3PagerRefdump(sqlite3BtreePager(pBt));
drhff0587c2007-08-29 17:43:19 +0000612 sqlite3BtreeLeave(pBt);
danielk197793758c82005-01-21 08:13:14 +0000613#endif
drh5c4d9702001-08-20 00:33:58 +0000614 return TCL_OK;
615}
616
617/*
drhaaab5722002-02-19 13:39:21 +0000618** Usage: btree_integrity_check ID ROOT ...
drh5c4d9702001-08-20 00:33:58 +0000619**
620** Look through every page of the given BTree file to verify correct
621** formatting and linkage. Return a line of text for each problem found.
622** Return an empty string if everything worked.
623*/
drhaaab5722002-02-19 13:39:21 +0000624static int btree_integrity_check(
drh5c4d9702001-08-20 00:33:58 +0000625 void *NotUsed,
626 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
627 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000628 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000629){
630 Btree *pBt;
drh5c4d9702001-08-20 00:33:58 +0000631 int nRoot;
632 int *aRoot;
633 int i;
drh1dcdbc02007-01-27 02:24:54 +0000634 int nErr;
drh40e016e2004-11-04 14:47:11 +0000635 char *zResult;
drh5c4d9702001-08-20 00:33:58 +0000636
637 if( argc<3 ){
638 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
639 " ID ROOT ...\"", 0);
640 return TCL_ERROR;
641 }
drhfe63d1c2004-09-08 20:13:04 +0000642 pBt = sqlite3TextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000643 nRoot = argc-2;
drh17435752007-08-16 04:30:38 +0000644 aRoot = (int*)sqlite3_malloc( sizeof(int)*(argc-2) );
drh5c4d9702001-08-20 00:33:58 +0000645 for(i=0; i<argc-2; i++){
646 if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
647 }
drhb7f91642004-10-31 02:22:47 +0000648#ifndef SQLITE_OMIT_INTEGRITY_CHECK
drhff0587c2007-08-29 17:43:19 +0000649 sqlite3BtreeEnter(pBt);
drh1dcdbc02007-01-27 02:24:54 +0000650 zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
drhff0587c2007-08-29 17:43:19 +0000651 sqlite3BtreeLeave(pBt);
drhb7f91642004-10-31 02:22:47 +0000652#else
drh40e016e2004-11-04 14:47:11 +0000653 zResult = 0;
drhb7f91642004-10-31 02:22:47 +0000654#endif
drh17435752007-08-16 04:30:38 +0000655 sqlite3_free((void*)aRoot);
drh5c4d9702001-08-20 00:33:58 +0000656 if( zResult ){
657 Tcl_AppendResult(interp, zResult, 0);
danielk19771e536952007-08-16 10:09:01 +0000658 sqlite3_free(zResult);
drh5c4d9702001-08-20 00:33:58 +0000659 }
660 return TCL_OK;
661}
662
663/*
drhc8629a12004-05-08 20:07:40 +0000664** Usage: btree_cursor_list ID
665**
666** Print information about all cursors to standard output for debugging.
667*/
668static int btree_cursor_list(
669 void *NotUsed,
670 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
671 int argc, /* Number of arguments */
672 const char **argv /* Text of each argument */
673){
674 Btree *pBt;
675
676 if( argc!=2 ){
677 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
678 " ID\"", 0);
679 return TCL_ERROR;
680 }
drhfe63d1c2004-09-08 20:13:04 +0000681 pBt = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000682 sqlite3BtreeEnter(pBt);
drhc8629a12004-05-08 20:07:40 +0000683 sqlite3BtreeCursorList(pBt);
drhff0587c2007-08-29 17:43:19 +0000684 sqlite3BtreeLeave(pBt);
drhc8629a12004-05-08 20:07:40 +0000685 return SQLITE_OK;
686}
687
688/*
drhecdc7532001-09-23 02:35:53 +0000689** Usage: btree_cursor ID TABLENUM WRITEABLE
drh5c4d9702001-08-20 00:33:58 +0000690**
691** Create a new cursor. Return the ID for the cursor.
692*/
693static int btree_cursor(
694 void *NotUsed,
695 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
696 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000697 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000698){
699 Btree *pBt;
700 int iTable;
701 BtCursor *pCur;
702 int rc;
drhecdc7532001-09-23 02:35:53 +0000703 int wrFlag;
drh5c4d9702001-08-20 00:33:58 +0000704 char zBuf[30];
705
drhecdc7532001-09-23 02:35:53 +0000706 if( argc!=4 ){
drh5c4d9702001-08-20 00:33:58 +0000707 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drhecdc7532001-09-23 02:35:53 +0000708 " ID TABLENUM WRITEABLE\"", 0);
drh5c4d9702001-08-20 00:33:58 +0000709 return TCL_ERROR;
710 }
drhfe63d1c2004-09-08 20:13:04 +0000711 pBt = sqlite3TextToPtr(argv[1]);
drh5c4d9702001-08-20 00:33:58 +0000712 if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR;
drhecdc7532001-09-23 02:35:53 +0000713 if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR;
drhff0587c2007-08-29 17:43:19 +0000714 sqlite3BtreeEnter(pBt);
drha34b6762004-05-07 13:30:42 +0000715 rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, 0, &pCur);
drhff0587c2007-08-29 17:43:19 +0000716 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000717 if( rc ){
718 Tcl_AppendResult(interp, errorName(rc), 0);
719 return TCL_ERROR;
720 }
drhfe63d1c2004-09-08 20:13:04 +0000721 sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur);
drh5c4d9702001-08-20 00:33:58 +0000722 Tcl_AppendResult(interp, zBuf, 0);
723 return SQLITE_OK;
724}
725
726/*
727** Usage: btree_close_cursor ID
728**
729** Close a cursor opened using btree_cursor.
730*/
731static int btree_close_cursor(
732 void *NotUsed,
733 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
734 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000735 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000736){
737 BtCursor *pCur;
drhff0587c2007-08-29 17:43:19 +0000738 Btree *pBt;
drh5c4d9702001-08-20 00:33:58 +0000739 int rc;
740
741 if( argc!=2 ){
742 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
743 " ID\"", 0);
744 return TCL_ERROR;
745 }
drhfe63d1c2004-09-08 20:13:04 +0000746 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000747 pBt = pCur->pBtree;
748 sqlite3BtreeEnter(pBt);
drh23e11ca2004-05-04 17:27:28 +0000749 rc = sqlite3BtreeCloseCursor(pCur);
drhff0587c2007-08-29 17:43:19 +0000750 sqlite3BtreeLeave(pBt);
drh5c4d9702001-08-20 00:33:58 +0000751 if( rc ){
752 Tcl_AppendResult(interp, errorName(rc), 0);
753 return TCL_ERROR;
754 }
755 return SQLITE_OK;
756}
757
758/*
759** Usage: btree_move_to ID KEY
760**
761** Move the cursor to the entry with the given key.
762*/
763static int btree_move_to(
764 void *NotUsed,
765 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
766 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000767 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000768){
769 BtCursor *pCur;
770 int rc;
771 int res;
772 char zBuf[20];
773
774 if( argc!=3 ){
775 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
776 " ID KEY\"", 0);
777 return TCL_ERROR;
778 }
drhfe63d1c2004-09-08 20:13:04 +0000779 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000780 sqlite3BtreeEnter(pCur->pBtree);
drhde647132004-05-07 17:57:49 +0000781 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
782 int iKey;
drhff0587c2007-08-29 17:43:19 +0000783 if( Tcl_GetInt(interp, argv[2], &iKey) ){
784 sqlite3BtreeLeave(pCur->pBtree);
785 return TCL_ERROR;
786 }
drhe4d90812007-03-29 05:51:49 +0000787 rc = sqlite3BtreeMoveto(pCur, 0, iKey, 0, &res);
drhde647132004-05-07 17:57:49 +0000788 }else{
drhe4d90812007-03-29 05:51:49 +0000789 rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res);
drhde647132004-05-07 17:57:49 +0000790 }
drhff0587c2007-08-29 17:43:19 +0000791 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000792 if( rc ){
793 Tcl_AppendResult(interp, errorName(rc), 0);
794 return TCL_ERROR;
795 }
drhce927062001-11-09 13:41:09 +0000796 if( res<0 ) res = -1;
797 if( res>0 ) res = 1;
drhfe63d1c2004-09-08 20:13:04 +0000798 sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",res);
drh5c4d9702001-08-20 00:33:58 +0000799 Tcl_AppendResult(interp, zBuf, 0);
800 return SQLITE_OK;
801}
802
803/*
804** Usage: btree_delete ID
805**
806** Delete the entry that the cursor is pointing to
807*/
808static int btree_delete(
809 void *NotUsed,
810 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
811 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000812 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000813){
814 BtCursor *pCur;
815 int rc;
816
817 if( argc!=2 ){
818 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
819 " ID\"", 0);
820 return TCL_ERROR;
821 }
drhfe63d1c2004-09-08 20:13:04 +0000822 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000823 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000824 rc = sqlite3BtreeDelete(pCur);
drhff0587c2007-08-29 17:43:19 +0000825 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000826 if( rc ){
827 Tcl_AppendResult(interp, errorName(rc), 0);
828 return TCL_ERROR;
829 }
830 return SQLITE_OK;
831}
832
833/*
drhb026e052007-05-02 01:34:31 +0000834** Usage: btree_insert ID KEY DATA ?NZERO?
drh5c4d9702001-08-20 00:33:58 +0000835**
836** Create a new entry with the given key and data. If an entry already
837** exists with the same key the old entry is overwritten.
838*/
839static int btree_insert(
danielk1977312d6b32004-06-29 13:18:23 +0000840 void * clientData,
841 Tcl_Interp *interp,
842 int objc,
843 Tcl_Obj *CONST objv[]
drh5c4d9702001-08-20 00:33:58 +0000844){
845 BtCursor *pCur;
846 int rc;
drhb026e052007-05-02 01:34:31 +0000847 int nZero;
drh5c4d9702001-08-20 00:33:58 +0000848
drhb026e052007-05-02 01:34:31 +0000849 if( objc!=4 && objc!=5 ){
850 Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA ?NZERO?");
drh5c4d9702001-08-20 00:33:58 +0000851 return TCL_ERROR;
852 }
drhfe63d1c2004-09-08 20:13:04 +0000853 pCur = sqlite3TextToPtr(Tcl_GetString(objv[1]));
drhb026e052007-05-02 01:34:31 +0000854 if( objc==5 ){
855 if( Tcl_GetIntFromObj(interp, objv[4], &nZero) ) return TCL_ERROR;
856 }else{
857 nZero = 0;
858 }
drhff0587c2007-08-29 17:43:19 +0000859 sqlite3BtreeEnter(pCur->pBtree);
danielk1977312d6b32004-06-29 13:18:23 +0000860 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
861 i64 iKey;
862 int len;
863 unsigned char *pBuf;
drhff0587c2007-08-29 17:43:19 +0000864 if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ){
865 sqlite3BtreeLeave(pCur->pBtree);
866 return TCL_ERROR;
867 }
danielk1977312d6b32004-06-29 13:18:23 +0000868 pBuf = Tcl_GetByteArrayFromObj(objv[3], &len);
drhb026e052007-05-02 01:34:31 +0000869 rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0);
drhde647132004-05-07 17:57:49 +0000870 }else{
danielk1977312d6b32004-06-29 13:18:23 +0000871 int keylen;
872 int dlen;
873 unsigned char *pKBuf;
874 unsigned char *pDBuf;
875 pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen);
876 pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen);
drhb026e052007-05-02 01:34:31 +0000877 rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, nZero, 0);
drhde647132004-05-07 17:57:49 +0000878 }
drhff0587c2007-08-29 17:43:19 +0000879 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000880 if( rc ){
881 Tcl_AppendResult(interp, errorName(rc), 0);
882 return TCL_ERROR;
883 }
884 return SQLITE_OK;
885}
886
887/*
888** Usage: btree_next ID
889**
drh2dcc9aa2002-12-04 13:40:25 +0000890** Move the cursor to the next entry in the table. Return 0 on success
891** or 1 if the cursor was already on the last entry in the table or if
892** the table is empty.
drh5c4d9702001-08-20 00:33:58 +0000893*/
894static int btree_next(
895 void *NotUsed,
896 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
897 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000898 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +0000899){
900 BtCursor *pCur;
901 int rc;
drh0de8c112002-07-06 16:32:14 +0000902 int res = 0;
903 char zBuf[100];
drh5c4d9702001-08-20 00:33:58 +0000904
905 if( argc!=2 ){
906 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
907 " ID\"", 0);
908 return TCL_ERROR;
909 }
drhfe63d1c2004-09-08 20:13:04 +0000910 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000911 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000912 rc = sqlite3BtreeNext(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000913 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +0000914 if( rc ){
915 Tcl_AppendResult(interp, errorName(rc), 0);
916 return TCL_ERROR;
917 }
drhfe63d1c2004-09-08 20:13:04 +0000918 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000919 Tcl_AppendResult(interp, zBuf, 0);
920 return SQLITE_OK;
921}
922
923/*
drh2dcc9aa2002-12-04 13:40:25 +0000924** Usage: btree_prev ID
925**
926** Move the cursor to the previous entry in the table. Return 0 on
927** success and 1 if the cursor was already on the first entry in
928** the table or if the table was empty.
929*/
930static int btree_prev(
931 void *NotUsed,
932 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
933 int argc, /* Number of arguments */
934 const char **argv /* Text of each argument */
935){
936 BtCursor *pCur;
937 int rc;
938 int res = 0;
939 char zBuf[100];
940
941 if( argc!=2 ){
942 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
943 " ID\"", 0);
944 return TCL_ERROR;
945 }
drhfe63d1c2004-09-08 20:13:04 +0000946 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000947 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000948 rc = sqlite3BtreePrevious(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000949 sqlite3BtreeLeave(pCur->pBtree);
drh2dcc9aa2002-12-04 13:40:25 +0000950 if( rc ){
951 Tcl_AppendResult(interp, errorName(rc), 0);
952 return TCL_ERROR;
953 }
drhfe63d1c2004-09-08 20:13:04 +0000954 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh2dcc9aa2002-12-04 13:40:25 +0000955 Tcl_AppendResult(interp, zBuf, 0);
956 return SQLITE_OK;
957}
958
959/*
drh0de8c112002-07-06 16:32:14 +0000960** Usage: btree_first ID
961**
drh2dcc9aa2002-12-04 13:40:25 +0000962** Move the cursor to the first entry in the table. Return 0 if the
963** cursor was left point to something and 1 if the table is empty.
drh0de8c112002-07-06 16:32:14 +0000964*/
965static int btree_first(
966 void *NotUsed,
967 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
968 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +0000969 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +0000970){
971 BtCursor *pCur;
972 int rc;
973 int res = 0;
974 char zBuf[100];
975
976 if( argc!=2 ){
977 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
978 " ID\"", 0);
979 return TCL_ERROR;
980 }
drhfe63d1c2004-09-08 20:13:04 +0000981 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +0000982 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +0000983 rc = sqlite3BtreeFirst(pCur, &res);
drhff0587c2007-08-29 17:43:19 +0000984 sqlite3BtreeLeave(pCur->pBtree);
drh0de8c112002-07-06 16:32:14 +0000985 if( rc ){
986 Tcl_AppendResult(interp, errorName(rc), 0);
987 return TCL_ERROR;
988 }
drhfe63d1c2004-09-08 20:13:04 +0000989 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh0de8c112002-07-06 16:32:14 +0000990 Tcl_AppendResult(interp, zBuf, 0);
drh5c4d9702001-08-20 00:33:58 +0000991 return SQLITE_OK;
992}
993
994/*
drh2dcc9aa2002-12-04 13:40:25 +0000995** Usage: btree_last ID
996**
997** Move the cursor to the last entry in the table. Return 0 if the
998** cursor was left point to something and 1 if the table is empty.
999*/
1000static int btree_last(
1001 void *NotUsed,
1002 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1003 int argc, /* Number of arguments */
1004 const char **argv /* Text of each argument */
1005){
1006 BtCursor *pCur;
1007 int rc;
1008 int res = 0;
1009 char zBuf[100];
1010
1011 if( argc!=2 ){
1012 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1013 " ID\"", 0);
1014 return TCL_ERROR;
1015 }
drhfe63d1c2004-09-08 20:13:04 +00001016 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +00001017 sqlite3BtreeEnter(pCur->pBtree);
drh4fc0fb42004-05-07 02:26:28 +00001018 rc = sqlite3BtreeLast(pCur, &res);
drhff0587c2007-08-29 17:43:19 +00001019 sqlite3BtreeLeave(pCur->pBtree);
drh2dcc9aa2002-12-04 13:40:25 +00001020 if( rc ){
1021 Tcl_AppendResult(interp, errorName(rc), 0);
1022 return TCL_ERROR;
1023 }
drhfe63d1c2004-09-08 20:13:04 +00001024 sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res);
drh2dcc9aa2002-12-04 13:40:25 +00001025 Tcl_AppendResult(interp, zBuf, 0);
1026 return SQLITE_OK;
1027}
1028
1029/*
drhc39e0002004-05-07 23:50:57 +00001030** Usage: btree_eof ID
1031**
1032** Return TRUE if the given cursor is not pointing at a valid entry.
1033** Return FALSE if the cursor does point to a valid entry.
1034*/
1035static int btree_eof(
1036 void *NotUsed,
1037 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1038 int argc, /* Number of arguments */
1039 const char **argv /* Text of each argument */
1040){
1041 BtCursor *pCur;
drhff0587c2007-08-29 17:43:19 +00001042 int rc;
drhc39e0002004-05-07 23:50:57 +00001043 char zBuf[50];
1044
1045 if( argc!=2 ){
1046 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1047 " ID\"", 0);
1048 return TCL_ERROR;
1049 }
drhfe63d1c2004-09-08 20:13:04 +00001050 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +00001051 sqlite3BtreeEnter(pCur->pBtree);
1052 rc = sqlite3BtreeEof(pCur);
1053 sqlite3BtreeLeave(pCur->pBtree);
1054 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc);
drhc39e0002004-05-07 23:50:57 +00001055 Tcl_AppendResult(interp, zBuf, 0);
1056 return SQLITE_OK;
1057}
1058
1059/*
drh4fc0fb42004-05-07 02:26:28 +00001060** Usage: btree_keysize ID
1061**
drh0e1c19e2004-05-11 00:58:56 +00001062** Return the number of bytes of key. For an INTKEY table, this
1063** returns the key itself.
drh4fc0fb42004-05-07 02:26:28 +00001064*/
1065static int btree_keysize(
1066 void *NotUsed,
1067 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1068 int argc, /* Number of arguments */
1069 const char **argv /* Text of each argument */
1070){
1071 BtCursor *pCur;
drha34b6762004-05-07 13:30:42 +00001072 u64 n;
drh4fc0fb42004-05-07 02:26:28 +00001073 char zBuf[50];
1074
1075 if( argc!=2 ){
1076 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1077 " ID\"", 0);
1078 return TCL_ERROR;
1079 }
drhfe63d1c2004-09-08 20:13:04 +00001080 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +00001081 sqlite3BtreeEnter(pCur->pBtree);
drh03d847e2005-12-09 20:21:58 +00001082 sqlite3BtreeKeySize(pCur, (i64*)&n);
drhff0587c2007-08-29 17:43:19 +00001083 sqlite3BtreeLeave(pCur->pBtree);
drhfe63d1c2004-09-08 20:13:04 +00001084 sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n);
drh4fc0fb42004-05-07 02:26:28 +00001085 Tcl_AppendResult(interp, zBuf, 0);
1086 return SQLITE_OK;
1087}
1088
1089/*
drh5c4d9702001-08-20 00:33:58 +00001090** Usage: btree_key ID
1091**
1092** Return the key for the entry at which the cursor is pointing.
1093*/
1094static int btree_key(
1095 void *NotUsed,
1096 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1097 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +00001098 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +00001099){
1100 BtCursor *pCur;
1101 int rc;
drh4fc0fb42004-05-07 02:26:28 +00001102 u64 n;
drh5c4d9702001-08-20 00:33:58 +00001103 char *zBuf;
1104
1105 if( argc!=2 ){
1106 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1107 " ID\"", 0);
1108 return TCL_ERROR;
1109 }
drhfe63d1c2004-09-08 20:13:04 +00001110 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +00001111 sqlite3BtreeEnter(pCur->pBtree);
drh03d847e2005-12-09 20:21:58 +00001112 sqlite3BtreeKeySize(pCur, (i64*)&n);
drha34b6762004-05-07 13:30:42 +00001113 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
1114 char zBuf2[60];
drhf7a83622004-09-17 19:39:23 +00001115 sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n);
drha34b6762004-05-07 13:30:42 +00001116 Tcl_AppendResult(interp, zBuf2, 0);
1117 }else{
drh17435752007-08-16 04:30:38 +00001118 zBuf = sqlite3_malloc( n+1 );
drha34b6762004-05-07 13:30:42 +00001119 rc = sqlite3BtreeKey(pCur, 0, n, zBuf);
drhde647132004-05-07 17:57:49 +00001120 if( rc ){
drhff0587c2007-08-29 17:43:19 +00001121 sqlite3BtreeLeave(pCur->pBtree);
drhde647132004-05-07 17:57:49 +00001122 Tcl_AppendResult(interp, errorName(rc), 0);
drha34b6762004-05-07 13:30:42 +00001123 return TCL_ERROR;
1124 }
1125 zBuf[n] = 0;
1126 Tcl_AppendResult(interp, zBuf, 0);
drh17435752007-08-16 04:30:38 +00001127 sqlite3_free(zBuf);
drh5c4d9702001-08-20 00:33:58 +00001128 }
drhff0587c2007-08-29 17:43:19 +00001129 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +00001130 return SQLITE_OK;
1131}
1132
1133/*
danielk19777701e812005-01-10 12:59:51 +00001134** Usage: btree_data ID ?N?
drh5c4d9702001-08-20 00:33:58 +00001135**
1136** Return the data for the entry at which the cursor is pointing.
1137*/
1138static int btree_data(
1139 void *NotUsed,
1140 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1141 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +00001142 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +00001143){
1144 BtCursor *pCur;
1145 int rc;
drha34b6762004-05-07 13:30:42 +00001146 u32 n;
drh5c4d9702001-08-20 00:33:58 +00001147 char *zBuf;
1148
danielk19777701e812005-01-10 12:59:51 +00001149 if( argc!=2 && argc!=3 ){
drh5c4d9702001-08-20 00:33:58 +00001150 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1151 " ID\"", 0);
1152 return TCL_ERROR;
1153 }
drhfe63d1c2004-09-08 20:13:04 +00001154 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +00001155 sqlite3BtreeEnter(pCur->pBtree);
danielk19777701e812005-01-10 12:59:51 +00001156 if( argc==2 ){
1157 sqlite3BtreeDataSize(pCur, &n);
1158 }else{
1159 n = atoi(argv[2]);
1160 }
drh17435752007-08-16 04:30:38 +00001161 zBuf = sqlite3_malloc( n+1 );
drh4fc0fb42004-05-07 02:26:28 +00001162 rc = sqlite3BtreeData(pCur, 0, n, zBuf);
drhff0587c2007-08-29 17:43:19 +00001163 sqlite3BtreeLeave(pCur->pBtree);
drhde647132004-05-07 17:57:49 +00001164 if( rc ){
1165 Tcl_AppendResult(interp, errorName(rc), 0);
danielk197731dad9d2007-08-16 11:36:15 +00001166 sqlite3_free(zBuf);
drh5c4d9702001-08-20 00:33:58 +00001167 return TCL_ERROR;
1168 }
1169 zBuf[n] = 0;
1170 Tcl_AppendResult(interp, zBuf, 0);
drh17435752007-08-16 04:30:38 +00001171 sqlite3_free(zBuf);
drh5c4d9702001-08-20 00:33:58 +00001172 return SQLITE_OK;
1173}
1174
1175/*
drh0e1c19e2004-05-11 00:58:56 +00001176** Usage: btree_fetch_key ID AMT
1177**
1178** Use the sqlite3BtreeKeyFetch() routine to get AMT bytes of the key.
1179** If sqlite3BtreeKeyFetch() fails, return an empty string.
1180*/
1181static int btree_fetch_key(
1182 void *NotUsed,
1183 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1184 int argc, /* Number of arguments */
1185 const char **argv /* Text of each argument */
1186){
1187 BtCursor *pCur;
1188 int n;
drhe51c44f2004-05-30 20:46:09 +00001189 int amt;
drh0e1c19e2004-05-11 00:58:56 +00001190 u64 nKey;
1191 const char *zBuf;
1192 char zStatic[1000];
1193
1194 if( argc!=3 ){
1195 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1196 " ID AMT\"", 0);
1197 return TCL_ERROR;
1198 }
drhfe63d1c2004-09-08 20:13:04 +00001199 pCur = sqlite3TextToPtr(argv[1]);
drh0e1c19e2004-05-11 00:58:56 +00001200 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
drhff0587c2007-08-29 17:43:19 +00001201 sqlite3BtreeEnter(pCur->pBtree);
drh03d847e2005-12-09 20:21:58 +00001202 sqlite3BtreeKeySize(pCur, (i64*)&nKey);
drhe51c44f2004-05-30 20:46:09 +00001203 zBuf = sqlite3BtreeKeyFetch(pCur, &amt);
1204 if( zBuf && amt>=n ){
drh0e1c19e2004-05-11 00:58:56 +00001205 assert( nKey<sizeof(zStatic) );
1206 if( n>0 ) nKey = n;
1207 memcpy(zStatic, zBuf, (int)nKey);
1208 zStatic[nKey] = 0;
1209 Tcl_AppendResult(interp, zStatic, 0);
1210 }
drhff0587c2007-08-29 17:43:19 +00001211 sqlite3BtreeLeave(pCur->pBtree);
drh0e1c19e2004-05-11 00:58:56 +00001212 return TCL_OK;
1213}
1214
1215/*
1216** Usage: btree_fetch_data ID AMT
1217**
1218** Use the sqlite3BtreeDataFetch() routine to get AMT bytes of the key.
1219** If sqlite3BtreeDataFetch() fails, return an empty string.
1220*/
1221static int btree_fetch_data(
1222 void *NotUsed,
1223 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1224 int argc, /* Number of arguments */
1225 const char **argv /* Text of each argument */
1226){
1227 BtCursor *pCur;
1228 int n;
drhe51c44f2004-05-30 20:46:09 +00001229 int amt;
drh0e1c19e2004-05-11 00:58:56 +00001230 u32 nData;
1231 const char *zBuf;
1232 char zStatic[1000];
1233
1234 if( argc!=3 ){
1235 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drhe51c44f2004-05-30 20:46:09 +00001236 " ID AMT\"", 0);
drh0e1c19e2004-05-11 00:58:56 +00001237 return TCL_ERROR;
1238 }
drhfe63d1c2004-09-08 20:13:04 +00001239 pCur = sqlite3TextToPtr(argv[1]);
drh0e1c19e2004-05-11 00:58:56 +00001240 if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR;
drhff0587c2007-08-29 17:43:19 +00001241 sqlite3BtreeEnter(pCur->pBtree);
drh0e1c19e2004-05-11 00:58:56 +00001242 sqlite3BtreeDataSize(pCur, &nData);
drhe51c44f2004-05-30 20:46:09 +00001243 zBuf = sqlite3BtreeDataFetch(pCur, &amt);
1244 if( zBuf && amt>=n ){
drh0e1c19e2004-05-11 00:58:56 +00001245 assert( nData<sizeof(zStatic) );
1246 if( n>0 ) nData = n;
1247 memcpy(zStatic, zBuf, (int)nData);
1248 zStatic[nData] = 0;
1249 Tcl_AppendResult(interp, zStatic, 0);
1250 }
drhff0587c2007-08-29 17:43:19 +00001251 sqlite3BtreeLeave(pCur->pBtree);
drh0e1c19e2004-05-11 00:58:56 +00001252 return TCL_OK;
1253}
1254
1255/*
drh0de8c112002-07-06 16:32:14 +00001256** Usage: btree_payload_size ID
1257**
1258** Return the number of bytes of payload
1259*/
1260static int btree_payload_size(
1261 void *NotUsed,
1262 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1263 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +00001264 const char **argv /* Text of each argument */
drh0de8c112002-07-06 16:32:14 +00001265){
1266 BtCursor *pCur;
drh4fc0fb42004-05-07 02:26:28 +00001267 int n2;
drha34b6762004-05-07 13:30:42 +00001268 u64 n1;
drh0de8c112002-07-06 16:32:14 +00001269 char zBuf[50];
1270
1271 if( argc!=2 ){
1272 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1273 " ID\"", 0);
1274 return TCL_ERROR;
1275 }
drhfe63d1c2004-09-08 20:13:04 +00001276 pCur = sqlite3TextToPtr(argv[1]);
drhff0587c2007-08-29 17:43:19 +00001277 sqlite3BtreeEnter(pCur->pBtree);
drha34b6762004-05-07 13:30:42 +00001278 if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
1279 n1 = 0;
1280 }else{
drh03d847e2005-12-09 20:21:58 +00001281 sqlite3BtreeKeySize(pCur, (i64*)&n1);
drha34b6762004-05-07 13:30:42 +00001282 }
drh03d847e2005-12-09 20:21:58 +00001283 sqlite3BtreeDataSize(pCur, (u32*)&n2);
drhff0587c2007-08-29 17:43:19 +00001284 sqlite3BtreeLeave(pCur->pBtree);
drhfe63d1c2004-09-08 20:13:04 +00001285 sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2));
drh0de8c112002-07-06 16:32:14 +00001286 Tcl_AppendResult(interp, zBuf, 0);
drh0de8c112002-07-06 16:32:14 +00001287 return SQLITE_OK;
1288}
1289
1290/*
drh3e27c022004-07-23 00:01:38 +00001291** Usage: btree_cursor_info ID ?UP-CNT?
drh5c4d9702001-08-20 00:33:58 +00001292**
drh3e27c022004-07-23 00:01:38 +00001293** Return integers containing information about the entry the
drh5c4d9702001-08-20 00:33:58 +00001294** cursor is pointing to:
1295**
1296** aResult[0] = The page number
1297** aResult[1] = The entry number
1298** aResult[2] = Total number of entries on this page
drh3e27c022004-07-23 00:01:38 +00001299** aResult[3] = Cell size (local payload + header)
drh5c4d9702001-08-20 00:33:58 +00001300** aResult[4] = Number of free bytes on this page
1301** aResult[5] = Number of free blocks on the page
drh3e27c022004-07-23 00:01:38 +00001302** aResult[6] = Total payload size (local + overflow)
1303** aResult[7] = Header size in bytes
1304** aResult[8] = Local payload size
1305** aResult[9] = Parent page number
drh50c67062007-02-10 19:22:35 +00001306** aResult[10]= Page number of the first overflow page
drh5c4d9702001-08-20 00:33:58 +00001307*/
drhc12fc0d2004-05-09 00:40:52 +00001308static int btree_cursor_info(
drh5c4d9702001-08-20 00:33:58 +00001309 void *NotUsed,
1310 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1311 int argc, /* Number of arguments */
drhc2eef3b2002-08-31 18:53:06 +00001312 const char **argv /* Text of each argument */
drh5c4d9702001-08-20 00:33:58 +00001313){
1314 BtCursor *pCur;
1315 int rc;
1316 int i, j;
drh3e27c022004-07-23 00:01:38 +00001317 int up;
drh50c67062007-02-10 19:22:35 +00001318 int aResult[11];
drh5c4d9702001-08-20 00:33:58 +00001319 char zBuf[400];
1320
drh3e27c022004-07-23 00:01:38 +00001321 if( argc!=2 && argc!=3 ){
drh5c4d9702001-08-20 00:33:58 +00001322 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
drh3e27c022004-07-23 00:01:38 +00001323 " ID ?UP-CNT?\"", 0);
drh5c4d9702001-08-20 00:33:58 +00001324 return TCL_ERROR;
1325 }
drhfe63d1c2004-09-08 20:13:04 +00001326 pCur = sqlite3TextToPtr(argv[1]);
drh3e27c022004-07-23 00:01:38 +00001327 if( argc==3 ){
1328 if( Tcl_GetInt(interp, argv[2], &up) ) return TCL_ERROR;
1329 }else{
1330 up = 0;
1331 }
drhff0587c2007-08-29 17:43:19 +00001332 sqlite3BtreeEnter(pCur->pBtree);
drh3e27c022004-07-23 00:01:38 +00001333 rc = sqlite3BtreeCursorInfo(pCur, aResult, up);
drh5c4d9702001-08-20 00:33:58 +00001334 if( rc ){
1335 Tcl_AppendResult(interp, errorName(rc), 0);
drhff0587c2007-08-29 17:43:19 +00001336 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +00001337 return TCL_ERROR;
1338 }
1339 j = 0;
1340 for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){
drhfe63d1c2004-09-08 20:13:04 +00001341 sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]);
drh5c4d9702001-08-20 00:33:58 +00001342 j += strlen(&zBuf[j]);
1343 }
drhff0587c2007-08-29 17:43:19 +00001344 sqlite3BtreeLeave(pCur->pBtree);
drh5c4d9702001-08-20 00:33:58 +00001345 Tcl_AppendResult(interp, &zBuf[1], 0);
1346 return SQLITE_OK;
1347}
1348
1349/*
drh50c67062007-02-10 19:22:35 +00001350** Copied from btree.c:
1351*/
drh4f0c5872007-03-26 22:05:01 +00001352static u32 t4Get4byte(unsigned char *p){
drh50c67062007-02-10 19:22:35 +00001353 return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
1354}
1355
1356/*
1357** btree_ovfl_info BTREE CURSOR
1358**
1359** Given a cursor, return the sequence of pages number that form the
1360** overflow pages for the data of the entry that the cursor is point
1361** to.
1362*/
1363static int btree_ovfl_info(
1364 void *NotUsed,
1365 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1366 int argc, /* Number of arguments */
1367 const char **argv /* Text of each argument */
1368){
1369 Btree *pBt;
1370 BtCursor *pCur;
1371 Pager *pPager;
1372 int rc;
1373 int n;
1374 int dataSize;
1375 u32 pgno;
1376 void *pPage;
1377 int aResult[11];
1378 char zElem[100];
1379 Tcl_DString str;
1380
1381 if( argc!=3 ){
1382 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1383 " BTREE CURSOR", 0);
1384 return TCL_ERROR;
1385 }
1386 pBt = sqlite3TextToPtr(argv[1]);
1387 pCur = sqlite3TextToPtr(argv[2]);
1388 if( (*(void**)pCur) != (void*)pBt ){
1389 Tcl_AppendResult(interp, "Cursor ", argv[2], " does not belong to btree ",
1390 argv[1], 0);
1391 return TCL_ERROR;
1392 }
drhff0587c2007-08-29 17:43:19 +00001393 sqlite3BtreeEnter(pBt);
drh50c67062007-02-10 19:22:35 +00001394 pPager = sqlite3BtreePager(pBt);
1395 rc = sqlite3BtreeCursorInfo(pCur, aResult, 0);
1396 if( rc ){
1397 Tcl_AppendResult(interp, errorName(rc), 0);
drhff0587c2007-08-29 17:43:19 +00001398 sqlite3BtreeLeave(pBt);
drh50c67062007-02-10 19:22:35 +00001399 return TCL_ERROR;
1400 }
danielk19774152e672007-09-12 17:01:45 +00001401 dataSize = pBt->pBt->usableSize;
drh50c67062007-02-10 19:22:35 +00001402 Tcl_DStringInit(&str);
1403 n = aResult[6] - aResult[8];
1404 n = (n + dataSize - 1)/dataSize;
1405 pgno = (u32)aResult[10];
1406 while( pgno && n-- ){
danielk19773b8a05f2007-03-19 17:44:26 +00001407 DbPage *pDbPage;
drh50c67062007-02-10 19:22:35 +00001408 sprintf(zElem, "%d", pgno);
1409 Tcl_DStringAppendElement(&str, zElem);
danielk19773b8a05f2007-03-19 17:44:26 +00001410 if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){
drh50c67062007-02-10 19:22:35 +00001411 Tcl_DStringFree(&str);
1412 Tcl_AppendResult(interp, "unable to get page ", zElem, 0);
drhff0587c2007-08-29 17:43:19 +00001413 sqlite3BtreeLeave(pBt);
drh50c67062007-02-10 19:22:35 +00001414 return TCL_ERROR;
1415 }
danielk19773b8a05f2007-03-19 17:44:26 +00001416 pPage = sqlite3PagerGetData(pDbPage);
drh4f0c5872007-03-26 22:05:01 +00001417 pgno = t4Get4byte((unsigned char*)pPage);
danielk19773b8a05f2007-03-19 17:44:26 +00001418 sqlite3PagerUnref(pDbPage);
drh50c67062007-02-10 19:22:35 +00001419 }
drhff0587c2007-08-29 17:43:19 +00001420 sqlite3BtreeLeave(pBt);
drh50c67062007-02-10 19:22:35 +00001421 Tcl_DStringResult(interp, &str);
1422 return SQLITE_OK;
1423}
1424
1425/*
drh9b171272004-05-08 02:03:22 +00001426** The command is provided for the purpose of setting breakpoints.
1427** in regression test scripts.
1428**
1429** By setting a GDB breakpoint on this procedure and executing the
1430** btree_breakpoint command in a test script, we can stop GDB at
1431** the point in the script where the btree_breakpoint command is
1432** inserted. This is useful for debugging.
1433*/
1434static int btree_breakpoint(
1435 void *NotUsed,
1436 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1437 int argc, /* Number of arguments */
1438 const char **argv /* Text of each argument */
1439){
1440 return TCL_OK;
1441}
1442
drh6d2fb152004-05-14 16:50:06 +00001443/*
1444** usage: varint_test START MULTIPLIER COUNT INCREMENT
1445**
1446** This command tests the sqlite3PutVarint() and sqlite3GetVarint()
1447** routines, both for accuracy and for speed.
1448**
1449** An integer is written using PutVarint() and read back with
1450** GetVarint() and varified to be unchanged. This repeats COUNT
1451** times. The first integer is START*MULTIPLIER. Each iteration
1452** increases the integer by INCREMENT.
1453**
1454** This command returns nothing if it works. It returns an error message
1455** if something goes wrong.
1456*/
1457static int btree_varint_test(
1458 void *NotUsed,
1459 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1460 int argc, /* Number of arguments */
1461 const char **argv /* Text of each argument */
1462){
1463 u32 start, mult, count, incr;
1464 u64 in, out;
drhd8820e82004-05-18 15:57:42 +00001465 int n1, n2, i, j;
drh6d2fb152004-05-14 16:50:06 +00001466 unsigned char zBuf[100];
1467 if( argc!=5 ){
1468 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1469 " START MULTIPLIER COUNT INCREMENT\"", 0);
1470 return TCL_ERROR;
1471 }
1472 if( Tcl_GetInt(interp, argv[1], (int*)&start) ) return TCL_ERROR;
1473 if( Tcl_GetInt(interp, argv[2], (int*)&mult) ) return TCL_ERROR;
1474 if( Tcl_GetInt(interp, argv[3], (int*)&count) ) return TCL_ERROR;
1475 if( Tcl_GetInt(interp, argv[4], (int*)&incr) ) return TCL_ERROR;
1476 in = start;
1477 in *= mult;
1478 for(i=0; i<count; i++){
drhd8820e82004-05-18 15:57:42 +00001479 char zErr[200];
drh6d2fb152004-05-14 16:50:06 +00001480 n1 = sqlite3PutVarint(zBuf, in);
1481 if( n1>9 || n1<1 ){
drhd8820e82004-05-18 15:57:42 +00001482 sprintf(zErr, "PutVarint returned %d - should be between 1 and 9", n1);
1483 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +00001484 return TCL_ERROR;
1485 }
1486 n2 = sqlite3GetVarint(zBuf, &out);
1487 if( n1!=n2 ){
drhd8820e82004-05-18 15:57:42 +00001488 sprintf(zErr, "PutVarint returned %d and GetVarint returned %d", n1, n2);
1489 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +00001490 return TCL_ERROR;
1491 }
1492 if( in!=out ){
drhd8820e82004-05-18 15:57:42 +00001493 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out);
1494 Tcl_AppendResult(interp, zErr, 0);
drh6d2fb152004-05-14 16:50:06 +00001495 return TCL_ERROR;
1496 }
drh9d213ef2004-06-30 04:02:11 +00001497 if( (in & 0xffffffff)==in ){
1498 u32 out32;
1499 n2 = sqlite3GetVarint32(zBuf, &out32);
1500 out = out32;
1501 if( n1!=n2 ){
1502 sprintf(zErr, "PutVarint returned %d and GetVarint32 returned %d",
1503 n1, n2);
1504 Tcl_AppendResult(interp, zErr, 0);
1505 return TCL_ERROR;
1506 }
1507 if( in!=out ){
1508 sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx from GetVarint32",
1509 in, out);
1510 Tcl_AppendResult(interp, zErr, 0);
1511 return TCL_ERROR;
1512 }
1513 }
drhd8820e82004-05-18 15:57:42 +00001514
1515 /* In order to get realistic timings, run getVarint 19 more times.
1516 ** This is because getVarint is called about 20 times more often
1517 ** than putVarint.
1518 */
1519 for(j=0; j<19; j++){
1520 sqlite3GetVarint(zBuf, &out);
1521 }
drh6d2fb152004-05-14 16:50:06 +00001522 in += incr;
1523 }
1524 return TCL_OK;
1525}
drh9b171272004-05-08 02:03:22 +00001526
1527/*
danielk197742741be2005-01-08 12:42:39 +00001528** usage: btree_from_db DB-HANDLE
1529**
1530** This command returns the btree handle for the main database associated
1531** with the database-handle passed as the argument. Example usage:
1532**
1533** sqlite3 db test.db
1534** set bt [btree_from_db db]
1535*/
1536static int btree_from_db(
1537 void *NotUsed,
1538 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1539 int argc, /* Number of arguments */
1540 const char **argv /* Text of each argument */
1541){
1542 char zBuf[100];
1543 Tcl_CmdInfo info;
1544 sqlite3 *db;
1545 Btree *pBt;
danielk197763c64f32007-05-17 14:45:12 +00001546 int iDb = 0;
danielk197742741be2005-01-08 12:42:39 +00001547
danielk197763c64f32007-05-17 14:45:12 +00001548 if( argc!=2 && argc!=3 ){
danielk197742741be2005-01-08 12:42:39 +00001549 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
danielk197763c64f32007-05-17 14:45:12 +00001550 " DB-HANDLE ?N?\"", 0);
danielk197742741be2005-01-08 12:42:39 +00001551 return TCL_ERROR;
1552 }
1553
1554 if( 1!=Tcl_GetCommandInfo(interp, argv[1], &info) ){
1555 Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0);
1556 return TCL_ERROR;
1557 }
danielk197763c64f32007-05-17 14:45:12 +00001558 if( argc==3 ){
1559 iDb = atoi(argv[2]);
1560 }
1561
danielk197742741be2005-01-08 12:42:39 +00001562 db = *((sqlite3 **)info.objClientData);
1563 assert( db );
1564
danielk197763c64f32007-05-17 14:45:12 +00001565 pBt = db->aDb[iDb].pBt;
danielk197742741be2005-01-08 12:42:39 +00001566 sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt);
1567 Tcl_SetResult(interp, zBuf, TCL_VOLATILE);
1568 return TCL_OK;
1569}
1570
danielk19771ad7f642005-01-20 05:24:32 +00001571
1572/*
1573** usage: btree_set_cache_size ID NCACHE
1574**
1575** Set the size of the cache used by btree $ID.
1576*/
1577static int btree_set_cache_size(
1578 void *NotUsed,
1579 Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
1580 int argc, /* Number of arguments */
1581 const char **argv /* Text of each argument */
1582){
1583 int nCache;
1584 Btree *pBt;
1585
1586 if( argc!=3 ){
1587 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1588 " BT NCACHE\"", 0);
1589 return TCL_ERROR;
1590 }
1591 pBt = sqlite3TextToPtr(argv[1]);
1592 if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR;
danielk1977a1644fd2007-08-29 12:31:25 +00001593
drhe5fe6902007-12-07 18:55:28 +00001594 sqlite3_mutex_enter(pBt->db->mutex);
drhff0587c2007-08-29 17:43:19 +00001595 sqlite3BtreeEnter(pBt);
danielk19771ad7f642005-01-20 05:24:32 +00001596 sqlite3BtreeSetCacheSize(pBt, nCache);
drhff0587c2007-08-29 17:43:19 +00001597 sqlite3BtreeLeave(pBt);
drhe5fe6902007-12-07 18:55:28 +00001598 sqlite3_mutex_leave(pBt->db->mutex);
danielk1977a1644fd2007-08-29 12:31:25 +00001599
danielk19771ad7f642005-01-20 05:24:32 +00001600 return TCL_OK;
1601}
1602
1603
danielk197742741be2005-01-08 12:42:39 +00001604/*
drh5c4d9702001-08-20 00:33:58 +00001605** Register commands with the TCL interpreter.
1606*/
1607int Sqlitetest3_Init(Tcl_Interp *interp){
drh3a4c1412004-05-09 20:40:11 +00001608 extern int sqlite3_btree_trace;
drhc2eef3b2002-08-31 18:53:06 +00001609 static struct {
1610 char *zName;
1611 Tcl_CmdProc *xProc;
1612 } aCmd[] = {
1613 { "btree_open", (Tcl_CmdProc*)btree_open },
1614 { "btree_close", (Tcl_CmdProc*)btree_close },
1615 { "btree_begin_transaction", (Tcl_CmdProc*)btree_begin_transaction },
1616 { "btree_commit", (Tcl_CmdProc*)btree_commit },
1617 { "btree_rollback", (Tcl_CmdProc*)btree_rollback },
1618 { "btree_create_table", (Tcl_CmdProc*)btree_create_table },
1619 { "btree_drop_table", (Tcl_CmdProc*)btree_drop_table },
1620 { "btree_clear_table", (Tcl_CmdProc*)btree_clear_table },
1621 { "btree_get_meta", (Tcl_CmdProc*)btree_get_meta },
1622 { "btree_update_meta", (Tcl_CmdProc*)btree_update_meta },
1623 { "btree_page_dump", (Tcl_CmdProc*)btree_page_dump },
1624 { "btree_tree_dump", (Tcl_CmdProc*)btree_tree_dump },
1625 { "btree_pager_stats", (Tcl_CmdProc*)btree_pager_stats },
1626 { "btree_pager_ref_dump", (Tcl_CmdProc*)btree_pager_ref_dump },
1627 { "btree_cursor", (Tcl_CmdProc*)btree_cursor },
1628 { "btree_close_cursor", (Tcl_CmdProc*)btree_close_cursor },
1629 { "btree_move_to", (Tcl_CmdProc*)btree_move_to },
1630 { "btree_delete", (Tcl_CmdProc*)btree_delete },
drhc2eef3b2002-08-31 18:53:06 +00001631 { "btree_next", (Tcl_CmdProc*)btree_next },
drh2dcc9aa2002-12-04 13:40:25 +00001632 { "btree_prev", (Tcl_CmdProc*)btree_prev },
drhc39e0002004-05-07 23:50:57 +00001633 { "btree_eof", (Tcl_CmdProc*)btree_eof },
drha34b6762004-05-07 13:30:42 +00001634 { "btree_keysize", (Tcl_CmdProc*)btree_keysize },
drhc2eef3b2002-08-31 18:53:06 +00001635 { "btree_key", (Tcl_CmdProc*)btree_key },
1636 { "btree_data", (Tcl_CmdProc*)btree_data },
drh0e1c19e2004-05-11 00:58:56 +00001637 { "btree_fetch_key", (Tcl_CmdProc*)btree_fetch_key },
1638 { "btree_fetch_data", (Tcl_CmdProc*)btree_fetch_data },
drhc2eef3b2002-08-31 18:53:06 +00001639 { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size },
1640 { "btree_first", (Tcl_CmdProc*)btree_first },
drh2dcc9aa2002-12-04 13:40:25 +00001641 { "btree_last", (Tcl_CmdProc*)btree_last },
drhc2eef3b2002-08-31 18:53:06 +00001642 { "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check },
drh9b171272004-05-08 02:03:22 +00001643 { "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint },
drh6d2fb152004-05-14 16:50:06 +00001644 { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test },
danielk19771d850a72004-05-31 08:26:49 +00001645 { "btree_begin_statement", (Tcl_CmdProc*)btree_begin_statement },
1646 { "btree_commit_statement", (Tcl_CmdProc*)btree_commit_statement },
1647 { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
danielk197742741be2005-01-08 12:42:39 +00001648 { "btree_from_db", (Tcl_CmdProc*)btree_from_db },
danielk19771ad7f642005-01-20 05:24:32 +00001649 { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size },
danielk197707cb5602006-01-20 10:55:05 +00001650 { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info },
drh50c67062007-02-10 19:22:35 +00001651 { "btree_ovfl_info", (Tcl_CmdProc*)btree_ovfl_info },
danielk197707cb5602006-01-20 10:55:05 +00001652 { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
drhc2eef3b2002-08-31 18:53:06 +00001653 };
1654 int i;
1655
1656 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
1657 Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
1658 }
drha34b6762004-05-07 13:30:42 +00001659 Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager3_refinfo_enable,
drh5c4d9702001-08-20 00:33:58 +00001660 TCL_LINK_INT);
drh3a4c1412004-05-09 20:40:11 +00001661 Tcl_LinkVar(interp, "btree_trace", (char*)&sqlite3_btree_trace,
1662 TCL_LINK_INT);
danielk1977312d6b32004-06-29 13:18:23 +00001663
1664 /* The btree_insert command is implemented using the tcl 'object'
1665 ** interface, not the string interface like the other commands in this
1666 ** file. This is so binary data can be inserted into btree tables.
1667 */
1668 Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0);
drh5c4d9702001-08-20 00:33:58 +00001669 return TCL_OK;
1670}