diff options
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src/test3.c')
| -rw-r--r-- | ext/pdo_sqlite/sqlite/src/test3.c | 275 |
1 files changed, 239 insertions, 36 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/test3.c b/ext/pdo_sqlite/sqlite/src/test3.c index 6557fb4f4d..8f568d7694 100644 --- a/ext/pdo_sqlite/sqlite/src/test3.c +++ b/ext/pdo_sqlite/sqlite/src/test3.c @@ -16,8 +16,7 @@ ** $Id$ */ #include "sqliteInt.h" -#include "pager.h" -#include "btree.h" +#include "btreeInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> @@ -49,6 +48,13 @@ static char *errorName(int rc){ } /* +** A bogus sqlite3 connection structure for use in the btree +** tests. +*/ +static sqlite3 sDb; +static int nRefSqlite3 = 0; + +/* ** Usage: btree_open FILENAME NCACHE FLAGS ** ** Open a new database @@ -69,7 +75,14 @@ static int btree_open( } if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[3], &flags) ) return TCL_ERROR; - rc = sqlite3BtreeOpen(argv[1], 0, &pBt, flags); + nRefSqlite3++; + if( nRefSqlite3==1 ){ + sDb.pVfs = sqlite3_vfs_find(0); + sDb.mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); + sqlite3_mutex_enter(sDb.mutex); + } + rc = sqlite3BtreeOpen(argv[1], &sDb, &pBt, flags, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_MAIN_DB); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -104,9 +117,17 @@ static int btree_close( Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } + nRefSqlite3--; + if( nRefSqlite3==0 ){ + sqlite3_mutex_leave(sDb.mutex); + sqlite3_mutex_free(sDb.mutex); + sDb.mutex = 0; + sDb.pVfs = 0; + } return TCL_OK; } + /* ** Usage: btree_begin_transaction ID ** @@ -126,7 +147,9 @@ static int btree_begin_transaction( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeBeginTrans(pBt, 1); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -153,7 +176,9 @@ static int btree_rollback( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeRollback(pBt); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -180,7 +205,9 @@ static int btree_commit( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCommit(pBt); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -207,7 +234,9 @@ static int btree_begin_statement( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeBeginStmt(pBt); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -234,7 +263,9 @@ static int btree_rollback_statement( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeRollbackStmt(pBt); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -261,7 +292,9 @@ static int btree_commit_statement( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCommitStmt(pBt); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -290,7 +323,9 @@ static int btree_create_table( } pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &flags) ) return TCL_ERROR; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCreateTable(pBt, &iTable, flags); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -322,7 +357,9 @@ static int btree_drop_table( } pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeDropTable(pBt, iTable, ¬Used1); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -351,7 +388,9 @@ static int btree_clear_table( } pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeClearTable(pBt, iTable); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -382,7 +421,9 @@ static int btree_get_meta( for(i=0; i<SQLITE_N_BTREE_META; i++){ char zBuf[30]; unsigned int v; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeGetMeta(pBt, i, &v); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -421,7 +462,9 @@ static int btree_update_meta( if( Tcl_GetInt(interp, argv[i+2], &aMeta[i]) ) return TCL_ERROR; } for(i=1; i<SQLITE_N_BTREE_META; i++){ + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeUpdateMeta(pBt, i, aMeta[i]); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -452,7 +495,9 @@ static int btree_page_dump( } pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreePageDump(pBt, iPage, 0); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -482,7 +527,9 @@ static int btree_tree_dump( } pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iPage) ) return TCL_ERROR; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreePageDump(pBt, iPage, 1); + sqlite3BtreeLeave(pBt); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -511,7 +558,18 @@ static int btree_pager_stats( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); - a = sqlite3pager_stats(sqlite3BtreePager(pBt)); + + /* Normally in this file, with a b-tree handle opened using the + ** [btree_open] command it is safe to call sqlite3BtreeEnter() directly. + ** But this function is sometimes called with a btree handle obtained + ** from an open SQLite connection (using [btree_from_db]). In this case + ** we need to obtain the mutex for the controlling SQLite handle before + ** it is safe to call sqlite3BtreeEnter(). + */ + sqlite3_mutex_enter(pBt->db->mutex); + + sqlite3BtreeEnter(pBt); + a = sqlite3PagerStats(sqlite3BtreePager(pBt)); for(i=0; i<11; i++){ static char *zName[] = { "ref", "page", "max", "size", "state", "err", @@ -522,6 +580,10 @@ static int btree_pager_stats( sqlite3_snprintf(sizeof(zBuf), zBuf,"%d",a[i]); Tcl_AppendElement(interp, zBuf); } + sqlite3BtreeLeave(pBt); + + /* Release the mutex on the SQLite handle that controls this b-tree */ + sqlite3_mutex_leave(pBt->db->mutex); return TCL_OK; } @@ -544,8 +606,10 @@ static int btree_pager_ref_dump( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); -#ifdef SQLITE_DEBUG - sqlite3pager_refdump(sqlite3BtreePager(pBt)); +#ifdef SQLITE_TEST + sqlite3BtreeEnter(pBt); + sqlite3PagerRefdump(sqlite3BtreePager(pBt)); + sqlite3BtreeLeave(pBt); #endif return TCL_OK; } @@ -567,6 +631,7 @@ static int btree_integrity_check( int nRoot; int *aRoot; int i; + int nErr; char *zResult; if( argc<3 ){ @@ -576,19 +641,21 @@ static int btree_integrity_check( } pBt = sqlite3TextToPtr(argv[1]); nRoot = argc-2; - aRoot = malloc( sizeof(int)*(argc-2) ); + aRoot = (int*)sqlite3_malloc( sizeof(int)*(argc-2) ); for(i=0; i<argc-2; i++){ if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR; } #ifndef SQLITE_OMIT_INTEGRITY_CHECK - zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot); + sqlite3BtreeEnter(pBt); + zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr); + sqlite3BtreeLeave(pBt); #else zResult = 0; #endif - free(aRoot); + sqlite3_free((void*)aRoot); if( zResult ){ Tcl_AppendResult(interp, zResult, 0); - sqliteFree(zResult); + sqlite3_free(zResult); } return TCL_OK; } @@ -598,7 +665,6 @@ static int btree_integrity_check( ** ** Print information about all cursors to standard output for debugging. */ -#ifdef SQLITE_DEBUG static int btree_cursor_list( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ @@ -613,10 +679,11 @@ static int btree_cursor_list( return TCL_ERROR; } pBt = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pBt); sqlite3BtreeCursorList(pBt); + sqlite3BtreeLeave(pBt); return SQLITE_OK; } -#endif /* ** Usage: btree_cursor ID TABLENUM WRITEABLE @@ -644,7 +711,9 @@ static int btree_cursor( pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, 0, &pCur); + sqlite3BtreeLeave(pBt); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -666,6 +735,7 @@ static int btree_close_cursor( const char **argv /* Text of each argument */ ){ BtCursor *pCur; + Btree *pBt; int rc; if( argc!=2 ){ @@ -674,7 +744,10 @@ static int btree_close_cursor( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + pBt = pCur->pBtree; + sqlite3BtreeEnter(pBt); rc = sqlite3BtreeCloseCursor(pCur); + sqlite3BtreeLeave(pBt); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -704,13 +777,18 @@ static int btree_move_to( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ int iKey; - if( Tcl_GetInt(interp, argv[2], &iKey) ) return TCL_ERROR; - rc = sqlite3BtreeMoveto(pCur, 0, iKey, &res); + if( Tcl_GetInt(interp, argv[2], &iKey) ){ + sqlite3BtreeLeave(pCur->pBtree); + return TCL_ERROR; + } + rc = sqlite3BtreeMoveto(pCur, 0, iKey, 0, &res); }else{ - rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), &res); + rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res); } + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -742,7 +820,9 @@ static int btree_delete( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeDelete(pCur); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -751,7 +831,7 @@ static int btree_delete( } /* -** Usage: btree_insert ID KEY DATA +** Usage: btree_insert ID KEY DATA ?NZERO? ** ** Create a new entry with the given key and data. If an entry already ** exists with the same key the old entry is overwritten. @@ -764,19 +844,29 @@ static int btree_insert( ){ BtCursor *pCur; int rc; + int nZero; - if( objc!=4 ){ - Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA"); + if( objc!=4 && objc!=5 ){ + Tcl_WrongNumArgs(interp, 1, objv, "ID KEY DATA ?NZERO?"); return TCL_ERROR; } pCur = sqlite3TextToPtr(Tcl_GetString(objv[1])); + if( objc==5 ){ + if( Tcl_GetIntFromObj(interp, objv[4], &nZero) ) return TCL_ERROR; + }else{ + nZero = 0; + } + sqlite3BtreeEnter(pCur->pBtree); if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ i64 iKey; int len; unsigned char *pBuf; - if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR; + if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ){ + sqlite3BtreeLeave(pCur->pBtree); + return TCL_ERROR; + } pBuf = Tcl_GetByteArrayFromObj(objv[3], &len); - rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len); + rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, nZero, 0); }else{ int keylen; int dlen; @@ -784,8 +874,9 @@ static int btree_insert( unsigned char *pDBuf; pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen); pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen); - rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen); + rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, nZero, 0); } + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -817,7 +908,9 @@ static int btree_next( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeNext(pCur, &res); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -851,7 +944,9 @@ static int btree_prev( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreePrevious(pCur, &res); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -884,7 +979,9 @@ static int btree_first( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeFirst(pCur, &res); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -917,7 +1014,9 @@ static int btree_last( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeLast(pCur, &res); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; @@ -940,6 +1039,7 @@ static int btree_eof( const char **argv /* Text of each argument */ ){ BtCursor *pCur; + int rc; char zBuf[50]; if( argc!=2 ){ @@ -948,7 +1048,10 @@ static int btree_eof( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); - sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", sqlite3BtreeEof(pCur)); + sqlite3BtreeEnter(pCur->pBtree); + rc = sqlite3BtreeEof(pCur); + sqlite3BtreeLeave(pCur->pBtree); + sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", rc); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; } @@ -975,7 +1078,9 @@ static int btree_keysize( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); sqlite3BtreeKeySize(pCur, (i64*)&n); + sqlite3BtreeLeave(pCur->pBtree); sqlite3_snprintf(sizeof(zBuf),zBuf, "%llu", n); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; @@ -1003,22 +1108,25 @@ static int btree_key( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); sqlite3BtreeKeySize(pCur, (i64*)&n); if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ char zBuf2[60]; sqlite3_snprintf(sizeof(zBuf2),zBuf2, "%llu", n); Tcl_AppendResult(interp, zBuf2, 0); }else{ - zBuf = malloc( n+1 ); + zBuf = sqlite3_malloc( n+1 ); rc = sqlite3BtreeKey(pCur, 0, n, zBuf); if( rc ){ + sqlite3BtreeLeave(pCur->pBtree); Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; } zBuf[n] = 0; Tcl_AppendResult(interp, zBuf, 0); - free(zBuf); + sqlite3_free(zBuf); } + sqlite3BtreeLeave(pCur->pBtree); return SQLITE_OK; } @@ -1044,20 +1152,23 @@ static int btree_data( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); if( argc==2 ){ sqlite3BtreeDataSize(pCur, &n); }else{ n = atoi(argv[2]); } - zBuf = malloc( n+1 ); + zBuf = sqlite3_malloc( n+1 ); rc = sqlite3BtreeData(pCur, 0, n, zBuf); + sqlite3BtreeLeave(pCur->pBtree); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); + sqlite3_free(zBuf); return TCL_ERROR; } zBuf[n] = 0; Tcl_AppendResult(interp, zBuf, 0); - free(zBuf); + sqlite3_free(zBuf); return SQLITE_OK; } @@ -1087,6 +1198,7 @@ static int btree_fetch_key( } pCur = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; + sqlite3BtreeEnter(pCur->pBtree); sqlite3BtreeKeySize(pCur, (i64*)&nKey); zBuf = sqlite3BtreeKeyFetch(pCur, &amt); if( zBuf && amt>=n ){ @@ -1096,6 +1208,7 @@ static int btree_fetch_key( zStatic[nKey] = 0; Tcl_AppendResult(interp, zStatic, 0); } + sqlite3BtreeLeave(pCur->pBtree); return TCL_OK; } @@ -1125,6 +1238,7 @@ static int btree_fetch_data( } pCur = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &n) ) return TCL_ERROR; + sqlite3BtreeEnter(pCur->pBtree); sqlite3BtreeDataSize(pCur, &nData); zBuf = sqlite3BtreeDataFetch(pCur, &amt); if( zBuf && amt>=n ){ @@ -1134,6 +1248,7 @@ static int btree_fetch_data( zStatic[nData] = 0; Tcl_AppendResult(interp, zStatic, 0); } + sqlite3BtreeLeave(pCur->pBtree); return TCL_OK; } @@ -1159,12 +1274,14 @@ static int btree_payload_size( return TCL_ERROR; } pCur = sqlite3TextToPtr(argv[1]); + sqlite3BtreeEnter(pCur->pBtree); if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){ n1 = 0; }else{ sqlite3BtreeKeySize(pCur, (i64*)&n1); } sqlite3BtreeDataSize(pCur, (u32*)&n2); + sqlite3BtreeLeave(pCur->pBtree); sqlite3_snprintf(sizeof(zBuf),zBuf, "%d", (int)(n1+n2)); Tcl_AppendResult(interp, zBuf, 0); return SQLITE_OK; @@ -1186,8 +1303,8 @@ static int btree_payload_size( ** aResult[7] = Header size in bytes ** aResult[8] = Local payload size ** aResult[9] = Parent page number +** aResult[10]= Page number of the first overflow page */ -#ifdef SQLITE_DEBUG static int btree_cursor_info( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ @@ -1198,7 +1315,7 @@ static int btree_cursor_info( int rc; int i, j; int up; - int aResult[10]; + int aResult[11]; char zBuf[400]; if( argc!=2 && argc!=3 ){ @@ -1212,9 +1329,11 @@ static int btree_cursor_info( }else{ up = 0; } + sqlite3BtreeEnter(pCur->pBtree); rc = sqlite3BtreeCursorInfo(pCur, aResult, up); if( rc ){ Tcl_AppendResult(interp, errorName(rc), 0); + sqlite3BtreeLeave(pCur->pBtree); return TCL_ERROR; } j = 0; @@ -1222,10 +1341,86 @@ static int btree_cursor_info( sqlite3_snprintf(40,&zBuf[j]," %d", aResult[i]); j += strlen(&zBuf[j]); } + sqlite3BtreeLeave(pCur->pBtree); Tcl_AppendResult(interp, &zBuf[1], 0); return SQLITE_OK; } -#endif + +/* +** Copied from btree.c: +*/ +static u32 t4Get4byte(unsigned char *p){ + return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3]; +} + +/* +** btree_ovfl_info BTREE CURSOR +** +** Given a cursor, return the sequence of pages number that form the +** overflow pages for the data of the entry that the cursor is point +** to. +*/ +static int btree_ovfl_info( + void *NotUsed, + Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ + int argc, /* Number of arguments */ + const char **argv /* Text of each argument */ +){ + Btree *pBt; + BtCursor *pCur; + Pager *pPager; + int rc; + int n; + int dataSize; + u32 pgno; + void *pPage; + int aResult[11]; + char zElem[100]; + Tcl_DString str; + + if( argc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], + " BTREE CURSOR", 0); + return TCL_ERROR; + } + pBt = sqlite3TextToPtr(argv[1]); + pCur = sqlite3TextToPtr(argv[2]); + if( (*(void**)pCur) != (void*)pBt ){ + Tcl_AppendResult(interp, "Cursor ", argv[2], " does not belong to btree ", + argv[1], 0); + return TCL_ERROR; + } + sqlite3BtreeEnter(pBt); + pPager = sqlite3BtreePager(pBt); + rc = sqlite3BtreeCursorInfo(pCur, aResult, 0); + if( rc ){ + Tcl_AppendResult(interp, errorName(rc), 0); + sqlite3BtreeLeave(pBt); + return TCL_ERROR; + } + dataSize = pBt->pBt->usableSize; + Tcl_DStringInit(&str); + n = aResult[6] - aResult[8]; + n = (n + dataSize - 1)/dataSize; + pgno = (u32)aResult[10]; + while( pgno && n-- ){ + DbPage *pDbPage; + sprintf(zElem, "%d", pgno); + Tcl_DStringAppendElement(&str, zElem); + if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){ + Tcl_DStringFree(&str); + Tcl_AppendResult(interp, "unable to get page ", zElem, 0); + sqlite3BtreeLeave(pBt); + return TCL_ERROR; + } + pPage = sqlite3PagerGetData(pDbPage); + pgno = t4Get4byte((unsigned char*)pPage); + sqlite3PagerUnref(pDbPage); + } + sqlite3BtreeLeave(pBt); + Tcl_DStringResult(interp, &str); + return SQLITE_OK; +} /* ** The command is provided for the purpose of setting breakpoints. @@ -1348,10 +1543,11 @@ static int btree_from_db( Tcl_CmdInfo info; sqlite3 *db; Btree *pBt; + int iDb = 0; - if( argc!=2 ){ + if( argc!=2 && argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], - " DB-HANDLE\"", 0); + " DB-HANDLE ?N?\"", 0); return TCL_ERROR; } @@ -1359,10 +1555,14 @@ static int btree_from_db( Tcl_AppendResult(interp, "No such db-handle: \"", argv[1], "\"", 0); return TCL_ERROR; } + if( argc==3 ){ + iDb = atoi(argv[2]); + } + db = *((sqlite3 **)info.objClientData); assert( db ); - pBt = db->aDb[0].pBt; + pBt = db->aDb[iDb].pBt; sqlite3_snprintf(sizeof(zBuf), zBuf, "%p", pBt); Tcl_SetResult(interp, zBuf, TCL_VOLATILE); return TCL_OK; @@ -1390,7 +1590,13 @@ static int btree_set_cache_size( } pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &nCache) ) return TCL_ERROR; + + sqlite3_mutex_enter(pBt->db->mutex); + sqlite3BtreeEnter(pBt); sqlite3BtreeSetCacheSize(pBt, nCache); + sqlite3BtreeLeave(pBt); + sqlite3_mutex_leave(pBt->db->mutex); + return TCL_OK; } @@ -1441,18 +1647,15 @@ int Sqlitetest3_Init(Tcl_Interp *interp){ { "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement }, { "btree_from_db", (Tcl_CmdProc*)btree_from_db }, { "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size }, -#ifdef SQLITE_DEBUG { "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info }, + { "btree_ovfl_info", (Tcl_CmdProc*)btree_ovfl_info }, { "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list }, -#endif }; int i; for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); } - Tcl_LinkVar(interp, "pager_refinfo_enable", (char*)&pager3_refinfo_enable, - TCL_LINK_INT); Tcl_LinkVar(interp, "btree_trace", (char*)&sqlite3_btree_trace, TCL_LINK_INT); |
