diff options
Diffstat (limited to 'libraries/sqlite/unix/sqlite-3.5.1/src/test3.c')
-rw-r--r-- | libraries/sqlite/unix/sqlite-3.5.1/src/test3.c | 1670 |
1 files changed, 1670 insertions, 0 deletions
diff --git a/libraries/sqlite/unix/sqlite-3.5.1/src/test3.c b/libraries/sqlite/unix/sqlite-3.5.1/src/test3.c new file mode 100644 index 0000000..4f14330 --- /dev/null +++ b/libraries/sqlite/unix/sqlite-3.5.1/src/test3.c | |||
@@ -0,0 +1,1670 @@ | |||
1 | /* | ||
2 | ** 2001 September 15 | ||
3 | ** | ||
4 | ** The author disclaims copyright to this source code. In place of | ||
5 | ** a legal notice, here is a blessing: | ||
6 | ** | ||
7 | ** 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. | ||
10 | ** | ||
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 | ** | ||
16 | ** $Id: test3.c,v 1.87 2007/09/12 17:01:45 danielk1977 Exp $ | ||
17 | */ | ||
18 | #include "sqliteInt.h" | ||
19 | #include "btreeInt.h" | ||
20 | #include "tcl.h" | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | |||
24 | /* | ||
25 | ** Interpret an SQLite error number | ||
26 | */ | ||
27 | static 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; | ||
32 | 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; | ||
40 | case SQLITE_FULL: zName = "SQLITE_FULL"; break; | ||
41 | case SQLITE_CANTOPEN: zName = "SQLITE_CANTOPEN"; break; | ||
42 | case SQLITE_PROTOCOL: zName = "SQLITE_PROTOCOL"; break; | ||
43 | case SQLITE_EMPTY: zName = "SQLITE_EMPTY"; break; | ||
44 | case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; | ||
45 | default: zName = "SQLITE_Unknown"; break; | ||
46 | } | ||
47 | return zName; | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | ** A bogus sqlite3 connection structure for use in the btree | ||
52 | ** tests. | ||
53 | */ | ||
54 | static sqlite3 sDb; | ||
55 | static int nRefSqlite3 = 0; | ||
56 | |||
57 | /* | ||
58 | ** Usage: btree_open FILENAME NCACHE FLAGS | ||
59 | ** | ||
60 | ** Open a new database | ||
61 | */ | ||
62 | static int btree_open( | ||
63 | void *NotUsed, | ||
64 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
65 | int argc, /* Number of arguments */ | ||
66 | const char **argv /* Text of each argument */ | ||
67 | ){ | ||
68 | Btree *pBt; | ||
69 | int rc, nCache, flags; | ||
70 | char zBuf[100]; | ||
71 | if( argc!=4 ){ | ||
72 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | ||
73 | " FILENAME NCACHE FLAGS\"", 0); | ||
74 | return TCL_ERROR; | ||
75 | } | ||
76 | if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; | ||
77 | if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR; | ||
78 | nRefSqlite3++; | ||
79 | if( nRefSqlite3==1 ){ | ||
80 | sDb.pVfs = sqlite3_vfs_find(0); | ||
81 | sDb.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); | ||
82 | sqlite3_mutex_enter(sDb.mutex); | ||
83 | } | ||
84 | rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, flags, | ||
85 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB); | ||
86 | if( rc!=SQLITE_OK ){ | ||
87 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
88 | return TCL_ERROR; | ||
89 | } | ||
90 | sqlite3BtreeSetCacheSize(pBt, nCache); | ||
91 | sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pBt); | ||
92 | Tcl_AppendResult(interp, zBuf, 0); | ||
93 | return TCL_OK; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | ** Usage: btree_close ID | ||
98 | ** | ||
99 | ** Close the given database. | ||
100 | */ | ||
101 | static int btree_close( | ||
102 | void *NotUsed, | ||
103 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
104 | int argc, /* Number of arguments */ | ||
105 | const char **argv /* Text of each argument */ | ||
106 | ){ | ||
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 | } | ||
114 | pBt = sqlite3TextToPtr(argv[1]); | ||
115 | rc = sqlite3BtreeClose(pBt); | ||
116 | if( rc!=SQLITE_OK ){ | ||
117 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
118 | return TCL_ERROR; | ||
119 | } | ||
120 | nRefSqlite3--; | ||
121 | if( nRefSqlite3==0 ){ | ||
122 | sqlite3_mutex_leave(sDb.mutex); | ||
123 | sqlite3_mutex_free(sDb.mutex); | ||
124 | sDb.mutex = 0; | ||
125 | sDb.pVfs = 0; | ||
126 | } | ||
127 | return TCL_OK; | ||
128 | } | ||
129 | |||
130 | |||
131 | /* | ||
132 | ** Usage: btree_begin_transaction ID | ||
133 | ** | ||
134 | ** Start a new transaction | ||
135 | */ | ||
136 | static int btree_begin_transaction( | ||
137 | void *NotUsed, | ||
138 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
139 | int argc, /* Number of arguments */ | ||
140 | const char **argv /* Text of each argument */ | ||
141 | ){ | ||
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 | } | ||
149 | pBt = sqlite3TextToPtr(argv[1]); | ||
150 | sqlite3BtreeEnter(pBt); | ||
151 | rc = sqlite3BtreeBeginTrans(pBt, 1); | ||
152 | sqlite3BtreeLeave(pBt); | ||
153 | 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 | */ | ||
165 | static int btree_rollback( | ||
166 | void *NotUsed, | ||
167 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
168 | int argc, /* Number of arguments */ | ||
169 | const char **argv /* Text of each argument */ | ||
170 | ){ | ||
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 | } | ||
178 | pBt = sqlite3TextToPtr(argv[1]); | ||
179 | sqlite3BtreeEnter(pBt); | ||
180 | rc = sqlite3BtreeRollback(pBt); | ||
181 | sqlite3BtreeLeave(pBt); | ||
182 | 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 | */ | ||
194 | static int btree_commit( | ||
195 | void *NotUsed, | ||
196 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
197 | int argc, /* Number of arguments */ | ||
198 | const char **argv /* Text of each argument */ | ||
199 | ){ | ||
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 | } | ||
207 | pBt = sqlite3TextToPtr(argv[1]); | ||
208 | sqlite3BtreeEnter(pBt); | ||
209 | rc = sqlite3BtreeCommit(pBt); | ||
210 | sqlite3BtreeLeave(pBt); | ||
211 | if( rc!=SQLITE_OK ){ | ||
212 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
213 | return TCL_ERROR; | ||
214 | } | ||
215 | return TCL_OK; | ||
216 | } | ||
217 | |||
218 | /* | ||
219 | ** Usage: btree_begin_statement ID | ||
220 | ** | ||
221 | ** Start a new statement transaction | ||
222 | */ | ||
223 | static 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 | } | ||
236 | pBt = sqlite3TextToPtr(argv[1]); | ||
237 | sqlite3BtreeEnter(pBt); | ||
238 | rc = sqlite3BtreeBeginStmt(pBt); | ||
239 | sqlite3BtreeLeave(pBt); | ||
240 | 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 | */ | ||
252 | static 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 | } | ||
265 | pBt = sqlite3TextToPtr(argv[1]); | ||
266 | sqlite3BtreeEnter(pBt); | ||
267 | rc = sqlite3BtreeRollbackStmt(pBt); | ||
268 | sqlite3BtreeLeave(pBt); | ||
269 | 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 | */ | ||
281 | static 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 | } | ||
294 | pBt = sqlite3TextToPtr(argv[1]); | ||
295 | sqlite3BtreeEnter(pBt); | ||
296 | rc = sqlite3BtreeCommitStmt(pBt); | ||
297 | sqlite3BtreeLeave(pBt); | ||
298 | if( rc!=SQLITE_OK ){ | ||
299 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
300 | return TCL_ERROR; | ||
301 | } | ||
302 | return TCL_OK; | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | ** Usage: btree_create_table ID FLAGS | ||
307 | ** | ||
308 | ** Create a new table in the database | ||
309 | */ | ||
310 | static int btree_create_table( | ||
311 | void *NotUsed, | ||
312 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
313 | int argc, /* Number of arguments */ | ||
314 | const char **argv /* Text of each argument */ | ||
315 | ){ | ||
316 | Btree *pBt; | ||
317 | int rc, iTable, flags; | ||
318 | char zBuf[30]; | ||
319 | if( argc!=3 ){ | ||
320 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | ||
321 | " ID FLAGS\"", 0); | ||
322 | return TCL_ERROR; | ||
323 | } | ||
324 | pBt = sqlite3TextToPtr(argv[1]); | ||
325 | if( Tcl_GetInt(interp, argv[2], &flags) ) return TCL_ERROR; | ||
326 | sqlite3BtreeEnter(pBt); | ||
327 | rc = sqlite3BtreeCreateTable(pBt, &iTable, flags); | ||
328 | sqlite3BtreeLeave(pBt); | ||
329 | if( rc!=SQLITE_OK ){ | ||
330 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
331 | return TCL_ERROR; | ||
332 | } | ||
333 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", iTable); | ||
334 | 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 | */ | ||
343 | static int btree_drop_table( | ||
344 | void *NotUsed, | ||
345 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
346 | int argc, /* Number of arguments */ | ||
347 | const char **argv /* Text of each argument */ | ||
348 | ){ | ||
349 | Btree *pBt; | ||
350 | int iTable; | ||
351 | int rc; | ||
352 | int notUsed1; | ||
353 | if( argc!=3 ){ | ||
354 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | ||
355 | " ID TABLENUM\"", 0); | ||
356 | return TCL_ERROR; | ||
357 | } | ||
358 | pBt = sqlite3TextToPtr(argv[1]); | ||
359 | if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; | ||
360 | sqlite3BtreeEnter(pBt); | ||
361 | rc = sqlite3BtreeDropTable(pBt, iTable, ¬Used1); | ||
362 | sqlite3BtreeLeave(pBt); | ||
363 | 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 | */ | ||
375 | static int btree_clear_table( | ||
376 | void *NotUsed, | ||
377 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
378 | int argc, /* Number of arguments */ | ||
379 | const char **argv /* Text of each argument */ | ||
380 | ){ | ||
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 | } | ||
389 | pBt = sqlite3TextToPtr(argv[1]); | ||
390 | if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; | ||
391 | sqlite3BtreeEnter(pBt); | ||
392 | rc = sqlite3BtreeClearTable(pBt, iTable); | ||
393 | sqlite3BtreeLeave(pBt); | ||
394 | 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 | */ | ||
406 | static int btree_get_meta( | ||
407 | void *NotUsed, | ||
408 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
409 | int argc, /* Number of arguments */ | ||
410 | const char **argv /* Text of each argument */ | ||
411 | ){ | ||
412 | Btree *pBt; | ||
413 | int rc; | ||
414 | int i; | ||
415 | if( argc!=2 ){ | ||
416 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | ||
417 | " ID\"", 0); | ||
418 | return TCL_ERROR; | ||
419 | } | ||
420 | pBt = sqlite3TextToPtr(argv[1]); | ||
421 | for(i=0; i<SQLITE_N_BTREE_META; i++){ | ||
422 | char zBuf[30]; | ||
423 | unsigned int v; | ||
424 | sqlite3BtreeEnter(pBt); | ||
425 | rc = sqlite3BtreeGetMeta(pBt, i, &v); | ||
426 | sqlite3BtreeLeave(pBt); | ||
427 | if( rc!=SQLITE_OK ){ | ||
428 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
429 | return TCL_ERROR; | ||
430 | } | ||
431 | sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",v); | ||
432 | 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 | */ | ||
442 | static int btree_update_meta( | ||
443 | void *NotUsed, | ||
444 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
445 | int argc, /* Number of arguments */ | ||
446 | const char **argv /* Text of each argument */ | ||
447 | ){ | ||
448 | Btree *pBt; | ||
449 | int rc; | ||
450 | int i; | ||
451 | int aMeta[SQLITE_N_BTREE_META]; | ||
452 | |||
453 | if( argc!=2+SQLITE_N_BTREE_META ){ | ||
454 | char zBuf[30]; | ||
455 | sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",SQLITE_N_BTREE_META); | ||
456 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | ||
457 | " ID METADATA...\" (METADATA is ", zBuf, " integers)", 0); | ||
458 | return TCL_ERROR; | ||
459 | } | ||
460 | pBt = sqlite3TextToPtr(argv[1]); | ||
461 | for(i=1; i<SQLITE_N_BTREE_META; i++){ | ||
462 | if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR; | ||
463 | } | ||
464 | for(i=1; i<SQLITE_N_BTREE_META; i++){ | ||
465 | sqlite3BtreeEnter(pBt); | ||
466 | rc = sqlite3BtreeUpdateMeta(pBt, i, aMeta[i]); | ||
467 | sqlite3BtreeLeave(pBt); | ||
468 | if( rc!=SQLITE_OK ){ | ||
469 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
470 | return TCL_ERROR; | ||
471 | } | ||
472 | } | ||
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 | */ | ||
481 | static int btree_page_dump( | ||
482 | void *NotUsed, | ||
483 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
484 | int argc, /* Number of arguments */ | ||
485 | const char **argv /* Text of each argument */ | ||
486 | ){ | ||
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 | } | ||
496 | pBt = sqlite3TextToPtr(argv[1]); | ||
497 | if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; | ||
498 | sqlite3BtreeEnter(pBt); | ||
499 | rc = sqlite3BtreePageDump(pBt, iPage, 0); | ||
500 | sqlite3BtreeLeave(pBt); | ||
501 | 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 | */ | ||
513 | static int btree_tree_dump( | ||
514 | void *NotUsed, | ||
515 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
516 | int argc, /* Number of arguments */ | ||
517 | const char **argv /* Text of each argument */ | ||
518 | ){ | ||
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 | } | ||
528 | pBt = sqlite3TextToPtr(argv[1]); | ||
529 | if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; | ||
530 | sqlite3BtreeEnter(pBt); | ||
531 | rc = sqlite3BtreePageDump(pBt, iPage, 1); | ||
532 | sqlite3BtreeLeave(pBt); | ||
533 | 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 | */ | ||
545 | static int btree_pager_stats( | ||
546 | void *NotUsed, | ||
547 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
548 | int argc, /* Number of arguments */ | ||
549 | const char **argv /* Text of each argument */ | ||
550 | ){ | ||
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 | } | ||
560 | pBt = sqlite3TextToPtr(argv[1]); | ||
561 | |||
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 | */ | ||
569 | sqlite3_mutex_enter(pBt->pSqlite->mutex); | ||
570 | |||
571 | sqlite3BtreeEnter(pBt); | ||
572 | a = sqlite3PagerStats(sqlite3BtreePager(pBt)); | ||
573 | for(i=0; i<11; i++){ | ||
574 | static char *zName[] = { | ||
575 | "ref", "page", "max", "size", "state", "err", | ||
576 | "hit", "miss", "ovfl", "read", "write" | ||
577 | }; | ||
578 | char zBuf[100]; | ||
579 | Tcl_AppendElement(interp, zName[i]); | ||
580 | sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]); | ||
581 | Tcl_AppendElement(interp, zBuf); | ||
582 | } | ||
583 | sqlite3BtreeLeave(pBt); | ||
584 | |||
585 | /* Release the mutex on the SQLite handle that controls this b-tree */ | ||
586 | sqlite3_mutex_leave(pBt->pSqlite->mutex); | ||
587 | return TCL_OK; | ||
588 | } | ||
589 | |||
590 | /* | ||
591 | ** Usage: btree_pager_ref_dump ID | ||
592 | ** | ||
593 | ** Print out all outstanding pages. | ||
594 | */ | ||
595 | static 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 */ | ||
599 | const char **argv /* Text of each argument */ | ||
600 | ){ | ||
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 | } | ||
608 | pBt = sqlite3TextToPtr(argv[1]); | ||
609 | #ifdef SQLITE_DEBUG | ||
610 | sqlite3BtreeEnter(pBt); | ||
611 | sqlite3PagerRefdump(sqlite3BtreePager(pBt)); | ||
612 | sqlite3BtreeLeave(pBt); | ||
613 | #endif | ||
614 | return TCL_OK; | ||
615 | } | ||
616 | |||
617 | /* | ||
618 | ** Usage: btree_integrity_check ID ROOT ... | ||
619 | ** | ||
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 | */ | ||
624 | static int btree_integrity_check( | ||
625 | void *NotUsed, | ||
626 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
627 | int argc, /* Number of arguments */ | ||
628 | const char **argv /* Text of each argument */ | ||
629 | ){ | ||
630 | Btree *pBt; | ||
631 | int nRoot; | ||
632 | int *aRoot; | ||
633 | int i; | ||
634 | int nErr; | ||
635 | char *zResult; | ||
636 | |||
637 | if( argc<3 ){ | ||
638 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | ||
639 | " ID ROOT ...\"", 0); | ||
640 | return TCL_ERROR; | ||
641 | } | ||
642 | pBt = sqlite3TextToPtr(argv[1]); | ||
643 | nRoot = argc-2; | ||
644 | aRoot = (int*)sqlite3_malloc( sizeof(int)*(argc-2) ); | ||
645 | for(i=0; i<argc-2; i++){ | ||
646 | if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR; | ||
647 | } | ||
648 | #ifndef SQLITE_OMIT_INTEGRITY_CHECK | ||
649 | sqlite3BtreeEnter(pBt); | ||
650 | zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr); | ||
651 | sqlite3BtreeLeave(pBt); | ||
652 | #else | ||
653 | zResult = 0; | ||
654 | #endif | ||
655 | sqlite3_free((void*)aRoot); | ||
656 | if( zResult ){ | ||
657 | Tcl_AppendResult(interp, zResult, 0); | ||
658 | sqlite3_free(zResult); | ||
659 | } | ||
660 | return TCL_OK; | ||
661 | } | ||
662 | |||
663 | /* | ||
664 | ** Usage: btree_cursor_list ID | ||
665 | ** | ||
666 | ** Print information about all cursors to standard output for debugging. | ||
667 | */ | ||
668 | static 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 | } | ||
681 | pBt = sqlite3TextToPtr(argv[1]); | ||
682 | sqlite3BtreeEnter(pBt); | ||
683 | sqlite3BtreeCursorList(pBt); | ||
684 | sqlite3BtreeLeave(pBt); | ||
685 | return SQLITE_OK; | ||
686 | } | ||
687 | |||
688 | /* | ||
689 | ** Usage: btree_cursor ID TABLENUM WRITEABLE | ||
690 | ** | ||
691 | ** Create a new cursor. Return the ID for the cursor. | ||
692 | */ | ||
693 | static int btree_cursor( | ||
694 | void *NotUsed, | ||
695 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
696 | int argc, /* Number of arguments */ | ||
697 | const char **argv /* Text of each argument */ | ||
698 | ){ | ||
699 | Btree *pBt; | ||
700 | int iTable; | ||
701 | BtCursor *pCur; | ||
702 | int rc; | ||
703 | int wrFlag; | ||
704 | char zBuf[30]; | ||
705 | |||
706 | if( argc!=4 ){ | ||
707 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | ||
708 | " ID TABLENUM WRITEABLE\"", 0); | ||
709 | return TCL_ERROR; | ||
710 | } | ||
711 | pBt = sqlite3TextToPtr(argv[1]); | ||
712 | if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; | ||
713 | if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; | ||
714 | sqlite3BtreeEnter(pBt); | ||
715 | rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, 0, &pCur); | ||
716 | sqlite3BtreeLeave(pBt); | ||
717 | if( rc ){ | ||
718 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
719 | return TCL_ERROR; | ||
720 | } | ||
721 | sqlite3_snprintf(sizeof(zBuf), zBuf,"%p", pCur); | ||
722 | 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 | */ | ||
731 | static int btree_close_cursor( | ||
732 | void *NotUsed, | ||
733 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
734 | int argc, /* Number of arguments */ | ||
735 | const char **argv /* Text of each argument */ | ||
736 | ){ | ||
737 | BtCursor *pCur; | ||
738 | Btree *pBt; | ||
739 | 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 | } | ||
746 | pCur = sqlite3TextToPtr(argv[1]); | ||
747 | pBt = pCur->pBtree; | ||
748 | sqlite3BtreeEnter(pBt); | ||
749 | rc = sqlite3BtreeCloseCursor(pCur); | ||
750 | sqlite3BtreeLeave(pBt); | ||
751 | 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 | */ | ||
763 | static int btree_move_to( | ||
764 | void *NotUsed, | ||
765 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
766 | int argc, /* Number of arguments */ | ||
767 | const char **argv /* Text of each argument */ | ||
768 | ){ | ||
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 | } | ||
779 | pCur = sqlite3TextToPtr(argv[1]); | ||
780 | sqlite3BtreeEnter(pCur->pBtree); | ||
781 | if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ | ||
782 | int iKey; | ||
783 | if( Tcl_GetInt(interp, argv[2], &iKey) ){ | ||
784 | sqlite3BtreeLeave(pCur->pBtree); | ||
785 | return TCL_ERROR; | ||
786 | } | ||
787 | rc = sqlite3BtreeMoveto(pCur, 0, iKey, 0, &res); | ||
788 | }else{ | ||
789 | rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res); | ||
790 | } | ||
791 | sqlite3BtreeLeave(pCur->pBtree); | ||
792 | if( rc ){ | ||
793 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
794 | return TCL_ERROR; | ||
795 | } | ||
796 | if( res<0 ) res = -1; | ||
797 | if( res>0 ) res = 1; | ||
798 | sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",res); | ||
799 | 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 | */ | ||
808 | static int btree_delete( | ||
809 | void *NotUsed, | ||
810 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
811 | int argc, /* Number of arguments */ | ||
812 | const char **argv /* Text of each argument */ | ||
813 | ){ | ||
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 | } | ||
822 | pCur = sqlite3TextToPtr(argv[1]); | ||
823 | sqlite3BtreeEnter(pCur->pBtree); | ||
824 | rc = sqlite3BtreeDelete(pCur); | ||
825 | sqlite3BtreeLeave(pCur->pBtree); | ||
826 | if( rc ){ | ||
827 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
828 | return TCL_ERROR; | ||
829 | } | ||
830 | return SQLITE_OK; | ||
831 | } | ||
832 | |||
833 | /* | ||
834 | ** Usage: btree_insert ID KEY DATA ?NZERO? | ||
835 | ** | ||
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 | */ | ||
839 | static int btree_insert( | ||
840 | void * clientData, | ||
841 | Tcl_Interp *interp, | ||
842 | int objc, | ||
843 | Tcl_Obj *CONST objv[] | ||
844 | ){ | ||
845 | BtCursor *pCur; | ||
846 | int rc; | ||
847 | int nZero; | ||
848 | |||
849 | if( objc!=4 && objc!=5 ){ | ||
850 | Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA ?NZERO?"); | ||
851 | return TCL_ERROR; | ||
852 | } | ||
853 | pCur = sqlite3TextToPtr(Tcl_GetString(objv[1])); | ||
854 | if( objc==5 ){ | ||
855 | if( Tcl_GetIntFromObj(interp, objv[4], &nZero) ) return TCL_ERROR; | ||
856 | }else{ | ||
857 | nZero = 0; | ||
858 | } | ||
859 | sqlite3BtreeEnter(pCur->pBtree); | ||
860 | if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ | ||
861 | i64 iKey; | ||
862 | int len; | ||
863 | unsigned char *pBuf; | ||
864 | if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ){ | ||
865 | sqlite3BtreeLeave(pCur->pBtree); | ||
866 | return TCL_ERROR; | ||
867 | } | ||
868 | pBuf = Tcl_GetByteArrayFromObj(objv[3], &len); | ||
869 | rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0); | ||
870 | }else{ | ||
871 | 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); | ||
877 | rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, nZero, 0); | ||
878 | } | ||
879 | sqlite3BtreeLeave(pCur->pBtree); | ||
880 | 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 | ** | ||
890 | ** 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. | ||
893 | */ | ||
894 | static int btree_next( | ||
895 | void *NotUsed, | ||
896 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
897 | int argc, /* Number of arguments */ | ||
898 | const char **argv /* Text of each argument */ | ||
899 | ){ | ||
900 | BtCursor *pCur; | ||
901 | int rc; | ||
902 | int res = 0; | ||
903 | char zBuf[100]; | ||
904 | |||
905 | if( argc!=2 ){ | ||
906 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | ||
907 | " ID\"", 0); | ||
908 | return TCL_ERROR; | ||
909 | } | ||
910 | pCur = sqlite3TextToPtr(argv[1]); | ||
911 | sqlite3BtreeEnter(pCur->pBtree); | ||
912 | rc = sqlite3BtreeNext(pCur, &res); | ||
913 | sqlite3BtreeLeave(pCur->pBtree); | ||
914 | if( rc ){ | ||
915 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
916 | return TCL_ERROR; | ||
917 | } | ||
918 | sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); | ||
919 | Tcl_AppendResult(interp, zBuf, 0); | ||
920 | return SQLITE_OK; | ||
921 | } | ||
922 | |||
923 | /* | ||
924 | ** 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 | */ | ||
930 | static 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 | } | ||
946 | pCur = sqlite3TextToPtr(argv[1]); | ||
947 | sqlite3BtreeEnter(pCur->pBtree); | ||
948 | rc = sqlite3BtreePrevious(pCur, &res); | ||
949 | sqlite3BtreeLeave(pCur->pBtree); | ||
950 | if( rc ){ | ||
951 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
952 | return TCL_ERROR; | ||
953 | } | ||
954 | sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); | ||
955 | Tcl_AppendResult(interp, zBuf, 0); | ||
956 | return SQLITE_OK; | ||
957 | } | ||
958 | |||
959 | /* | ||
960 | ** Usage: btree_first ID | ||
961 | ** | ||
962 | ** 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. | ||
964 | */ | ||
965 | static int btree_first( | ||
966 | void *NotUsed, | ||
967 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
968 | int argc, /* Number of arguments */ | ||
969 | const char **argv /* Text of each argument */ | ||
970 | ){ | ||
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 | } | ||
981 | pCur = sqlite3TextToPtr(argv[1]); | ||
982 | sqlite3BtreeEnter(pCur->pBtree); | ||
983 | rc = sqlite3BtreeFirst(pCur, &res); | ||
984 | sqlite3BtreeLeave(pCur->pBtree); | ||
985 | if( rc ){ | ||
986 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
987 | return TCL_ERROR; | ||
988 | } | ||
989 | sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); | ||
990 | Tcl_AppendResult(interp, zBuf, 0); | ||
991 | return SQLITE_OK; | ||
992 | } | ||
993 | |||
994 | /* | ||
995 | ** 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 | */ | ||
1000 | static 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 | } | ||
1016 | pCur = sqlite3TextToPtr(argv[1]); | ||
1017 | sqlite3BtreeEnter(pCur->pBtree); | ||
1018 | rc = sqlite3BtreeLast(pCur, &res); | ||
1019 | sqlite3BtreeLeave(pCur->pBtree); | ||
1020 | if( rc ){ | ||
1021 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
1022 | return TCL_ERROR; | ||
1023 | } | ||
1024 | sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",res); | ||
1025 | Tcl_AppendResult(interp, zBuf, 0); | ||
1026 | return SQLITE_OK; | ||
1027 | } | ||
1028 | |||
1029 | /* | ||
1030 | ** 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 | */ | ||
1035 | static 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; | ||
1042 | int rc; | ||
1043 | 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 | } | ||
1050 | pCur = sqlite3TextToPtr(argv[1]); | ||
1051 | sqlite3BtreeEnter(pCur->pBtree); | ||
1052 | rc = sqlite3BtreeEof(pCur); | ||
1053 | sqlite3BtreeLeave(pCur->pBtree); | ||
1054 | sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); | ||
1055 | Tcl_AppendResult(interp, zBuf, 0); | ||
1056 | return SQLITE_OK; | ||
1057 | } | ||
1058 | |||
1059 | /* | ||
1060 | ** Usage: btree_keysize ID | ||
1061 | ** | ||
1062 | ** Return the number of bytes of key. For an INTKEY table, this | ||
1063 | ** returns the key itself. | ||
1064 | */ | ||
1065 | static 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; | ||
1072 | u64 n; | ||
1073 | 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 | } | ||
1080 | pCur = sqlite3TextToPtr(argv[1]); | ||
1081 | sqlite3BtreeEnter(pCur->pBtree); | ||
1082 | sqlite3BtreeKeySize(pCur, (i64*)&n); | ||
1083 | sqlite3BtreeLeave(pCur->pBtree); | ||
1084 | sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n); | ||
1085 | Tcl_AppendResult(interp, zBuf, 0); | ||
1086 | return SQLITE_OK; | ||
1087 | } | ||
1088 | |||
1089 | /* | ||
1090 | ** Usage: btree_key ID | ||
1091 | ** | ||
1092 | ** Return the key for the entry at which the cursor is pointing. | ||
1093 | */ | ||
1094 | static int btree_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 rc; | ||
1102 | u64 n; | ||
1103 | 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 | } | ||
1110 | pCur = sqlite3TextToPtr(argv[1]); | ||
1111 | sqlite3BtreeEnter(pCur->pBtree); | ||
1112 | sqlite3BtreeKeySize(pCur, (i64*)&n); | ||
1113 | if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ | ||
1114 | char zBuf2[60]; | ||
1115 | sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n); | ||
1116 | Tcl_AppendResult(interp, zBuf2, 0); | ||
1117 | }else{ | ||
1118 | zBuf = sqlite3_malloc( n+1 ); | ||
1119 | rc = sqlite3BtreeKey(pCur, 0, n, zBuf); | ||
1120 | if( rc ){ | ||
1121 | sqlite3BtreeLeave(pCur->pBtree); | ||
1122 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
1123 | return TCL_ERROR; | ||
1124 | } | ||
1125 | zBuf[n] = 0; | ||
1126 | Tcl_AppendResult(interp, zBuf, 0); | ||
1127 | sqlite3_free(zBuf); | ||
1128 | } | ||
1129 | sqlite3BtreeLeave(pCur->pBtree); | ||
1130 | return SQLITE_OK; | ||
1131 | } | ||
1132 | |||
1133 | /* | ||
1134 | ** Usage: btree_data ID ?N? | ||
1135 | ** | ||
1136 | ** Return the data for the entry at which the cursor is pointing. | ||
1137 | */ | ||
1138 | static int btree_data( | ||
1139 | void *NotUsed, | ||
1140 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
1141 | int argc, /* Number of arguments */ | ||
1142 | const char **argv /* Text of each argument */ | ||
1143 | ){ | ||
1144 | BtCursor *pCur; | ||
1145 | int rc; | ||
1146 | u32 n; | ||
1147 | char *zBuf; | ||
1148 | |||
1149 | if( argc!=2 && argc!=3 ){ | ||
1150 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | ||
1151 | " ID\"", 0); | ||
1152 | return TCL_ERROR; | ||
1153 | } | ||
1154 | pCur = sqlite3TextToPtr(argv[1]); | ||
1155 | sqlite3BtreeEnter(pCur->pBtree); | ||
1156 | if( argc==2 ){ | ||
1157 | sqlite3BtreeDataSize(pCur, &n); | ||
1158 | }else{ | ||
1159 | n = atoi(argv[2]); | ||
1160 | } | ||
1161 | zBuf = sqlite3_malloc( n+1 ); | ||
1162 | rc = sqlite3BtreeData(pCur, 0, n, zBuf); | ||
1163 | sqlite3BtreeLeave(pCur->pBtree); | ||
1164 | if( rc ){ | ||
1165 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
1166 | sqlite3_free(zBuf); | ||
1167 | return TCL_ERROR; | ||
1168 | } | ||
1169 | zBuf[n] = 0; | ||
1170 | Tcl_AppendResult(interp, zBuf, 0); | ||
1171 | sqlite3_free(zBuf); | ||
1172 | return SQLITE_OK; | ||
1173 | } | ||
1174 | |||
1175 | /* | ||
1176 | ** 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 | */ | ||
1181 | static 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; | ||
1189 | int amt; | ||
1190 | 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 | } | ||
1199 | pCur = sqlite3TextToPtr(argv[1]); | ||
1200 | if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; | ||
1201 | sqlite3BtreeEnter(pCur->pBtree); | ||
1202 | sqlite3BtreeKeySize(pCur, (i64*)&nKey); | ||
1203 | zBuf = sqlite3BtreeKeyFetch(pCur, &amt); | ||
1204 | if( zBuf && amt>=n ){ | ||
1205 | 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 | } | ||
1211 | sqlite3BtreeLeave(pCur->pBtree); | ||
1212 | 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 | */ | ||
1221 | static 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; | ||
1229 | int amt; | ||
1230 | 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], | ||
1236 | " ID AMT\"", 0); | ||
1237 | return TCL_ERROR; | ||
1238 | } | ||
1239 | pCur = sqlite3TextToPtr(argv[1]); | ||
1240 | if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; | ||
1241 | sqlite3BtreeEnter(pCur->pBtree); | ||
1242 | sqlite3BtreeDataSize(pCur, &nData); | ||
1243 | zBuf = sqlite3BtreeDataFetch(pCur, &amt); | ||
1244 | if( zBuf && amt>=n ){ | ||
1245 | 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 | } | ||
1251 | sqlite3BtreeLeave(pCur->pBtree); | ||
1252 | return TCL_OK; | ||
1253 | } | ||
1254 | |||
1255 | /* | ||
1256 | ** Usage: btree_payload_size ID | ||
1257 | ** | ||
1258 | ** Return the number of bytes of payload | ||
1259 | */ | ||
1260 | static int btree_payload_size( | ||
1261 | void *NotUsed, | ||
1262 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
1263 | int argc, /* Number of arguments */ | ||
1264 | const char **argv /* Text of each argument */ | ||
1265 | ){ | ||
1266 | BtCursor *pCur; | ||
1267 | int n2; | ||
1268 | u64 n1; | ||
1269 | 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 | } | ||
1276 | pCur = sqlite3TextToPtr(argv[1]); | ||
1277 | sqlite3BtreeEnter(pCur->pBtree); | ||
1278 | if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ | ||
1279 | n1 = 0; | ||
1280 | }else{ | ||
1281 | sqlite3BtreeKeySize(pCur, (i64*)&n1); | ||
1282 | } | ||
1283 | sqlite3BtreeDataSize(pCur, (u32*)&n2); | ||
1284 | sqlite3BtreeLeave(pCur->pBtree); | ||
1285 | sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2)); | ||
1286 | Tcl_AppendResult(interp, zBuf, 0); | ||
1287 | return SQLITE_OK; | ||
1288 | } | ||
1289 | |||
1290 | /* | ||
1291 | ** Usage: btree_cursor_info ID ?UP-CNT? | ||
1292 | ** | ||
1293 | ** Return integers containing information about the entry the | ||
1294 | ** 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 | ||
1299 | ** aResult[3] = Cell size (local payload + header) | ||
1300 | ** aResult[4] = Number of free bytes on this page | ||
1301 | ** aResult[5] = Number of free blocks on the page | ||
1302 | ** 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 | ||
1306 | ** aResult[10]= Page number of the first overflow page | ||
1307 | */ | ||
1308 | static int btree_cursor_info( | ||
1309 | void *NotUsed, | ||
1310 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ | ||
1311 | int argc, /* Number of arguments */ | ||
1312 | const char **argv /* Text of each argument */ | ||
1313 | ){ | ||
1314 | BtCursor *pCur; | ||
1315 | int rc; | ||
1316 | int i, j; | ||
1317 | int up; | ||
1318 | int aResult[11]; | ||
1319 | char zBuf[400]; | ||
1320 | |||
1321 | if( argc!=2 && argc!=3 ){ | ||
1322 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | ||
1323 | " ID ?UP-CNT?\"", 0); | ||
1324 | return TCL_ERROR; | ||
1325 | } | ||
1326 | pCur = sqlite3TextToPtr(argv[1]); | ||
1327 | if( argc==3 ){ | ||
1328 | if( Tcl_GetInt(interp, argv[2], &up) ) return TCL_ERROR; | ||
1329 | }else{ | ||
1330 | up = 0; | ||
1331 | } | ||
1332 | sqlite3BtreeEnter(pCur->pBtree); | ||
1333 | rc = sqlite3BtreeCursorInfo(pCur, aResult, up); | ||
1334 | if( rc ){ | ||
1335 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
1336 | sqlite3BtreeLeave(pCur->pBtree); | ||
1337 | return TCL_ERROR; | ||
1338 | } | ||
1339 | j = 0; | ||
1340 | for(i=0; i<sizeof(aResult)/sizeof(aResult[0]); i++){ | ||
1341 | sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]); | ||
1342 | j += strlen(&zBuf[j]); | ||
1343 | } | ||
1344 | sqlite3BtreeLeave(pCur->pBtree); | ||
1345 | Tcl_AppendResult(interp, &zBuf[1], 0); | ||
1346 | return SQLITE_OK; | ||
1347 | } | ||
1348 | |||
1349 | /* | ||
1350 | ** Copied from btree.c: | ||
1351 | */ | ||
1352 | static u32 t4Get4byte(unsigned char *p){ | ||
1353 | 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 | */ | ||
1363 | static 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 | } | ||
1393 | sqlite3BtreeEnter(pBt); | ||
1394 | pPager = sqlite3BtreePager(pBt); | ||
1395 | rc = sqlite3BtreeCursorInfo(pCur, aResult, 0); | ||
1396 | if( rc ){ | ||
1397 | Tcl_AppendResult(interp, errorName(rc), 0); | ||
1398 | sqlite3BtreeLeave(pBt); | ||
1399 | return TCL_ERROR; | ||
1400 | } | ||
1401 | dataSize = pBt->pBt->usableSize; | ||
1402 | Tcl_DStringInit(&str); | ||
1403 | n = aResult[6] - aResult[8]; | ||
1404 | n = (n + dataSize - 1)/dataSize; | ||
1405 | pgno = (u32)aResult[10]; | ||
1406 | while( pgno && n-- ){ | ||
1407 | DbPage *pDbPage; | ||
1408 | sprintf(zElem, "%d", pgno); | ||
1409 | Tcl_DStringAppendElement(&str, zElem); | ||
1410 | if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){ | ||
1411 | Tcl_DStringFree(&str); | ||
1412 | Tcl_AppendResult(interp, "unable to get page ", zElem, 0); | ||
1413 | sqlite3BtreeLeave(pBt); | ||
1414 | return TCL_ERROR; | ||
1415 | } | ||
1416 | pPage = sqlite3PagerGetData(pDbPage); | ||
1417 | pgno = t4Get4byte((unsigned char*)pPage); | ||
1418 | sqlite3PagerUnref(pDbPage); | ||
1419 | } | ||
1420 | sqlite3BtreeLeave(pBt); | ||
1421 | Tcl_DStringResult(interp, &str); | ||
1422 | return SQLITE_OK; | ||
1423 | } | ||
1424 | |||
1425 | /* | ||
1426 | ** 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 | */ | ||
1434 | static 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 | |||
1443 | /* | ||
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 | */ | ||
1457 | static 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; | ||
1465 | int n1, n2, i, j; | ||
1466 | 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++){ | ||
1479 | char zErr[200]; | ||
1480 | n1 = sqlite3PutVarint(zBuf, in); | ||
1481 | if( n1>9 || n1<1 ){ | ||
1482 | sprintf(zErr, "PutVarint returned %d - should be between 1 and 9", n1); | ||
1483 | Tcl_AppendResult(interp, zErr, 0); | ||
1484 | return TCL_ERROR; | ||
1485 | } | ||
1486 | n2 = sqlite3GetVarint(zBuf, &out); | ||
1487 | if( n1!=n2 ){ | ||
1488 | sprintf(zErr, "PutVarint returned %d and GetVarint returned %d", n1, n2); | ||
1489 | Tcl_AppendResult(interp, zErr, 0); | ||
1490 | return TCL_ERROR; | ||
1491 | } | ||
1492 | if( in!=out ){ | ||
1493 | sprintf(zErr, "Wrote 0x%016llx and got back 0x%016llx", in, out); | ||
1494 | Tcl_AppendResult(interp, zErr, 0); | ||
1495 | return TCL_ERROR; | ||
1496 | } | ||
1497 | 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 | } | ||
1514 | |||
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 | } | ||
1522 | in += incr; | ||
1523 | } | ||
1524 | return TCL_OK; | ||
1525 | } | ||
1526 | |||
1527 | /* | ||
1528 | ** 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 | */ | ||
1536 | static 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; | ||
1546 | int iDb = 0; | ||
1547 | |||
1548 | if( argc!=2 && argc!=3 ){ | ||
1549 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], | ||
1550 | " DB-HANDLE ?N?\"", 0); | ||
1551 | 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 | } | ||
1558 | if( argc==3 ){ | ||
1559 | iDb = atoi(argv[2]); | ||
1560 | } | ||
1561 | |||
1562 | db = *((sqlite3 **)info.objClientData); | ||
1563 | assert( db ); | ||
1564 | |||
1565 | pBt = db->aDb[iDb].pBt; | ||
1566 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); | ||
1567 | Tcl_SetResult(interp, zBuf, TCL_VOLATILE); | ||
1568 | return TCL_OK; | ||
1569 | } | ||
1570 | |||
1571 | |||
1572 | /* | ||
1573 | ** usage: btree_set_cache_size ID NCACHE | ||
1574 | ** | ||
1575 | ** Set the size of the cache used by btree $ID. | ||
1576 | */ | ||
1577 | static 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; | ||
1593 | |||
1594 | sqlite3_mutex_enter(pBt->pSqlite->mutex); | ||
1595 | sqlite3BtreeEnter(pBt); | ||
1596 | sqlite3BtreeSetCacheSize(pBt, nCache); | ||
1597 | sqlite3BtreeLeave(pBt); | ||
1598 | sqlite3_mutex_leave(pBt->pSqlite->mutex); | ||
1599 | |||
1600 | return TCL_OK; | ||
1601 | } | ||
1602 | |||
1603 | |||
1604 | /* | ||
1605 | ** Register commands with the TCL interpreter. | ||
1606 | */ | ||
1607 | int Sqlitetest3_Init(Tcl_Interp *interp){ | ||
1608 | extern int sqlite3_btree_trace; | ||
1609 | 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 }, | ||
1631 | { "btree_next", (Tcl_CmdProc*)btree_next }, | ||
1632 | { "btree_prev", (Tcl_CmdProc*)btree_prev }, | ||
1633 | { "btree_eof", (Tcl_CmdProc*)btree_eof }, | ||
1634 | { "btree_keysize", (Tcl_CmdProc*)btree_keysize }, | ||
1635 | { "btree_key", (Tcl_CmdProc*)btree_key }, | ||
1636 | { "btree_data", (Tcl_CmdProc*)btree_data }, | ||
1637 | { "btree_fetch_key", (Tcl_CmdProc*)btree_fetch_key }, | ||
1638 | { "btree_fetch_data", (Tcl_CmdProc*)btree_fetch_data }, | ||
1639 | { "btree_payload_size", (Tcl_CmdProc*)btree_payload_size }, | ||
1640 | { "btree_first", (Tcl_CmdProc*)btree_first }, | ||
1641 | { "btree_last", (Tcl_CmdProc*)btree_last }, | ||
1642 | { "btree_integrity_check", (Tcl_CmdProc*)btree_integrity_check }, | ||
1643 | { "btree_breakpoint", (Tcl_CmdProc*)btree_breakpoint }, | ||
1644 | { "btree_varint_test", (Tcl_CmdProc*)btree_varint_test }, | ||
1645 | { "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 }, | ||
1648 | { "btree_from_db", (Tcl_CmdProc*)btree_from_db }, | ||
1649 | { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }, | ||
1650 | { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info }, | ||
1651 | { "btree_ovfl_info", (Tcl_CmdProc*)btree_ovfl_info }, | ||
1652 | { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list }, | ||
1653 | }; | ||
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 | } | ||
1659 | Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager3_refinfo_enable, | ||
1660 | TCL_LINK_INT); | ||
1661 | Tcl_LinkVar(interp, "btree_trace", (char*)&sqlite3_btree_trace, | ||
1662 | TCL_LINK_INT); | ||
1663 | |||
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); | ||
1669 | return TCL_OK; | ||
1670 | } | ||