Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add the sqlite3_unlock_notify() API. (CVS 6348) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
b649a6cc5bfefddd6a04b1183647d292 |
User & Date: | danielk1977 2009-03-16 13:19:36.000 |
Context
2009-03-16
| ||
13:37 | Additional hyperlinks in the sqlite3_unlock_notify() documentation. (CVS 6349) (check-in: 4dae5f6ed1 user: drh tags: trunk) | |
13:19 | Add the sqlite3_unlock_notify() API. (CVS 6348) (check-in: b649a6cc5b user: danielk1977 tags: trunk) | |
12:30 | Bump the version number to 3.6.12. (CVS 6347) (check-in: 2fcccca3e5 user: drh tags: trunk) | |
Changes
Changes to main.mk.
︙ | ︙ | |||
55 56 57 58 59 60 61 | fts3.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \ fts3_tokenizer.o fts3_tokenizer1.o \ func.o global.o hash.o \ icu.o insert.o journal.o legacy.o loadext.o \ main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \ memjournal.o \ mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \ | | | 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | fts3.o fts3_expr.o fts3_hash.o fts3_icu.o fts3_porter.o \ fts3_tokenizer.o fts3_tokenizer1.o \ func.o global.o hash.o \ icu.o insert.o journal.o legacy.o loadext.o \ main.o malloc.o mem0.o mem1.o mem2.o mem3.o mem5.o \ memjournal.o \ mutex.o mutex_noop.o mutex_os2.o mutex_unix.o mutex_w32.o \ notify.o opcodes.o os.o os_os2.o os_unix.o os_win.o \ pager.o parse.o pcache.o pcache1.o pragma.o prepare.o printf.o \ random.o resolve.o rowset.o rtree.o select.o status.o \ table.o tokenize.o trigger.o \ update.o util.o vacuum.o \ vdbe.o vdbeapi.o vdbeaux.o vdbeblob.o vdbemem.o \ walker.o where.o utf.o vtab.o |
︙ | ︙ | |||
108 109 110 111 112 113 114 115 116 117 118 119 120 121 | $(TOP)/src/memjournal.c \ $(TOP)/src/mutex.c \ $(TOP)/src/mutex.h \ $(TOP)/src/mutex_noop.c \ $(TOP)/src/mutex_os2.c \ $(TOP)/src/mutex_unix.c \ $(TOP)/src/mutex_w32.c \ $(TOP)/src/os.c \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ $(TOP)/src/os_os2.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ $(TOP)/src/pager.c \ | > | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | $(TOP)/src/memjournal.c \ $(TOP)/src/mutex.c \ $(TOP)/src/mutex.h \ $(TOP)/src/mutex_noop.c \ $(TOP)/src/mutex_os2.c \ $(TOP)/src/mutex_unix.c \ $(TOP)/src/mutex_w32.c \ $(TOP)/src/notify.c \ $(TOP)/src/os.c \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ $(TOP)/src/os_os2.c \ $(TOP)/src/os_unix.c \ $(TOP)/src/os_win.c \ $(TOP)/src/pager.c \ |
︙ | ︙ |
Changes to src/backup.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_backup_XXX() ** API functions and the related features. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_backup_XXX() ** API functions and the related features. ** ** $Id: backup.c,v 1.13 2009/03/16 13:19:36 danielk1977 Exp $ */ #include "sqliteInt.h" #include "btreeInt.h" /* Macro to find the minimum of two numeric values. */ #ifndef MIN |
︙ | ︙ | |||
288 289 290 291 292 293 294 | Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */ Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */ int ii; /* Iterator variable */ int nSrcPage = -1; /* Size of source db in pages */ int bCloseTrans = 0; /* True if src db requires unlocking */ /* If the source pager is currently in a write-transaction, return | | | | 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */ Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */ int ii; /* Iterator variable */ int nSrcPage = -1; /* Size of source db in pages */ int bCloseTrans = 0; /* True if src db requires unlocking */ /* If the source pager is currently in a write-transaction, return ** SQLITE_BUSY immediately. */ if( p->pDestDb && p->pSrc->pBt->inTransaction==TRANS_WRITE ){ rc = SQLITE_BUSY; }else{ rc = SQLITE_OK; } /* Lock the destination database, if it is not locked already. */ if( SQLITE_OK==rc && p->bDestLocked==0 && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2)) |
︙ | ︙ |
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: btree.c,v 1.573 2009/03/16 13:19:36 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. ** Including a description of file format and an overview of operation. */ #include "btreeInt.h" |
︙ | ︙ | |||
105 106 107 108 109 110 111 | if( !p->sharable ){ return SQLITE_OK; } /* If some other connection is holding an exclusive lock, the ** requested lock may not be obtained. */ | | > | | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | if( !p->sharable ){ return SQLITE_OK; } /* If some other connection is holding an exclusive lock, the ** requested lock may not be obtained. */ if( pBt->pWriter!=p && pBt->isExclusive ){ sqlite3ConnectionBlocked(p->db, pBt->pWriter->db); return SQLITE_LOCKED_SHAREDCACHE; } /* This (along with setSharedCacheTableLock()) is where ** the ReadUncommitted flag is dealt with. ** If the caller is querying for a read-lock on any table ** other than the sqlite_master table (table 1) and if the ReadUncommitted ** flag is set, then the lock granted even if there are write-locks |
︙ | ︙ | |||
133 134 135 136 137 138 139 | 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK || iTab==MASTER_ROOT ){ for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ if( pIter->pBtree!=p && pIter->iTable==iTab && (pIter->eLock!=eLock || eLock!=READ_LOCK) ){ | > > > > > | | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | 0==(p->db->flags&SQLITE_ReadUncommitted) || eLock==WRITE_LOCK || iTab==MASTER_ROOT ){ for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ if( pIter->pBtree!=p && pIter->iTable==iTab && (pIter->eLock!=eLock || eLock!=READ_LOCK) ){ sqlite3ConnectionBlocked(p->db, pIter->pBtree->db); if( eLock==WRITE_LOCK ){ assert( p==pBt->pWriter ); pBt->isPending = 1; } return SQLITE_LOCKED_SHAREDCACHE; } } } return SQLITE_OK; } #endif /* !SQLITE_OMIT_SHARED_CACHE */ |
︙ | ︙ | |||
229 230 231 232 233 234 235 | BtLock **ppIter = &pBt->pLock; assert( sqlite3BtreeHoldsMutex(p) ); assert( p->sharable || 0==*ppIter ); while( *ppIter ){ BtLock *pLock = *ppIter; | | > | > | > > > > > > > > > > > > | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | BtLock **ppIter = &pBt->pLock; assert( sqlite3BtreeHoldsMutex(p) ); assert( p->sharable || 0==*ppIter ); while( *ppIter ){ BtLock *pLock = *ppIter; assert( pBt->isExclusive==0 || pBt->pWriter==pLock->pBtree ); if( pLock->pBtree==p ){ *ppIter = pLock->pNext; sqlite3_free(pLock); }else{ ppIter = &pLock->pNext; } } assert( pBt->isPending==0 || pBt->pWriter ); if( pBt->pWriter==p ){ pBt->pWriter = 0; pBt->isExclusive = 0; pBt->isPending = 0; }else if( pBt->nTransaction==2 ){ /* This function is called when connection p is concluding its ** transaction. If there currently exists a writer, and p is not ** that writer, then the number of locks held by connections other ** than the writer must be about to drop to zero. In this case ** set the isPending flag to 0. ** ** If there is not currently a writer, then BtShared.isPending must ** be zero already. So this next line is harmless in that case. */ pBt->isPending = 0; } } #endif /* SQLITE_OMIT_SHARED_CACHE */ static void releasePage(MemPage *pPage); /* Forward reference */ /* |
︙ | ︙ | |||
2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 | ** of A's read lock. A tries to promote to reserved but is blocked by B. ** One or the other of the two processes must give way or there can be ** no progress. By returning SQLITE_BUSY and not invoking the busy callback ** when A already has a read lock, we encourage A to give up and let B ** proceed. */ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ BtShared *pBt = p->pBt; int rc = SQLITE_OK; sqlite3BtreeEnter(p); pBt->db = p->db; btreeIntegrity(p); | > | 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 | ** of A's read lock. A tries to promote to reserved but is blocked by B. ** One or the other of the two processes must give way or there can be ** no progress. By returning SQLITE_BUSY and not invoking the busy callback ** when A already has a read lock, we encourage A to give up and let B ** proceed. */ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ sqlite3 *pBlock = 0; BtShared *pBt = p->pBt; int rc = SQLITE_OK; sqlite3BtreeEnter(p); pBt->db = p->db; btreeIntegrity(p); |
︙ | ︙ | |||
2069 2070 2071 2072 2073 2074 2075 2076 2077 | /* Write transactions are not possible on a read-only database */ if( pBt->readOnly && wrflag ){ rc = SQLITE_READONLY; goto trans_begun; } /* If another database handle has already opened a write transaction ** on this shared-btree structure and a second write transaction is | > | | < < < | < | | | > > > > > | 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 | /* Write transactions are not possible on a read-only database */ if( pBt->readOnly && wrflag ){ rc = SQLITE_READONLY; goto trans_begun; } #ifndef SQLITE_OMIT_SHARED_CACHE /* If another database handle has already opened a write transaction ** on this shared-btree structure and a second write transaction is ** requested, return SQLITE_LOCKED. */ if( (wrflag && pBt->inTransaction==TRANS_WRITE) || pBt->isPending ){ pBlock = pBt->pWriter->db; }else if( wrflag>1 ){ BtLock *pIter; for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ if( pIter->pBtree!=p ){ pBlock = pIter->pBtree->db; break; } } } if( pBlock ){ sqlite3ConnectionBlocked(p->db, pBlock); rc = SQLITE_LOCKED_SHAREDCACHE; goto trans_begun; } #endif do { if( pBt->pPage1==0 ){ do{ rc = lockBtree(pBt); }while( pBt->pPage1==0 && rc==SQLITE_OK ); |
︙ | ︙ | |||
2125 2126 2127 2128 2129 2130 2131 | pBt->nTransaction++; } p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); if( p->inTrans>pBt->inTransaction ){ pBt->inTransaction = p->inTrans; } #ifndef SQLITE_OMIT_SHARED_CACHE | | | > | | 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 | pBt->nTransaction++; } p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); if( p->inTrans>pBt->inTransaction ){ pBt->inTransaction = p->inTrans; } #ifndef SQLITE_OMIT_SHARED_CACHE if( wrflag ){ assert( !pBt->pWriter ); pBt->pWriter = p; pBt->isExclusive = (wrflag>1); } #endif } trans_begun: if( rc==SQLITE_OK && wrflag ){ |
︙ | ︙ | |||
2936 2937 2938 2939 2940 2941 2942 | assert( sqlite3BtreeHoldsMutex(p) ); assert( wrFlag==0 || wrFlag==1 ); if( wrFlag ){ assert( !pBt->readOnly ); if( NEVER(pBt->readOnly) ){ return SQLITE_READONLY; } | | > > | | 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 | assert( sqlite3BtreeHoldsMutex(p) ); assert( wrFlag==0 || wrFlag==1 ); if( wrFlag ){ assert( !pBt->readOnly ); if( NEVER(pBt->readOnly) ){ return SQLITE_READONLY; } rc = checkForReadConflicts(p, iTable, 0, 0); if( rc!=SQLITE_OK ){ assert( rc==SQLITE_LOCKED_SHAREDCACHE ); return rc; } } if( pBt->pPage1==0 ){ rc = lockBtreeWithRetry(p); if( rc!=SQLITE_OK ){ return rc; |
︙ | ︙ | |||
5964 5965 5966 5967 5968 5969 5970 | if( p->eState!=CURSOR_VALID ) continue; if( p->wrFlag==0 #ifndef SQLITE_OMIT_INCRBLOB || p->isIncrblobHandle #endif ){ sqlite3 *dbOther = p->pBtree->db; | | | > | | 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 | if( p->eState!=CURSOR_VALID ) continue; if( p->wrFlag==0 #ifndef SQLITE_OMIT_INCRBLOB || p->isIncrblobHandle #endif ){ sqlite3 *dbOther = p->pBtree->db; assert(dbOther); if( dbOther!=db && (dbOther->flags & SQLITE_ReadUncommitted)==0 ){ sqlite3ConnectionBlocked(db, dbOther); return SQLITE_LOCKED_SHAREDCACHE; } } } return SQLITE_OK; } /* |
︙ | ︙ | |||
6003 6004 6005 6006 6007 6008 6009 | unsigned char *oldCell; unsigned char *newCell = 0; assert( cursorHoldsMutex(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( !pBt->readOnly ); assert( pCur->wrFlag ); | | > | > > | 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 | unsigned char *oldCell; unsigned char *newCell = 0; assert( cursorHoldsMutex(pCur) ); assert( pBt->inTransaction==TRANS_WRITE ); assert( !pBt->readOnly ); assert( pCur->wrFlag ); rc = checkForReadConflicts(pCur->pBtree, pCur->pgnoRoot, pCur, nKey); if( rc ){ /* The table pCur points to has a read lock */ assert( rc==SQLITE_LOCKED_SHAREDCACHE ); return rc; } if( pCur->eState==CURSOR_FAULT ){ return pCur->skip; } /* Save the positions of any other cursors open on this table */ sqlite3BtreeClearCursor(pCur); |
︙ | ︙ | |||
6100 6101 6102 6103 6104 6105 6106 | if( pCur->eState==CURSOR_FAULT ){ return pCur->skip; } if( NEVER(pCur->aiIdx[pCur->iPage]>=pPage->nCell) ){ return SQLITE_ERROR; /* The cursor is not pointing to anything */ } assert( pCur->wrFlag ); | | < | | > > | 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 | if( pCur->eState==CURSOR_FAULT ){ return pCur->skip; } if( NEVER(pCur->aiIdx[pCur->iPage]>=pPage->nCell) ){ return SQLITE_ERROR; /* The cursor is not pointing to anything */ } assert( pCur->wrFlag ); rc = checkForReadConflicts(p, pCur->pgnoRoot, pCur, pCur->info.nKey); if( rc!=SQLITE_OK ){ /* The table pCur points to has a read lock */ assert( rc==SQLITE_LOCKED_SHAREDCACHE ); return rc; } /* Restore the current cursor position (a no-op if the cursor is not in ** CURSOR_REQUIRESEEK state) and save the positions of any other cursors ** open on the same table. Then call sqlite3PagerWrite() on the page ** that the entry will be deleted from. */ |
︙ | ︙ | |||
6534 6535 6536 6537 6538 6539 6540 | /* It is illegal to drop a table if any cursors are open on the ** database. This is because in auto-vacuum mode the backend may ** need to move another root-page to fill a gap left by the deleted ** root page. If an open cursor was using this page a problem would ** occur. */ if( pBt->pCursor ){ | > | | 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 | /* It is illegal to drop a table if any cursors are open on the ** database. This is because in auto-vacuum mode the backend may ** need to move another root-page to fill a gap left by the deleted ** root page. If an open cursor was using this page a problem would ** occur. */ if( pBt->pCursor ){ sqlite3ConnectionBlocked(p->db, pBt->pCursor->pBtree->db); return SQLITE_LOCKED_SHAREDCACHE; } rc = sqlite3BtreeGetPage(pBt, (Pgno)iTable, &pPage, 0); if( rc ) return rc; rc = sqlite3BtreeClearTable(p, iTable, 0); if( rc ){ releasePage(pPage); |
︙ | ︙ | |||
7374 7375 7376 7377 7378 7379 7380 | pBt->xFreeSchema = xFree; } sqlite3BtreeLeave(p); return pBt->pSchema; } /* | | | > | > | 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 | pBt->xFreeSchema = xFree; } sqlite3BtreeLeave(p); return pBt->pSchema; } /* ** Return SQLITE_LOCKED_SHAREDCACHE if another user of the same shared ** btree as the argument handle holds an exclusive lock on the ** sqlite_master table. Otherwise SQLITE_OK. */ int sqlite3BtreeSchemaLocked(Btree *p){ int rc; assert( sqlite3_mutex_held(p->db->mutex) ); sqlite3BtreeEnter(p); rc = querySharedCacheTableLock(p, MASTER_ROOT, READ_LOCK); assert( rc==SQLITE_OK || rc==SQLITE_LOCKED_SHAREDCACHE ); sqlite3BtreeLeave(p); return rc; } #ifndef SQLITE_OMIT_SHARED_CACHE /* |
︙ | ︙ | |||
7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 | ** Argument pCsr must be a cursor opened for writing on an ** INTKEY table currently pointing at a valid table entry. ** This function modifies the data stored as part of that entry. ** Only the data content may only be modified, it is not possible ** to change the length of the data stored. */ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ assert( cursorHoldsMutex(pCsr) ); assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); assert(pCsr->isIncrblobHandle); restoreCursorPosition(pCsr); assert( pCsr->eState!=CURSOR_REQUIRESEEK ); if( pCsr->eState!=CURSOR_VALID ){ return SQLITE_ABORT; } /* Check some preconditions: ** (a) the cursor is open for writing, ** (b) there is no read-lock on the table being modified and ** (c) the cursor points at a valid row of an intKey table. */ if( !pCsr->wrFlag ){ return SQLITE_READONLY; } assert( !pCsr->pBt->readOnly && pCsr->pBt->inTransaction==TRANS_WRITE ); | > > | > | > > | 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 | ** Argument pCsr must be a cursor opened for writing on an ** INTKEY table currently pointing at a valid table entry. ** This function modifies the data stored as part of that entry. ** Only the data content may only be modified, it is not possible ** to change the length of the data stored. */ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){ int rc; assert( cursorHoldsMutex(pCsr) ); assert( sqlite3_mutex_held(pCsr->pBtree->db->mutex) ); assert(pCsr->isIncrblobHandle); restoreCursorPosition(pCsr); assert( pCsr->eState!=CURSOR_REQUIRESEEK ); if( pCsr->eState!=CURSOR_VALID ){ return SQLITE_ABORT; } /* Check some preconditions: ** (a) the cursor is open for writing, ** (b) there is no read-lock on the table being modified and ** (c) the cursor points at a valid row of an intKey table. */ if( !pCsr->wrFlag ){ return SQLITE_READONLY; } assert( !pCsr->pBt->readOnly && pCsr->pBt->inTransaction==TRANS_WRITE ); rc = checkForReadConflicts(pCsr->pBtree, pCsr->pgnoRoot, pCsr, 0); if( rc!=SQLITE_OK ){ /* The table pCur points to has a read lock */ assert( rc==SQLITE_LOCKED_SHAREDCACHE ); return rc; } if( pCsr->eState==CURSOR_INVALID || !pCsr->apPage[pCsr->iPage]->intKey ){ return SQLITE_ERROR; } return accessPayload(pCsr, offset, amt, (unsigned char *)z, 0, 1); } |
︙ | ︙ |
Changes to src/btreeInt.h.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** $Id: btreeInt.h,v 1.43 2009/03/16 13:19:36 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. |
︙ | ︙ | |||
352 353 354 355 356 357 358 359 360 361 362 363 364 365 | ** ** Fields in this structure are accessed under the BtShared.mutex ** mutex, except for nRef and pNext which are accessed under the ** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field ** may not be modified once it is initially set as long as nRef>0. ** The pSchema field may be set once under BtShared.mutex and ** thereafter is unchanged as long as nRef>0. */ struct BtShared { Pager *pPager; /* The page cache */ sqlite3 *db; /* Database connection currently using this Btree */ BtCursor *pCursor; /* A list of all open cursors */ MemPage *pPage1; /* First page of the database */ u8 inStmt; /* True if we are in a statement subtransaction */ | > > > > > > > > > > > > > > > > > > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | ** ** Fields in this structure are accessed under the BtShared.mutex ** mutex, except for nRef and pNext which are accessed under the ** global SQLITE_MUTEX_STATIC_MASTER mutex. The pPager field ** may not be modified once it is initially set as long as nRef>0. ** The pSchema field may be set once under BtShared.mutex and ** thereafter is unchanged as long as nRef>0. ** ** isPending: ** ** If a BtShared client fails to obtain a write-lock on a database ** table (because there exists one or more read-locks on the table), ** the shared-cache enters 'pending-lock' state and isPending is ** set to true. ** ** The shared-cache leaves the 'pending lock' state when either of ** the following occur: ** ** 1) The current writer (BtShared.pWriter) concludes its transaction, OR ** 2) The number of locks held by other connections drops to zero. ** ** while in the 'pending-lock' state, no connection may start a new ** transaction. ** ** This feature is included to help prevent writer-starvation. */ struct BtShared { Pager *pPager; /* The page cache */ sqlite3 *db; /* Database connection currently using this Btree */ BtCursor *pCursor; /* A list of all open cursors */ MemPage *pPage1; /* First page of the database */ u8 inStmt; /* True if we are in a statement subtransaction */ |
︙ | ︙ | |||
381 382 383 384 385 386 387 | void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */ Bitvec *pHasContent; /* Set of pages moved to free-list this transaction */ #ifndef SQLITE_OMIT_SHARED_CACHE int nRef; /* Number of references to this structure */ BtShared *pNext; /* Next on a list of sharable BtShared structs */ BtLock *pLock; /* List of locks held on this shared-btree struct */ | > | > | 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ sqlite3_mutex *mutex; /* Non-recursive mutex required to access this struct */ Bitvec *pHasContent; /* Set of pages moved to free-list this transaction */ #ifndef SQLITE_OMIT_SHARED_CACHE int nRef; /* Number of references to this structure */ BtShared *pNext; /* Next on a list of sharable BtShared structs */ BtLock *pLock; /* List of locks held on this shared-btree struct */ Btree *pWriter; /* Btree with currently open write transaction */ u8 isExclusive; /* True if pWriter has an EXCLUSIVE lock on the db */ u8 isPending; /* If waiting for read-locks to clear */ #endif u8 *pTmpSpace; /* BtShared.pageSize bytes of space for tmp use */ }; /* ** An instance of the following structure is used to hold information ** about a cell. The parseCellPtr() function fills in this structure |
︙ | ︙ |
Changes to src/main.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** ** $Id: main.c,v 1.531 2009/03/16 13:19:36 danielk1977 Exp $ */ #include "sqliteInt.h" #ifdef SQLITE_ENABLE_FTS3 # include "fts3.h" #endif #ifdef SQLITE_ENABLE_RTREE |
︙ | ︙ | |||
625 626 627 628 629 630 631 632 633 634 635 636 637 638 | pDb->pBt = 0; if( j!=1 ){ pDb->pSchema = 0; } } } sqlite3ResetInternalSchema(db, 0); assert( db->nDb<=2 ); assert( db->aDb==db->aDbStatic ); for(j=0; j<ArraySize(db->aFunc.a); j++){ FuncDef *pNext, *pHash, *p; for(p=db->aFunc.a[j]; p; p=pHash){ pHash = p->pHash; while( p ){ | > > > > > > | 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 | pDb->pBt = 0; if( j!=1 ){ pDb->pSchema = 0; } } } sqlite3ResetInternalSchema(db, 0); /* Tell the code in notify.c that the connection no longer holds any ** locks and does not require any further unlock-notify callbacks. */ sqlite3ConnectionClosed(db); assert( db->nDb<=2 ); assert( db->aDb==db->aDbStatic ); for(j=0; j<ArraySize(db->aFunc.a); j++){ FuncDef *pNext, *pHash, *p; for(p=db->aFunc.a[j]; p; p=pHash){ pHash = p->pHash; while( p ){ |
︙ | ︙ |
Added src/notify.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | /* ** 2009 March 3 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** ** This file contains the implementation of the sqlite3_unlock_notify() ** API method and its associated functionality. ** ** $Id: notify.c,v 1.1 2009/03/16 13:19:36 danielk1977 Exp $ */ #include "sqliteInt.h" #include "btreeInt.h" /* Omit this entire file if SQLITE_ENABLE_UNLOCK_NOTIFY is not defined. */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* ** Public interfaces: ** ** sqlite3ConnectionBlocked() ** sqlite3ConnectionUnlocked() ** sqlite3ConnectionClosed() ** sqlite3_unlock_notify() */ #define assertMutexHeld() \ assert( sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)) ) /* ** Head of a linked list of all sqlite3 objects created by this process ** for which either sqlite3.pBlockingConnection or sqlite3.pUnlockConnection ** is not NULL. This variable may only accessed while the STATIC_MASTER ** mutex is held. */ static sqlite3 *SQLITE_WSD sqlite3BlockedList = 0; #ifndef NDEBUG /* ** This function is a complex assert() that verifies the following ** properties of the blocked connections list: ** ** 1) Each entry in the list has a non-NULL value for either ** pUnlockConnection or pBlockingConnection, or both. ** ** 2) All entries in the list that share a common value for ** xUnlockNotify are grouped together. ** ** 3) If the argument db is not NULL, then none of the entries in the ** blocked connections list have pUnlockConnection or pBlockingConnection ** set to db. This is used when closing connection db. */ static void checkListProperties(sqlite3 *db){ sqlite3 *p; for(p=sqlite3BlockedList; p; p=p->pNextBlocked){ int seen = 0; sqlite3 *p2; /* Verify property (1) */ assert( p->pUnlockConnection || p->pBlockingConnection ); /* Verify property (2) */ for(p2=sqlite3BlockedList; p2!=p; p2=p2->pNextBlocked){ if( p2->xUnlockNotify==p->xUnlockNotify ) seen = 1; assert( p2->xUnlockNotify==p->xUnlockNotify || !seen ); assert( db==0 || p->pUnlockConnection!=db ); assert( db==0 || p->pBlockingConnection!=db ); } } } #else # define checkListProperties(x) #endif /* ** Remove connection db from the blocked connections list. If connection ** db is not currently a part of the list, this function is a no-op. */ static void removeFromBlockedList(sqlite3 *db){ sqlite3 **pp; assertMutexHeld(); for(pp=&sqlite3BlockedList; *pp; pp = &(*pp)->pNextBlocked){ if( *pp==db ){ *pp = (*pp)->pNextBlocked; break; } } } /* ** Add connection db to the blocked connections list. It is assumed ** that it is not already a part of the list. */ static void addToBlockedList(sqlite3 *db){ sqlite3 **pp; assertMutexHeld(); for( pp=&sqlite3BlockedList; *pp && (*pp)->xUnlockNotify!=db->xUnlockNotify; pp=&(*pp)->pNextBlocked ); db->pNextBlocked = *pp; *pp = db; } /* ** Obtain the STATIC_MASTER mutex. */ static void enterMutex(){ sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); checkListProperties(0); } /* ** Release the STATIC_MASTER mutex. */ static void leaveMutex(){ assertMutexHeld(); checkListProperties(0); sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); } /* ** Register an unlock-notify callback. */ int sqlite3_unlock_notify( sqlite3 *db, void (*xNotify)(void **, int), void *pArg ){ int rc = SQLITE_OK; sqlite3_mutex_enter(db->mutex); enterMutex(); if( 0==db->pBlockingConnection ){ /* The blocking transaction has been concluded. Or there never was a ** blocking transaction. In either case, invoke the notify callback ** immediately. */ xNotify(&pArg, 1); }else{ sqlite3 *p; for(p=db->pBlockingConnection; p && p!=db; p=p->pUnlockConnection); if( p ){ rc = SQLITE_LOCKED; /* Deadlock detected. */ }else{ db->pUnlockConnection = db->pBlockingConnection; db->xUnlockNotify = xNotify; db->pUnlockArg = pArg; removeFromBlockedList(db); addToBlockedList(db); } } leaveMutex(); assert( !db->mallocFailed ); sqlite3Error(db, rc, (rc?"database is deadlocked":0)); sqlite3_mutex_leave(db->mutex); return rc; } /* ** This function is called while stepping or preparing a statement ** associated with connection db. The operation will return SQLITE_LOCKED ** to the user because it requires a lock that will not be available ** until connection pBlocker concludes its current transaction. */ void sqlite3ConnectionBlocked(sqlite3 *db, sqlite3 *pBlocker){ enterMutex(); if( db->pBlockingConnection==0 && db->pUnlockConnection==0 ){ addToBlockedList(db); } db->pBlockingConnection = pBlocker; leaveMutex(); } /* ** The transaction opened by database db has just finished. Locks held ** by database connection db have been released. ** ** This function loops through each entry in the blocked connections ** list and does the following: ** ** 1) If the sqlite3.pBlockingConnection member of a list entry is ** set to db, then set pBlockingConnection=0. ** ** 2) If the sqlite3.pUnlockConnection member of a list entry is ** set to db, then invoke the configured unlock-notify callback and ** set pUnlockConnection=0. ** ** 3) If the two steps above mean that pBlockingConnection==0 and ** pUnlockConnection==0, remove the entry from the blocked connections ** list. */ void sqlite3ConnectionUnlocked(sqlite3 *db){ void (*xUnlockNotify)(void **, int) = 0; /* Unlock-notify cb to invoke */ int nArg = 0; /* Number of entries in aArg[] */ sqlite3 **pp; /* Iterator variable */ void *aStatic[16]; void **aArg = aStatic; void **aDyn = 0; enterMutex(); /* Enter STATIC_MASTER mutex */ /* This loop runs once for each entry in the blocked-connections list. */ for(pp=&sqlite3BlockedList; *pp; /* no-op */ ){ sqlite3 *p = *pp; /* Step 1. */ if( p->pBlockingConnection==db ){ p->pBlockingConnection = 0; } /* Step 2. */ if( p->pUnlockConnection==db ){ assert( p->xUnlockNotify ); if( p->xUnlockNotify!=xUnlockNotify && nArg!=0 ){ xUnlockNotify(aArg, nArg); nArg = 0; } sqlite3BeginBenignMalloc(); assert( aArg==aDyn || (aDyn==0 && aArg==aStatic) ); assert( nArg<=ArraySize(aStatic) || aArg==aDyn ); if( (!aDyn && nArg==ArraySize(aStatic)) || (aDyn && nArg==(sqlite3DbMallocSize(db, aDyn)/sizeof(void*))) ){ /* The aArg[] array needs to grow. */ void **pNew = (void **)sqlite3Malloc(nArg*sizeof(void *)*2); if( pNew ){ memcpy(pNew, aArg, nArg*sizeof(void *)); sqlite3_free(aDyn); aDyn = aArg = pNew; }else{ /* This occurs when the array of context pointers that need to ** be passed to the unlock-notify callback is larger than the ** aStatic[] array allocated on the stack and the attempt to ** allocate a larger array from the heap has failed. ** ** This is a difficult situation to handle. Returning an error ** code to the caller is insufficient, as even if an error code ** is returned the transaction on connection db will still be ** closed and the unlock-notify callbacks on blocked connections ** will go unissued. This might cause the application to wait ** indefinitely for an unlock-notify callback that will never ** arrive. ** ** Instead, invoke the unlock-notify callback with the context ** array already accumulated. We can then clear the array and ** begin accumulating any further context pointers without ** requiring any dynamic allocation. This is sub-optimal because ** it means that instead of one callback with a large array of ** context pointers the application will receive two or more ** callbacks with smaller arrays of context pointers, which will ** reduce the applications ability to prioritize multiple ** connections. But it is the best that can be done under the ** circumstances. */ xUnlockNotify(aArg, nArg); nArg = 0; } } sqlite3EndBenignMalloc(); aArg[nArg++] = p->pUnlockArg; xUnlockNotify = p->xUnlockNotify; p->pUnlockConnection = 0; p->xUnlockNotify = 0; p->pUnlockArg = 0; } /* Step 3. */ if( p->pBlockingConnection==0 && p->pUnlockConnection==0 ){ /* Remove connection p from the blocked connections list. */ *pp = p->pNextBlocked; p->pNextBlocked = 0; }else{ pp = &p->pNextBlocked; } } if( nArg!=0 ){ xUnlockNotify(aArg, nArg); } sqlite3_free(aDyn); leaveMutex(); /* Leave STATIC_MASTER mutex */ } /* ** This is called when the database connection passed as an argument is ** being closed. The connection is removed from the blocked list. */ void sqlite3ConnectionClosed(sqlite3 *db){ sqlite3ConnectionUnlocked(db); enterMutex(); removeFromBlockedList(db); checkListProperties(db); leaveMutex(); } #endif |
Changes to src/prepare.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_prepare() ** interface, and routines that contribute to loading the database schema ** from disk. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the implementation of the sqlite3_prepare() ** interface, and routines that contribute to loading the database schema ** from disk. ** ** $Id: prepare.c,v 1.109 2009/03/16 13:19:36 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Fill the InitData structure with an error message that indicates ** that the database is corrupt. */ |
︙ | ︙ | |||
566 567 568 569 570 571 572 | for(i=0; i<db->nDb; i++) { Btree *pBt = db->aDb[i].pBt; if( pBt ){ assert( sqlite3BtreeHoldsMutex(pBt) ); rc = sqlite3BtreeSchemaLocked(pBt); if( rc ){ const char *zDb = db->aDb[i].zName; | | | | 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 | for(i=0; i<db->nDb; i++) { Btree *pBt = db->aDb[i].pBt; if( pBt ){ assert( sqlite3BtreeHoldsMutex(pBt) ); rc = sqlite3BtreeSchemaLocked(pBt); if( rc ){ const char *zDb = db->aDb[i].zName; sqlite3Error(db, rc, "database schema is locked: %s", zDb); (void)sqlite3SafetyOff(db); testcase( db->flags & SQLITE_ReadUncommitted ); return sqlite3ApiExit(db, rc); } } } memset(&sParse, 0, sizeof(sParse)); sParse.db = db; if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){ |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** on how SQLite interfaces are suppose to operate. ** ** The name of this file under configuration management is "sqlite.h.in". ** The makefile makes some minor changes to this file (such as inserting ** the version number) and changes its name to "sqlite3.h" as ** part of the build process. ** ** @(#) $Id: sqlite.h.in,v 1.434 2009/03/16 13:19:36 danielk1977 Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ #include <stdarg.h> /* Needed for the definition of va_list */ /* ** Make sure we can call this stuff from C++. |
︙ | ︙ | |||
378 379 380 381 382 383 384 385 386 387 388 389 390 391 | #define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8)) #define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8)) #define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8)) #define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8)) #define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8)) #define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) /* ** CAPI3REF: Flags For File Open Operations {H10230} <H11120> <H12700> ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the xOpen method of the | > > | 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 | #define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8)) #define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8)) #define SQLITE_IOERR_ACCESS (SQLITE_IOERR | (13<<8)) #define SQLITE_IOERR_CHECKRESERVEDLOCK (SQLITE_IOERR | (14<<8)) #define SQLITE_IOERR_LOCK (SQLITE_IOERR | (15<<8)) #define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8) ) /* ** CAPI3REF: Flags For File Open Operations {H10230} <H11120> <H12700> ** ** These bit values are intended for use in the ** 3rd parameter to the [sqlite3_open_v2()] interface and ** in the 4th parameter to the xOpen method of the |
︙ | ︙ | |||
5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 | sqlite3 *pSource, /* Source database handle */ const char *zSourceName /* Source database name */ ); int sqlite3_backup_step(sqlite3_backup *p, int nPage); int sqlite3_backup_finish(sqlite3_backup *p); int sqlite3_backup_remaining(sqlite3_backup *p); int sqlite3_backup_pagecount(sqlite3_backup *p); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 | sqlite3 *pSource, /* Source database handle */ const char *zSourceName /* Source database name */ ); int sqlite3_backup_step(sqlite3_backup *p, int nPage); int sqlite3_backup_finish(sqlite3_backup *p); int sqlite3_backup_remaining(sqlite3_backup *p); int sqlite3_backup_pagecount(sqlite3_backup *p); /* ** CAPI3REF: Unlock Notification ** EXPERIMENTAL ** ** When running in shared-cache mode, a database operation may fail with ** an SQLITE_LOCKED error if the required locks on the shared-cache or ** individual tables within the shared-cache cannot be obtained. See ** [SQLite Shared-Cache Mode] for a description of shared-cache locking. ** This API may be used to register a callback that SQLite will invoke ** when the connection currently holding the required lock relinquishes it. ** This API is only available if the library was compiled with the ** SQLITE_ENABLE_UNLOCK_NOTIFY C-preprocessor symbol defined. ** ** See Also: [Using the SQLite Unlock Notification Feature]. ** ** Shared-cache locks are released when a database connection concludes ** its current transaction, either by committing it or rolling it back. ** ** When a connection (known as the blocked connection) fails to obtain a ** shared-cache lock and SQLITE_LOCKED is returned to the caller, the ** identity of the database connection (the blocking connection) that ** has locked the required resource is stored internally. After an ** application receives an SQLITE_LOCKED error, it may call the ** sqlite3_unlock_notify() method with the blocked connection handle as ** the first argument to register for a callback that will be invoked ** when the blocking connections current transaction is concluded. The ** callback is invoked from within the [sqlite3_step] or [sqlite3_close] ** call that concludes the blocking connections transaction. ** ** If sqlite3_unlock_notify() is called in a multi-threaded application, ** there is a chance that the blocking connection will have already ** concluded its transaction by the time sqlite3_unlock_notify() is invoked. ** If this happens, then the specified callback is invoked immediately, ** from within the call to sqlite3_unlock_notify(). ** ** If the blocked connection is attempting to obtain a write-lock on a ** shared-cache table, and more than one other connection currently holds ** a read-lock on the same table, then SQLite arbitrarily selects one of ** the other connections to use as the blocking connection. ** ** There may be at most one unlock-notify callback registered by a ** blocked connection. If sqlite3_unlock_notify() is called when the ** blocked connection already has a registered unlock-notify callback, ** then the new callback replaces the old. If sqlite3_unlock_notify() is ** called with a NULL pointer as its second argument, then any existing ** unlock-notify callback is cancelled. The blocked connections ** unlock-notify callback may also be canceled by closing the blocked ** connection using [sqlite3_close()]. ** ** The unlock-notify callback is not reentrant. If an application invokes ** any sqlite3_xxx API functions from within an unlock-notify callback, a ** crash or deadlock may be the result. ** ** Unless deadlock is detected (see below), sqlite3_unlock_notify() always ** returns SQLITE_OK. ** ** <b>Callback Invocation Details</b> ** ** When an unlock-notify callback is registered, the application provides a ** single void* pointer that is passed to the callback when it is invoked. ** However, the signature of the callback function allows SQLite to pass ** it an array of void* context pointers. The first argument passed to ** an unlock-notify callback is a pointer to an array of void* pointers, ** and the second is the number of entries in the array. ** ** When a blocking connections transaction is concluded, there may be ** more than one blocked connection that has registered for an unlock-notify ** callback. If two or more such blocked connections have specified the ** same callback function, then instead of invoking the callback function ** multiple times, it is invoked once with the set of void* context pointers ** specified by the blocked connections bundled together into an array. ** This gives the application an opportunity to prioritize any actions ** related to the set of unblocked database connections. ** ** <b>Deadlock Detection</b> ** ** Assuming that after registering for an unlock-notify callback a ** database waits for the callback to be issued before taking any further ** action (a reasonable assumption), then using this API may cause the ** application to deadlock. For example, if connection X is waiting for ** connection Y's transaction to be concluded, and similarly connection ** Y is waiting on connection X's transaction, then neither connection ** will proceed and the system may remain deadlocked indefinitely. ** ** To avoid this scenario, the sqlite3_unlock_notify() performs deadlock ** detection. If a given call to sqlite3_unlock_notify() would put the ** system in a deadlocked state, then SQLITE_LOCKED is returned and no ** unlock-notify callback is registered. The system is said to be in ** a deadlocked state if connection A has registered for an unlock-notify ** callback on the conclusion of connection B's transaction, and connection ** B has itself registered for an unlock-notify callback when connection ** A's transaction is concluded. Indirect deadlock is also detected, so ** the system is also considered to be deadlocked if connection B has ** registered for an unlock-notify callback on the conclusion of connection ** C's transaction, where connection C is waiting on connection A. Any ** number of levels of indirection are allowed. ** ** <b>The "DROP TABLE" Exception</b> ** ** When a call to [sqlite3_step()] returns SQLITE_LOCKED, it is almost ** always appropriate to call sqlite3_unlock_notify(). There is however, ** one exception. When executing a "DROP TABLE" or "DROP INDEX" statement, ** SQLite checks if there are any currently executing SELECT statements ** that belong to the same connection. If there are, SQLITE_LOCKED is ** returned. In this case there is no "blocking connection", so invoking ** sqlite3_unlock_notify() results in the unlock-notify callback being ** invoked immediately. If the application then re-attempts the "DROP TABLE" ** or "DROP INDEX" query, an infinite loop might be the result. ** ** One way around this problem is to check the extended error code returned ** by an sqlite3_step() call. If there is a blocking connection, then the ** extended error code is set to SQLITE_LOCKED_SHAREDCACHE. Otherwise, in ** the special "DROP TABLE/INDEX" case, the extended error code is just ** SQLITE_LOCKED. */ int sqlite3_unlock_notify( sqlite3 *pBlocked, /* Waiting connection */ void (*xNotify)(void **apArg, int nArg), /* Callback function to invoke */ void *pNotifyArg /* Argument to pass to xNotify */ ); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double #endif #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.841 2009/03/16 13:19:36 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** Include the configuration header output by 'configure' if we're using the ** autoconf-based build |
︙ | ︙ | |||
804 805 806 807 808 809 810 811 812 813 814 815 816 817 | Db aDbStatic[2]; /* Static space for the 2 default backends */ #ifdef SQLITE_SSE sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */ #endif Savepoint *pSavepoint; /* List of active savepoints */ int nSavepoint; /* Number of non-transaction savepoints */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ }; /* ** A macro to discover the encoding of a database. */ #define ENC(db) ((db)->aDb[0].pSchema->enc) | > > > > > > > > > > > | 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 | Db aDbStatic[2]; /* Static space for the 2 default backends */ #ifdef SQLITE_SSE sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */ #endif Savepoint *pSavepoint; /* List of active savepoints */ int nSavepoint; /* Number of non-transaction savepoints */ u8 isTransactionSavepoint; /* True if the outermost savepoint is a TS */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY /* The following variables are all protected by the STATIC_MASTER ** mutex, not by sqlite3.mutex. They are used by code in notify.c. */ sqlite3 *pBlockingConnection; /* Connection that caused SQLITE_LOCKED */ sqlite3 *pUnlockConnection; /* Connection to watch for unlock */ void *pUnlockArg; /* Argument to xUnlockNotify */ void (*xUnlockNotify)(void **, int); /* Unlock notify callback */ sqlite3 *pNextBlocked; /* Next in list of all blocked connections */ #endif }; /* ** A macro to discover the encoding of a database. */ #define ENC(db) ((db)->aDb[0].pSchema->enc) |
︙ | ︙ | |||
2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 | #define sqlite3ExprSetHeight(x,y) #define sqlite3SelectExprHeight(x) 0 #define sqlite3ExprCheckHeight(x,y) #endif u32 sqlite3Get4byte(const u8*); void sqlite3Put4byte(u8*, u32); #ifdef SQLITE_SSE #include "sseInt.h" #endif #ifdef SQLITE_DEBUG void sqlite3ParserTrace(FILE*, char *); | > > > > > > > > > > > | 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 | #define sqlite3ExprSetHeight(x,y) #define sqlite3SelectExprHeight(x) 0 #define sqlite3ExprCheckHeight(x,y) #endif u32 sqlite3Get4byte(const u8*); void sqlite3Put4byte(u8*, u32); #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY void sqlite3ConnectionBlocked(sqlite3 *, sqlite3 *); void sqlite3ConnectionUnlocked(sqlite3 *db); void sqlite3ConnectionClosed(sqlite3 *db); #else #define sqlite3ConnectionBlocked(x,y) #define sqlite3ConnectionUnlocked(x) #define sqlite3ConnectionClosed(x) #endif #ifdef SQLITE_SSE #include "sseInt.h" #endif #ifdef SQLITE_DEBUG void sqlite3ParserTrace(FILE*, char *); |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of SQLite. ** ** $Id: tclsqlite.c,v 1.238 2009/03/16 13:19:36 danielk1977 Exp $ */ #include "tcl.h" #include <errno.h> /* ** Some additional include files are needed if this file is not ** appended to the amalgamation. |
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 116 117 118 | char *zProgress; /* The progress callback routine */ char *zAuth; /* The authorization callback routine */ int disableAuth; /* Disable the authorizer if it exists */ char *zNull; /* Text to substitute for an SQL NULL value */ SqlFunc *pFunc; /* List of SQL functions */ Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ SqlCollate *pCollate; /* List of SQL collation functions */ int rc; /* Return code of most recent sqlite3_exec() */ Tcl_Obj *pCollateNeeded; /* Collation needed script */ SqlPreparedStmt *stmtList; /* List of prepared statements*/ SqlPreparedStmt *stmtLast; /* Last statement in the list */ int maxStmt; /* The next maximum number of stmtList */ int nStmt; /* Number of statements in stmtList */ | > | 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | char *zProgress; /* The progress callback routine */ char *zAuth; /* The authorization callback routine */ int disableAuth; /* Disable the authorizer if it exists */ char *zNull; /* Text to substitute for an SQL NULL value */ SqlFunc *pFunc; /* List of SQL functions */ Tcl_Obj *pUpdateHook; /* Update hook script (if any) */ Tcl_Obj *pRollbackHook; /* Rollback hook script (if any) */ Tcl_Obj *pUnlockNotify; /* Unlock notify script (if any) */ SqlCollate *pCollate; /* List of SQL collation functions */ int rc; /* Return code of most recent sqlite3_exec() */ Tcl_Obj *pCollateNeeded; /* Collation needed script */ SqlPreparedStmt *stmtList; /* List of prepared statements*/ SqlPreparedStmt *stmtLast; /* Last statement in the list */ int maxStmt; /* The next maximum number of stmtList */ int nStmt; /* Number of statements in stmtList */ |
︙ | ︙ | |||
569 570 571 572 573 574 575 576 577 578 579 580 581 582 | static void DbRollbackHandler(void *clientData){ SqliteDb *pDb = (SqliteDb*)clientData; assert(pDb->pRollbackHook); if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){ Tcl_BackgroundError(pDb->interp); } } static void DbUpdateHandler( void *p, int op, const char *zDb, const char *zTbl, sqlite_int64 rowid | > > > > > > > > > > > > > > > > > > > > > > > > > | 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 | static void DbRollbackHandler(void *clientData){ SqliteDb *pDb = (SqliteDb*)clientData; assert(pDb->pRollbackHook); if( TCL_OK!=Tcl_EvalObjEx(pDb->interp, pDb->pRollbackHook, 0) ){ Tcl_BackgroundError(pDb->interp); } } #ifdef SQLITE_TEST static void setTestUnlockNotifyVars(Tcl_Interp *interp, int iArg, int nArg){ char zBuf[64]; sprintf(zBuf, "%d", iArg); Tcl_SetVar(interp, "sqlite_unlock_notify_arg", zBuf, TCL_GLOBAL_ONLY); sprintf(zBuf, "%d", nArg); Tcl_SetVar(interp, "sqlite_unlock_notify_argcount", zBuf, TCL_GLOBAL_ONLY); } #else #define setTestUnlockNotifyVars(x,y,z) #endif static void DbUnlockNotify(void **apArg, int nArg){ int i; for(i=0; i<nArg; i++){ const int flags = (TCL_EVAL_GLOBAL|TCL_EVAL_DIRECT); SqliteDb *pDb = (SqliteDb *)apArg[i]; setTestUnlockNotifyVars(pDb->interp, i, nArg); assert( pDb->pUnlockNotify); Tcl_EvalObjEx(pDb->interp, pDb->pUnlockNotify, flags); Tcl_DecrRefCount(pDb->pUnlockNotify); pDb->pUnlockNotify = 0; } } static void DbUpdateHandler( void *p, int op, const char *zDb, const char *zTbl, sqlite_int64 rowid |
︙ | ︙ | |||
989 990 991 992 993 994 995 | "complete", "copy", "enable_load_extension", "errorcode", "eval", "exists", "function", "incrblob", "interrupt", "last_insert_rowid", "nullvalue", "onecolumn", "profile", "progress", "rekey", "restore", "rollback_hook", "status", "timeout", "total_changes", "trace", | | < > | > | 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 | "complete", "copy", "enable_load_extension", "errorcode", "eval", "exists", "function", "incrblob", "interrupt", "last_insert_rowid", "nullvalue", "onecolumn", "profile", "progress", "rekey", "restore", "rollback_hook", "status", "timeout", "total_changes", "trace", "transaction", "unlock_notify", "update_hook", "version", 0 }; enum DB_enum { DB_AUTHORIZER, DB_BACKUP, DB_BUSY, DB_CACHE, DB_CHANGES, DB_CLOSE, DB_COLLATE, DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE, DB_COPY, DB_ENABLE_LOAD_EXTENSION, DB_ERRORCODE, DB_EVAL, DB_EXISTS, DB_FUNCTION, DB_INCRBLOB, DB_INTERRUPT, DB_LAST_INSERT_ROWID, DB_NULLVALUE, DB_ONECOLUMN, DB_PROFILE, DB_PROGRESS, DB_REKEY, DB_RESTORE, DB_ROLLBACK_HOOK, DB_STATUS, DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE, DB_TRANSACTION, DB_UNLOCK_NOTIFY, DB_UPDATE_HOOK, DB_VERSION, }; /* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */ if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); return TCL_ERROR; } |
︙ | ︙ | |||
2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 | } sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); } pDb->disableAuth--; break; } /* ** $db update_hook ?script? ** $db rollback_hook ?script? */ case DB_UPDATE_HOOK: case DB_ROLLBACK_HOOK: { | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 | } sqlite3_exec(pDb->db, "ROLLBACK", 0, 0, 0); } pDb->disableAuth--; break; } /* ** $db unlock_notify ?script? */ case DB_UNLOCK_NOTIFY: { #ifndef SQLITE_ENABLE_UNLOCK_NOTIFY Tcl_AppendResult(interp, "unlock_notify not available in this build", 0); rc = TCL_ERROR; #else if( objc!=2 && objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?SCRIPT?"); rc = TCL_ERROR; }else{ void (*xNotify)(void **, int) = 0; void *pNotifyArg = 0; if( pDb->pUnlockNotify ){ Tcl_DecrRefCount(pDb->pUnlockNotify); pDb->pUnlockNotify = 0; } if( objc==3 ){ xNotify = DbUnlockNotify; pNotifyArg = (void *)pDb; pDb->pUnlockNotify = objv[2]; Tcl_IncrRefCount(pDb->pUnlockNotify); } if( sqlite3_unlock_notify(pDb->db, xNotify, pNotifyArg) ){ Tcl_AppendResult(interp, sqlite3_errmsg(pDb->db), 0); rc = TCL_ERROR; } } #endif break; } /* ** $db update_hook ?script? ** $db rollback_hook ?script? */ case DB_UPDATE_HOOK: case DB_ROLLBACK_HOOK: { |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test1.c,v 1.348 2009/03/16 13:19:36 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> /* |
︙ | ︙ | |||
121 122 123 124 125 126 127 128 129 130 131 132 133 134 | case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; case SQLITE_PERM: zName = "SQLITE_PERM"; break; case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; case SQLITE_FULL: zName = "SQLITE_FULL"; break; | > | 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | case SQLITE_OK: zName = "SQLITE_OK"; break; case SQLITE_ERROR: zName = "SQLITE_ERROR"; break; case SQLITE_INTERNAL: zName = "SQLITE_INTERNAL"; break; case SQLITE_PERM: zName = "SQLITE_PERM"; break; case SQLITE_ABORT: zName = "SQLITE_ABORT"; break; case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break; case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; case SQLITE_READONLY: zName = "SQLITE_READONLY"; break; case SQLITE_INTERRUPT: zName = "SQLITE_INTERRUPT"; break; case SQLITE_IOERR: zName = "SQLITE_IOERR"; break; case SQLITE_CORRUPT: zName = "SQLITE_CORRUPT"; break; case SQLITE_NOTFOUND: zName = "SQLITE_NOTFOUND"; break; case SQLITE_FULL: zName = "SQLITE_FULL"; break; |
︙ | ︙ | |||
3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 | if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = sqlite3_step(pStmt); /* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */ Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); return TCL_OK; } /* ** Usage: sqlite3_column_count STMT ** ** Return the number of columns returned by the sql statement STMT. */ static int test_column_count( | > > > > > > > > > > > > > > > > > > | 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 | if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; rc = sqlite3_step(pStmt); /* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */ Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0); return TCL_OK; } static int test_sql( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3_stmt *pStmt; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; Tcl_SetResult(interp, (char *)sqlite3_sql(pStmt), TCL_VOLATILE); return TCL_OK; } /* ** Usage: sqlite3_column_count STMT ** ** Return the number of columns returned by the sql statement STMT. */ static int test_column_count( |
︙ | ︙ | |||
4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 | Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nRecyclable)); Tcl_SetObjResult(interp, pRet); return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; extern int sqlite3_interrupt_count; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 | Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nRecyclable)); Tcl_SetObjResult(interp, pRet); return TCL_OK; } static void test_unlock_notify_cb(void **aArg, int nArg){ int ii; for(ii=0; ii<nArg; ii++){ Tcl_EvalEx((Tcl_Interp *)aArg[ii], "unlock_notify", -1, TCL_EVAL_GLOBAL); } } /* ** tclcmd: sqlite3_unlock_notify db */ #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY static int test_unlock_notify( ClientData clientData, /* Unused */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; int rc; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ return TCL_ERROR; } rc = sqlite3_unlock_notify(db, test_unlock_notify_cb, (void *)interp); Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC); return TCL_OK; } #endif /* ** Register commands with the TCL interpreter. */ int Sqlitetest1_Init(Tcl_Interp *interp){ extern int sqlite3_search_count; extern int sqlite3_interrupt_count; |
︙ | ︙ | |||
4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 | { "sqlite3_finalize", test_finalize ,0 }, { "sqlite3_stmt_status", test_stmt_status ,0 }, { "sqlite3_reset", test_reset ,0 }, { "sqlite3_expired", test_expired ,0 }, { "sqlite3_transfer_bindings", test_transfer_bind ,0 }, { "sqlite3_changes", test_changes ,0 }, { "sqlite3_step", test_step ,0 }, { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, | > | 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 | { "sqlite3_finalize", test_finalize ,0 }, { "sqlite3_stmt_status", test_stmt_status ,0 }, { "sqlite3_reset", test_reset ,0 }, { "sqlite3_expired", test_expired ,0 }, { "sqlite3_transfer_bindings", test_transfer_bind ,0 }, { "sqlite3_changes", test_changes ,0 }, { "sqlite3_step", test_step ,0 }, { "sqlite3_sql", test_sql ,0 }, { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, |
︙ | ︙ | |||
4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 | { "sqlite3_table_column_metadata", test_table_column_metadata, 0 }, #endif #ifndef SQLITE_OMIT_INCRBLOB { "sqlite3_blob_read", test_blob_read, 0 }, { "sqlite3_blob_write", test_blob_write, 0 }, #endif { "pcache_stats", test_pcache_stats, 0 }, }; static int bitmask_size = sizeof(Bitmask)*8; int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; extern int sqlite3_xferopt_count; | > > > | 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 | { "sqlite3_table_column_metadata", test_table_column_metadata, 0 }, #endif #ifndef SQLITE_OMIT_INCRBLOB { "sqlite3_blob_read", test_blob_read, 0 }, { "sqlite3_blob_write", test_blob_write, 0 }, #endif { "pcache_stats", test_pcache_stats, 0 }, #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY { "sqlite3_unlock_notify", test_unlock_notify, 0 }, #endif }; static int bitmask_size = sizeof(Bitmask)*8; int i; extern int sqlite3_sync_count, sqlite3_fullsync_count; extern int sqlite3_opentemp_count; extern int sqlite3_like_count; extern int sqlite3_xferopt_count; |
︙ | ︙ |
Changes to src/test_config.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** ** This file contains code used for testing the SQLite system. ** None of the code in this file goes into a deliverable build. ** ** The focus of this file is providing the TCL testing layer ** access to compile-time constants. ** | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** ** This file contains code used for testing the SQLite system. ** None of the code in this file goes into a deliverable build. ** ** The focus of this file is providing the TCL testing layer ** access to compile-time constants. ** ** $Id: test_config.c,v 1.48 2009/03/16 13:19:36 danielk1977 Exp $ */ #include "sqliteLimit.h" #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> |
︙ | ︙ | |||
488 489 490 491 492 493 494 495 496 497 498 499 500 501 | #endif #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) Tcl_SetVar2(interp, "sqlite_options", "update_delete_limit", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "update_delete_limit", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_SECURE_DELETE Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "0", TCL_GLOBAL_ONLY); #endif | > > > > > > | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 | #endif #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) Tcl_SetVar2(interp, "sqlite_options", "update_delete_limit", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "update_delete_limit", "0", TCL_GLOBAL_ONLY); #endif #if defined(SQLITE_ENABLE_UNLOCK_NOTIFY) Tcl_SetVar2(interp, "sqlite_options", "unlock_notify", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "unlock_notify", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_SECURE_DELETE Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "secure_delete", "0", TCL_GLOBAL_ONLY); #endif |
︙ | ︙ |
Changes to src/test_thread.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** ** This file contains the implementation of some Tcl commands used to ** test that sqlite3 database handles may be concurrently accessed by ** multiple threads. Right now this only works on unix. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** ** This file contains the implementation of some Tcl commands used to ** test that sqlite3 database handles may be concurrently accessed by ** multiple threads. Right now this only works on unix. ** ** $Id: test_thread.c,v 1.11 2009/03/16 13:19:36 danielk1977 Exp $ */ #include "sqliteInt.h" #include <tcl.h> #if SQLITE_THREADSAFE |
︙ | ︙ | |||
51 52 53 54 55 56 57 58 59 60 61 62 63 64 | Tcl_Event base; /* Base class of type Tcl_Event */ char *zScript; /* The script to execute. */ Tcl_Interp *interp; /* The interpreter to execute it in. */ }; static Tcl_ObjCmdProc sqlthread_proc; static Tcl_ObjCmdProc clock_seconds_proc; int Sqlitetest1_Init(Tcl_Interp *); /* ** Handler for events of type EvalEvent. */ static int tclScriptEvent(Tcl_Event *evPtr, int flags){ int rc; | > | 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | Tcl_Event base; /* Base class of type Tcl_Event */ char *zScript; /* The script to execute. */ Tcl_Interp *interp; /* The interpreter to execute it in. */ }; static Tcl_ObjCmdProc sqlthread_proc; static Tcl_ObjCmdProc clock_seconds_proc; static Tcl_ObjCmdProc blocking_step_proc; int Sqlitetest1_Init(Tcl_Interp *); /* ** Handler for events of type EvalEvent. */ static int tclScriptEvent(Tcl_Event *evPtr, int flags){ int rc; |
︙ | ︙ | |||
102 103 104 105 106 107 108 109 110 111 112 113 114 115 | int rc; SqlThread *p = (SqlThread *)pSqlThread; extern int Sqlitetest_mutex_Init(Tcl_Interp*); interp = Tcl_CreateInterp(); Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0); Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, pSqlThread, 0); Sqlitetest1_Init(interp); Sqlitetest_mutex_Init(interp); rc = Tcl_Eval(interp, p->zScript); pRes = Tcl_GetObjResult(interp); pList = Tcl_NewObj(); Tcl_IncrRefCount(pList); | > > > | 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | int rc; SqlThread *p = (SqlThread *)pSqlThread; extern int Sqlitetest_mutex_Init(Tcl_Interp*); interp = Tcl_CreateInterp(); Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0); Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, pSqlThread, 0); #if defined(OS_UNIX) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) Tcl_CreateObjCommand(interp, "sqlite3_blocking_step", blocking_step_proc,0,0); #endif Sqlitetest1_Init(interp); Sqlitetest_mutex_Init(interp); rc = Tcl_Eval(interp, p->zScript); pRes = Tcl_GetObjResult(interp); pList = Tcl_NewObj(); Tcl_IncrRefCount(pList); |
︙ | ︙ | |||
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | Tcl_SetObjResult(interp, Tcl_NewIntObj(now.sec)); UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(objc); UNUSED_PARAMETER(objv); return TCL_OK; } /* ** Register commands with the TCL interpreter. */ int SqlitetestThread_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, 0, 0); Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0); return TCL_OK; } #else int SqlitetestThread_Init(Tcl_Interp *interp){ return TCL_OK; } #endif | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 | Tcl_SetObjResult(interp, Tcl_NewIntObj(now.sec)); UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(objc); UNUSED_PARAMETER(objv); return TCL_OK; } /************************************************************************* ** This block contains the implementation of the [sqlite3_blocking_step] ** command available to threads created by [sqlthread spawn] commands. It ** is only available on UNIX for now. This is because pthread condition ** variables are used. ** ** The source code for the C functions sqlite3_blocking_step(), ** blocking_step_notify() and the structure UnlockNotification is ** automatically extracted from this file and used as part of the ** documentation for the sqlite3_unlock_notify() API function. This ** should be considered if these functions are to be extended (i.e. to ** support windows) in the future. */ #if defined(OS_UNIX) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) /* BEGIN_SQLITE_BLOCKING_STEP */ /* This example uses the pthreads API */ #include <pthread.h> /* ** A pointer to an instance of this structure is passed as the user-context ** pointer when registering for an unlock-notify callback. */ typedef struct UnlockNotification UnlockNotification; struct UnlockNotification { int fired; /* True after unlock event has occured */ pthread_cond_t cond; /* Condition variable to wait on */ pthread_mutex_t mutex; /* Mutex to protect structure */ }; /* ** This function is an unlock-notify callback registered with SQLite. */ static void blocking_step_notify(void **apArg, int nArg){ int i; for(i=0; i<nArg; i++){ UnlockNotification *p = (UnlockNotification *)apArg[i]; pthread_mutex_lock(&p->mutex); p->fired = 1; pthread_cond_signal(&p->cond); pthread_mutex_unlock(&p->mutex); } } /* ** This function is a wrapper around the SQLite function sqlite3_step(). ** It functions in the same way as step(), except that if a required ** shared-cache lock cannot be obtained, this function may block waiting for ** the lock to become available. In this scenario the normal API step() ** function always returns SQLITE_LOCKED. ** ** If this function returns SQLITE_LOCKED, the caller should rollback ** the current transaction (if any) and try again later. Otherwise, the ** system may become deadlocked. */ int sqlite3_blocking_step(sqlite3_stmt *pStmt){ int rc = SQLITE_OK; while( rc==SQLITE_OK && SQLITE_LOCKED==(rc = sqlite3_step(pStmt)) ){ sqlite3 *db = sqlite3_db_handle(pStmt); UnlockNotification un; /* Initialize the UnlockNotification structure. */ un.fired = 0; pthread_mutex_init(&un.mutex, 0); pthread_cond_init(&un.cond, 0); rc = sqlite3_unlock_notify(db, blocking_step_notify, (void *)&un); assert( rc==SQLITE_LOCKED || rc==SQLITE_OK ); /* The call to sqlite3_unlock_notify() always returns either ** SQLITE_LOCKED or SQLITE_OK. ** ** If SQLITE_LOCKED was returned, then the system is deadlocked. In this ** case this function needs to return SQLITE_LOCKED to the caller so ** that it can roll back the current transaction. Simply leaving rc ** as it is is enough to accomplish that, as the next test of the ** while() condition above will fail and the current value of rc ** (SQLITE_LOCKED) will be returned to the caller. sqlite3_reset() is ** not called on the statement handle, so the caller can still use either ** sqlite3_finalize() or reset() to collect the statement's error code ** after this function returns. ** ** Otherwise, if SQLITE_OK was returned, do two things: ** ** 1) Reset the SQL statement. ** 2) Block until the unlock-notify callback is invoked. */ if( rc==SQLITE_OK ){ sqlite3_reset(pStmt); pthread_mutex_lock(&un.mutex); if( !un.fired ){ pthread_cond_wait(&un.cond, &un.mutex); } pthread_mutex_unlock(&un.mutex); } /* Destroy the mutex and condition variables created at the top of ** the while loop. */ pthread_cond_destroy(&un.cond); pthread_mutex_destroy(&un.mutex); } return rc; } /* END_SQLITE_BLOCKING_STEP */ /* ** Usage: sqlite3_blocking_step STMT ** ** Advance the statement to the next row. */ static int blocking_step_proc( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ /* Functions from test1.c */ void *sqlite3TestTextToPtr(const char *); const char *sqlite3TestErrorName(int); sqlite3_stmt *pStmt; int rc; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT"); return TCL_ERROR; } pStmt = (sqlite3_stmt*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); rc = sqlite3_blocking_step(pStmt); Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), 0); return TCL_OK; } #endif /* ** End of implementation of [sqlite3_blocking_step]. ************************************************************************/ /* ** Register commands with the TCL interpreter. */ int SqlitetestThread_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, 0, 0); Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0); #if defined(OS_UNIX) && defined(SQLITE_ENABLE_UNLOCK_NOTIFY) Tcl_CreateObjCommand(interp, "sqlite3_blocking_step", blocking_step_proc,0,0); #endif return TCL_OK; } #else int SqlitetestThread_Init(Tcl_Interp *interp){ return TCL_OK; } #endif |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** ** $Id: vdbe.c,v 1.825 2009/03/16 13:19:36 danielk1977 Exp $ */ #include "sqliteInt.h" #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor ** moves, either by the OP_SeekXX, OP_Next, or OP_Prev opcodes. The test |
︙ | ︙ | |||
4815 4816 4817 4818 4819 4820 4821 | case OP_TableLock: { int p1 = pOp->p1; u8 isWriteLock = (u8)pOp->p3; assert( p1>=0 && p1<db->nDb ); assert( (p->btreeMask & (1<<p1))!=0 ); assert( isWriteLock==0 || isWriteLock==1 ); rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); | | | | | 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 | case OP_TableLock: { int p1 = pOp->p1; u8 isWriteLock = (u8)pOp->p3; assert( p1>=0 && p1<db->nDb ); assert( (p->btreeMask & (1<<p1))!=0 ); assert( isWriteLock==0 || isWriteLock==1 ); rc = sqlite3BtreeLockTable(db->aDb[p1].pBt, pOp->p2, isWriteLock); if( (rc&0xFF)==SQLITE_LOCKED ){ const char *z = pOp->p4.z; sqlite3SetString(&p->zErrMsg, db, "database table is locked: %s", z); } break; } #endif /* SQLITE_OMIT_SHARED_CACHE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VBegin * * * P4 * ** ** P4 may be a pointer to an sqlite3_vtab structure. If so, call the ** xBegin method for that table. ** ** Also, whether or not P4 is set, check that this is not being called from ** within a callback to a virtual table xSync() method. If it is, the error ** code will be set to SQLITE_LOCKED. */ case OP_VBegin: { sqlite3_vtab *pVtab = pOp->p4.pVtab; rc = sqlite3VtabBegin(db, pVtab); if( pVtab ){ sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = pVtab->zErrMsg; |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | ** ************************************************************************* ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** | | | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ** ************************************************************************* ** This file contains code used for creating, destroying, and populating ** a VDBE (or an "sqlite3_stmt" as it is known to the outside world.) Prior ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** ** $Id: vdbeaux.c,v 1.442 2009/03/16 13:19:36 danielk1977 Exp $ */ #include "sqliteInt.h" #include "vdbeInt.h" /* |
︙ | ︙ | |||
1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 | assert( db->activeVdbeCnt>=db->writeVdbeCnt ); } p->magic = VDBE_MAGIC_HALT; checkActiveVdbeCnt(db); if( p->db->mallocFailed ){ p->rc = SQLITE_NOMEM; } return SQLITE_OK; } /* ** Each VDBE holds the result of the most recent sqlite3_step() call | > > > > > > > > | 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 | assert( db->activeVdbeCnt>=db->writeVdbeCnt ); } p->magic = VDBE_MAGIC_HALT; checkActiveVdbeCnt(db); if( p->db->mallocFailed ){ p->rc = SQLITE_NOMEM; } /* If the auto-commit flag is set to true, then any locks that were held ** by connection db have now been released. Call sqlite3ConnectionUnlocked() ** to invoke any required unlock-notify callbacks. */ if( db->autoCommit ){ sqlite3ConnectionUnlocked(db); } return SQLITE_OK; } /* ** Each VDBE holds the result of the most recent sqlite3_step() call |
︙ | ︙ |
Changes to src/vtab.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2006 June 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to help implement virtual tables. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2006 June 10 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to help implement virtual tables. ** ** $Id: vtab.c,v 1.82 2009/03/16 13:19:36 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_VIRTUALTABLE #include "sqliteInt.h" static int createModule( sqlite3 *db, /* Database in which module is registered */ const char *zName, /* Name assigned to this module */ |
︙ | ︙ | |||
707 708 709 710 711 712 713 | int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){ int rc = SQLITE_OK; const sqlite3_module *pModule; /* Special case: If db->aVTrans is NULL and db->nVTrans is greater ** than zero, then this function is being called from within a ** virtual module xSync() callback. It is illegal to write to | | | 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 | int sqlite3VtabBegin(sqlite3 *db, sqlite3_vtab *pVtab){ int rc = SQLITE_OK; const sqlite3_module *pModule; /* Special case: If db->aVTrans is NULL and db->nVTrans is greater ** than zero, then this function is being called from within a ** virtual module xSync() callback. It is illegal to write to ** virtual module tables in this case, so return SQLITE_MISUSE. */ if( sqlite3VtabInSync(db) ){ return SQLITE_LOCKED; } if( !pVtab ){ return SQLITE_OK; } |
︙ | ︙ |
Changes to test/backup.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2009 January 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite3_backup_XXX API. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2009 January 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite3_backup_XXX API. # # $Id: backup.test,v 1.9 2009/03/16 13:19:36 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl #--------------------------------------------------------------------- # Test organization: # |
︙ | ︙ | |||
732 733 734 735 736 737 738 | execsql { BEGIN; INSERT INTO t1 VALUES(1, 4); } } {} do_test backup-7.2.2 { B step 5000 | | | 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 | execsql { BEGIN; INSERT INTO t1 VALUES(1, 4); } } {} do_test backup-7.2.2 { B step 5000 } {SQLITE_BUSY} do_test backup-7.2.3 { execsql { ROLLBACK } B step 5000 } {SQLITE_DONE} do_test backup-7.2.4 { B finish } {SQLITE_OK} |
︙ | ︙ |
Changes to test/incrblob2.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Test that it is possible to have two open blob handles on a single # blob object. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # # Test that it is possible to have two open blob handles on a single # blob object. # # $Id: incrblob2.test,v 1.10 2009/03/16 13:19:36 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!autovacuum || !pragma || !incrblob} { finish_test |
︙ | ︙ | |||
261 262 263 264 265 266 267 | do_test incrblob2-5.2 { catchsql { INSERT INTO t1 VALUES(2, 'fghij') } db2 } {0 {}} do_test incrblob2-5.3 { set blob [db incrblob t1 data 1] catchsql { INSERT INTO t1 VALUES(3, 'klmno') } db2 | | | 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | do_test incrblob2-5.2 { catchsql { INSERT INTO t1 VALUES(2, 'fghij') } db2 } {0 {}} do_test incrblob2-5.3 { set blob [db incrblob t1 data 1] catchsql { INSERT INTO t1 VALUES(3, 'klmno') } db2 } {1 {database table is locked}} do_test incrblob2-5.4 { close $blob execsql BEGIN db2 catchsql { INSERT INTO t1 VALUES(4, 'pqrst') } db2 } {0 {}} |
︙ | ︙ |
Added test/notify1.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | # 2009 March 04 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the sqlite3_unlock_notify() API. # # $Id: notify1.test,v 1.1 2009/03/16 13:19:36 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable !unlock_notify||!shared_cache { finish_test return } db close set ::enable_shared_cache [sqlite3_enable_shared_cache 1] #------------------------------------------------------------------------- # Warm body test. Test that an unlock-notify callback can be registered # and that it is invoked. # do_test notify1-1.1 { sqlite3 db test.db sqlite3 db2 test.db execsql { CREATE TABLE t1(a, b) } } {} do_test notify1-1.2 { execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); } catchsql { INSERT INTO t1 VALUES(3, 4) } db2 } {1 {database table is locked}} do_test notify1-1.3 { set zScript "" db2 unlock_notify { set zScript "db2 eval { INSERT INTO t1 VALUES(3, 4) }" } execsql { SELECT * FROM t1 } } {1 2} do_test notify1-1.4 { set zScript } {} do_test notify1-1.5 { execsql { COMMIT } eval $zScript execsql { SELECT * FROM t1 } } {1 2 3 4} #------------------------------------------------------------------------- # The following tests, notify1-2.*, test that deadlock is detected # correctly. # do_test notify1-2.1 { execsql { CREATE TABLE t2(a, b); INSERT INTO t2 VALUES('I', 'II'); } } {} # # Test for simple deadlock involving two database connections. # # 1. Grab a write-lock on t1 with [db]. Then grab a read-lock on t2 with [db2]. # 2. Try to grab a read-lock on t1 with [db2] (fails). # 3. Have [db2] wait on the read-lock it failed to obtain in step 2. # 4. Try to grab a write-lock on t2 with [db] (fails). # 5. Try to have [db] wait on the lock from step 4. Fails, as the system # would be deadlocked (since [db2] is already waiting on [db], and this # operation would have [db] wait on [db2]). # do_test notify1-2.2.1 { execsql { BEGIN; INSERT INTO t1 VALUES(5, 6); } execsql { BEGIN; SELECT * FROM t2; } db2 } {I II} do_test notify1-2.2.2 { catchsql { SELECT * FROM t1 } db2 } {1 {database table is locked: t1}} do_test notify1-2.2.3 { db2 unlock_notify {lappend unlock_notify db2} } {} do_test notify1-2.2.4 { catchsql { INSERT INTO t2 VALUES('III', 'IV') } } {1 {database table is locked: t2}} do_test notify1-2.2.5 { set rc [catch { db unlock_notify {lappend unlock_notify db} } msg] list $rc $msg } {1 {database is deadlocked}} # # Test for slightly more complex deadlock involving three database # connections: db, db2 and db3. # do_test notify1-2.3.1 { db close db2 close file delete -force test.db test2.db test3.db foreach con {db db2 db3} { sqlite3 $con test.db $con eval { ATTACH 'test2.db' AS aux2 } $con eval { ATTACH 'test3.db' AS aux3 } } execsql { CREATE TABLE main.t1(a, b); CREATE TABLE aux2.t2(a, b); CREATE TABLE aux3.t3(a, b); } } {} do_test notify1-2.3.2 { execsql { BEGIN ; INSERT INTO t1 VALUES(1, 2) } db execsql { BEGIN ; INSERT INTO t2 VALUES(1, 2) } db2 execsql { BEGIN ; INSERT INTO t3 VALUES(1, 2) } db3 } {} do_test notify1-2.3.3 { catchsql { SELECT * FROM t2 } db } {1 {database table is locked: t2}} do_test notify1-2.3.4 { catchsql { SELECT * FROM t3 } db2 } {1 {database table is locked: t3}} do_test notify1-2.3.5 { catchsql { SELECT * FROM t1 } db3 } {1 {database table is locked: t1}} do_test notify1-2.3.6 { set lUnlock [list] db unlock_notify {lappend lUnlock db} db2 unlock_notify {lappend lUnlock db2} } {} do_test notify1-2.3.7 { set rc [catch { db3 unlock_notify {lappend lUnlock db3} } msg] list $rc $msg } {1 {database is deadlocked}} do_test notify1-2.3.8 { execsql { COMMIT } set lUnlock } {} do_test notify1-2.3.9 { db3 unlock_notify {lappend lUnlock db3} set lUnlock } {db3} do_test notify1-2.3.10 { execsql { COMMIT } db2 set lUnlock } {db3 db} do_test notify1-2.3.11 { execsql { COMMIT } db3 set lUnlock } {db3 db db2} catch { db3 close } catch { db2 close } catch { db close } #------------------------------------------------------------------------- # The following tests, notify1-3.* and notify1-4.*, test that callbacks # can be issued when there are many (>16) connections waiting on a single # unlock event. # foreach {tn nConn} {3 20 4 76} { do_test notify1-$tn.1 { sqlite3 db test.db execsql { BEGIN; INSERT INTO t1 VALUES('a', 'b'); } } {} set lUnlock [list] set lUnlockFinal [list] for {set ii 1} {$ii <= $nConn} {incr ii} { do_test notify1-$tn.2.$ii.1 { set cmd "db$ii" sqlite3 $cmd test.db catchsql { SELECT * FROM t1 } $cmd } {1 {database table is locked: t1}} do_test notify1-$tn.2.$ii.2 { $cmd unlock_notify "lappend lUnlock $ii" } {} lappend lUnlockFinal $ii } do_test notify1-$tn.3 { set lUnlock } {} do_test notify1-$tn.4 { execsql {COMMIT} lsort -integer $lUnlock } $lUnlockFinal do_test notify1-$tn.5 { for {set ii 1} {$ii <= $nConn} {incr ii} { "db$ii" close } } {} } db close #------------------------------------------------------------------------- # These tests, notify1-5.*, test that a malloc() failure that occurs while # allocating an array to use as an argument to an unlock-notify callback # is handled correctly. # source $testdir/malloc_common.tcl breakpoint do_malloc_test notify1-5 -tclprep { set ::lUnlock [list] execsql { CREATE TABLE t1(a, b); BEGIN; INSERT INTO t1 VALUES('a', 'b'); } for {set ii 1} {$ii <= 60} {incr ii} { set cmd "db$ii" sqlite3 $cmd test.db catchsql { SELECT * FROM t1 } $cmd $cmd unlock_notify "lappend ::lUnlock $ii" } } -sqlbody { COMMIT; } -cleanup { # One of two things should have happened: # # 1) The transaction opened by [db] was not committed. No unlock-notify # callbacks were invoked, OR # 2) The transaction opened by [db] was committed and 60 unlock-notify # callbacks were invoked. # do_test notify1-5.systemstate { expr { ([llength $::lUnlock]==0 && [sqlite3_get_autocommit db]==0) || ([llength $::lUnlock]==60 && [sqlite3_get_autocommit db]==1) } } {1} for {set ii 1} {$ii <= 60} {incr ii} { "db$ii" close } } #------------------------------------------------------------------------- # Test cases notify1-6.* test cases where the following occur: # # notify1-6.1.*: Test encountering an SQLITE_LOCKED error when the # "blocking connection" has already been set by a previous # SQLITE_LOCKED. # # notify1-6.2.*: Test encountering an SQLITE_LOCKED error when already # waiting on an unlock-notify callback. # # notify1-6.3.*: Test that if an SQLITE_LOCKED error is encountered while # already waiting on an unlock-notify callback, and then # the blocker that caused the SQLITE_LOCKED commits its # transaction, the unlock-notify callback is not invoked. # # notify1-6.4.*: Like 6.3.*, except that instead of the second blocker # committing its transaction, the first does. The # unlock-notify callback is therefore invoked. # db close do_test notify1-6.1.1 { file delete -force test.db test2.db foreach conn {db db2 db3} { sqlite3 $conn test.db execsql { ATTACH 'test2.db' AS two } $conn } execsql { CREATE TABLE t1(a, b); CREATE TABLE two.t2(a, b); } execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); } db2 execsql { BEGIN; INSERT INTO t2 VALUES(1, 2); } db3 } {} do_test notify1-6.1.2 { catchsql { SELECT * FROM t2 } } {1 {database table is locked: t2}} do_test notify1-6.1.3 { catchsql { SELECT * FROM t1 } } {1 {database table is locked: t1}} do_test notify1-6.2.1 { set unlocked 0 db unlock_notify {set unlocked 1} set unlocked } {0} do_test notify1-6.2.2 { catchsql { SELECT * FROM t2 } } {1 {database table is locked: t2}} do_test notify1-6.2.3 { execsql { COMMIT } db2 set unlocked } {1} do_test notify1-6.3.1 { execsql { BEGIN; INSERT INTO t1 VALUES(3, 4); } db2 } {} do_test notify1-6.3.2 { catchsql { SELECT * FROM t1 } } {1 {database table is locked: t1}} do_test notify1-6.3.3 { set unlocked 0 db unlock_notify {set unlocked 1} set unlocked } {0} do_test notify1-6.3.4 { catchsql { SELECT * FROM t2 } } {1 {database table is locked: t2}} do_test notify1-6.3.5 { execsql { COMMIT } db3 set unlocked } {0} do_test notify1-6.4.1 { execsql { BEGIN; INSERT INTO t2 VALUES(3, 4); } db3 catchsql { SELECT * FROM t2 } } {1 {database table is locked: t2}} do_test notify1-6.4.2 { execsql { COMMIT } db2 set unlocked } {1} do_test notify1-6.4.3 { execsql { COMMIT } db3 } {} db close db2 close db3 close #------------------------------------------------------------------------- # Test cases notify1-7.* tests that when more than one distinct # unlock-notify function is registered, all are invoked correctly. # proc unlock_notify {} { incr ::unlock_notify } do_test notify1-7.1 { foreach conn {db db2 db3} { sqlite3 $conn test.db } execsql { BEGIN; INSERT INTO t1 VALUES(5, 6); } } {} do_test notify1-7.2 { catchsql { SELECT * FROM t1 } db2 } {1 {database table is locked: t1}} do_test notify1-7.3 { catchsql { SELECT * FROM t1 } db3 } {1 {database table is locked: t1}} do_test notify1-7.4 { set unlock_notify 0 db2 unlock_notify unlock_notify sqlite3_unlock_notify db3 } {SQLITE_OK} do_test notify1-7.5 { set unlock_notify } {0} do_test notify1-7.6 { execsql { COMMIT } set unlock_notify } {2} #------------------------------------------------------------------------- # Test cases notify1-8.* tests that the correct SQLITE_LOCKED extended # error code is returned in various scenarios. # do_test notify1-8.1 { execsql { BEGIN; INSERT INTO t1 VALUES(7, 8); } sqlite3_extended_result_codes db2 1 catchsql { SELECT * FROM t1 } db2 } {1 {database table is locked: t1}} do_test notify1-8.2 { sqlite3_extended_errcode db2 } {SQLITE_LOCKED_SHAREDCACHE} do_test notify1-8.3 { execsql { COMMIT; BEGIN EXCLUSIVE; } catchsql { SELECT * FROM t1 } db2 } {1 {database schema is locked: main}} do_test notify1-8.4 { sqlite3_extended_errcode db2 } {SQLITE_LOCKED_SHAREDCACHE} do_test notify1-8.X { execsql { COMMIT } } {} #------------------------------------------------------------------------- # Test cases notify1-9.* test the shared-cache 'pending-lock' feature. # do_test notify1-9.1 { execsql { CREATE TABLE t2(a, b); BEGIN; SELECT * FROM t1; } db2 } {1 2 3 4 5 6 7 8} do_test notify1-9.2 { execsql { SELECT * FROM t1 } db3 } {1 2 3 4 5 6 7 8} do_test notify1-9.3 { catchsql { BEGIN; INSERT INTO t1 VALUES(9, 10); } } {1 {database table is locked: t1}} do_test notify1-9.4 { catchsql { SELECT * FROM t2 } db3 } {1 {database table is locked}} do_test notify1-9.5 { execsql { COMMIT } db2 execsql { SELECT * FROM t2 } db3 } {} do_test notify1-9.6 { execsql { COMMIT } } {} do_test notify1-9.7 { execsql { BEGIN; SELECT * FROM t1; } db2 } {1 2 3 4 5 6 7 8} do_test notify1-9.8 { execsql { SELECT * FROM t1 } db3 } {1 2 3 4 5 6 7 8} do_test notify1-9.9 { catchsql { BEGIN; INSERT INTO t1 VALUES(9, 10); } } {1 {database table is locked: t1}} do_test notify1-9.10 { catchsql { SELECT * FROM t2 } db3 } {1 {database table is locked}} do_test notify1-9.11 { execsql { COMMIT } execsql { SELECT * FROM t2 } db3 } {} do_test notify1-9.12 { execsql { COMMIT } db2 } {} db close db2 close db3 close sqlite3_enable_shared_cache $::enable_shared_cache finish_test |
Added test/notify2.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | # 2009 March 04 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # $Id: notify2.test,v 1.1 2009/03/16 13:19:36 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # The tests in this file test the sqlite3_blocking_step() function in # test_thread.c. sqlite3_blocking_step() is not an SQLite API function, # it is just a demonstration of how the sqlite3_unlock_notify() function # can be used to synchronize multi-threaded access to SQLite databases # in shared-cache mode. # # Since the implementation of sqlite3_blocking_step() is included on the # website as example code, it is important to test that it works. # # notify2-1.*: # # This test uses $nThread threads. Each thread opens the main database # and attaches two other databases. Each database contains a single table. # # Each thread repeats transactions over and over for 20 seconds. Each # transaction consists of 3 operations. Each operation is either a read # or a write of one of the tables. The read operations verify an invariant # to make sure that things are working as expected. If an SQLITE_LOCKED # error is returned the current transaction is rolled back immediately. # # This exercise is repeated twice, once using sqlite3_step(), and the # other using sqlite3_blocking_step(). The results are compared to ensure # that sqlite3_blocking_step() resulted in higher transaction throughput. # if {[info commands sqlite3_blocking_step] eq ""} { finish_test return } db close set ::enable_shared_cache [sqlite3_enable_shared_cache 1] source $testdir/thread_common.tcl # Number of threads to run simultaneously. # set nThread 3 set nSecond 5 # The Tcl script executed by each of the $nThread threads used by this test. # set ThreadProgram { # Proc used by threads to execute SQL. # proc execsql_blocking {db zSql} { set lRes [list] set rc SQLITE_OK while {$rc=="SQLITE_OK" && $zSql ne ""} { set STMT [sqlite3_prepare_v2 $db $zSql -1 zSql] while {[set rc [$::xStep $STMT]] eq "SQLITE_ROW"} { for {set i 0} {$i < [sqlite3_column_count $STMT]} {incr i} { lappend lRes [sqlite3_column_text $STMT 0] } } set rc [sqlite3_finalize $STMT] } if {$rc != "SQLITE_OK"} { error "$rc [sqlite3_errmsg $db]" } return $lRes } proc select_one {args} { set n [llength $args] lindex $args [expr int($n*rand())] } # Open a database connection. Attach the two auxillary databases. set ::DB [sqlite3_open test.db] execsql_blocking $::DB { ATTACH 'test2.db' AS aux2; ATTACH 'test3.db' AS aux3; } # This loop runs for ~20 seconds. # set iStart [clock_seconds] while { ([clock_seconds]-$iStart) < $nSecond } { # Each transaction does 3 operations. Each operation is either a read # or write of a randomly selected table (t1, t2 or t3). Set the variables # $SQL(1), $SQL(2) and $SQL(3) to the SQL commands used to implement # each operation. # for {set ii 1} {$ii <= 3} {incr ii} { set SQL($ii) [string map [list xxx [select_one t1 t2 t3]] [select_one { SELECT (SELECT b FROM xxx WHERE a=(SELECT max(a) FROM xxx))==total(a) FROM xxx WHERE a!=(SELECT max(a) FROM xxx); } { DELETE FROM xxx WHERE a<(SELECT max(a)-100 FROM xxx); INSERT INTO xxx SELECT NULL, total(a) FROM xxx; }]] } # Execute the SQL transaction. # set rc [catch { execsql_blocking $::DB " BEGIN; $SQL(1); $SQL(2); $SQL(3); COMMIT; " } msg] if {$rc && [string match "SQLITE_LOCKED*" $msg]} { # Hit an SQLITE_LOCKED error. Rollback the current transaction. execsql_blocking $::DB ROLLBACK } elseif {$rc} { # Hit some other kind of error. This is a malfunction. error $msg } else { # No error occured. Check that any SELECT statements in the transaction # returned "1". Otherwise, the invariant was false, indicating that # some malfunction has occured. foreach r $msg { if {$r != 1} { puts "Invariant check failed: $msg" } } } } # Close the database connection and return 0. # sqlite3_close $::DB expr 0 } foreach {iTest xStep} {1 sqlite3_blocking_step 2 sqlite3_step} { file delete -force test.db test2.db test3.db set ThreadSetup "set xStep $xStep ; set nSecond $nSecond" # Set up the database schema used by this test. Each thread opens file # test.db as the main database, then attaches files test2.db and test3.db # as auxillary databases. Each file contains a single table (t1, t2 and t3, in # files test.db, test2.db and test3.db, respectively). # do_test notify2-$iTest.1.1 { sqlite3 db test.db execsql { ATTACH 'test2.db' AS aux2; ATTACH 'test3.db' AS aux3; CREATE TABLE main.t1(a INTEGER PRIMARY KEY, b); CREATE TABLE aux2.t2(a INTEGER PRIMARY KEY, b); CREATE TABLE aux3.t3(a INTEGER PRIMARY KEY, b); INSERT INTO t1 SELECT NULL, 0; INSERT INTO t2 SELECT NULL, 0; INSERT INTO t3 SELECT NULL, 0; } } {} do_test notify2-$iTest.1.2 { db close } {} # Launch $nThread threads. Then wait for them to finish. # puts "Running $xStep test for $nSecond seconds" unset -nocomplain finished for {set ii 0} {$ii < $nThread} {incr ii} { thread_spawn finished($ii) $ThreadSetup $ThreadProgram } for {set ii 0} {$ii < $nThread} {incr ii} { do_test notify2-$iTest.2.$ii { if {![info exists finished($ii)]} { vwait finished($ii) } set finished($ii) } {0} } # Count the total number of succesful writes. do_test notify2-$iTest.3.1 { sqlite3 db test.db execsql { ATTACH 'test2.db' AS aux2; ATTACH 'test3.db' AS aux3; } set anWrite($xStep) [execsql { SELECT (SELECT max(a) FROM t1) + (SELECT max(a) FROM t2) + (SELECT max(a) FROM t3) }] db close } {} } do_test notify2-3 { expr {$anWrite(sqlite3_blocking_step) > $anWrite(sqlite3_step)} } {1} sqlite3_enable_shared_cache $::enable_shared_cache finish_test |
Changes to test/shared.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2005 December 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # 2005 December 30 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # $Id: shared.test,v 1.36 2009/03/16 13:19:36 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl db close # These tests cannot be run without the ATTACH command. # |
︙ | ︙ | |||
871 872 873 874 875 876 877 | catchsql {BEGIN} db2 } {1 {cannot start a transaction within a transaction}} do_test shared-$av.11.4 { catchsql {SELECT * FROM abc2;} db2 } {0 {}} do_test shared-$av.11.5 { catchsql {INSERT INTO abc2 VALUES(1, 2, 3);} db2 | | | 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 | catchsql {BEGIN} db2 } {1 {cannot start a transaction within a transaction}} do_test shared-$av.11.4 { catchsql {SELECT * FROM abc2;} db2 } {0 {}} do_test shared-$av.11.5 { catchsql {INSERT INTO abc2 VALUES(1, 2, 3);} db2 } {1 {database table is locked}} do_test shared-$av.11.6 { catchsql {SELECT * FROM abc2} } {0 {}} do_test shared-$av.11.6 { execsql { ROLLBACK; PRAGMA read_uncommitted = 1; |
︙ | ︙ |
Changes to test/tclsqlite.test.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # This file implements regression tests for TCL interface to the # SQLite library. # # Actually, all tests are based on the TCL interface, so the main # interface is pretty well tested. This file contains some addition # tests for fringe issues that the main test suite does not cover. # | | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | # This file implements regression tests for TCL interface to the # SQLite library. # # Actually, all tests are based on the TCL interface, so the main # interface is pretty well tested. This file contains some addition # tests for fringe issues that the main test suite does not cover. # # $Id: tclsqlite.test,v 1.73 2009/03/16 13:19:36 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Check the error messages generated by tclsqlite # if {[sqlite3 -has-codec]} { set r "sqlite_orig HANDLE FILENAME ?-key CODEC-KEY?" } else { set r "sqlite3 HANDLE FILENAME ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN?" } do_test tcl-1.1 { set v [catch {sqlite3 bogus} msg] regsub {really_sqlite3} $msg {sqlite3} msg lappend v $msg } [list 1 "wrong # args: should be \"$r\""] do_test tcl-1.2 { set v [catch {db bogus} msg] lappend v $msg } {1 {bad option "bogus": must be authorizer, backup, busy, cache, changes, close, collate, collation_needed, commit_hook, complete, copy, enable_load_extension, errorcode, eval, exists, function, incrblob, interrupt, last_insert_rowid, nullvalue, onecolumn, profile, progress, rekey, restore, rollback_hook, status, timeout, total_changes, trace, transaction, unlock_notify, update_hook, or version}} do_test tcl-1.2.1 { set v [catch {db cache bogus} msg] lappend v $msg } {1 {bad option "bogus": must be flush or size}} do_test tcl-1.2.2 { set v [catch {db cache} msg] lappend v $msg |
︙ | ︙ |
Changes to test/tkt2854.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2007 December 20 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # 2007 December 20 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # $Id: tkt2854.test,v 1.4 2009/03/16 13:19:36 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl db close ifcapable !shared_cache { finish_test |
︙ | ︙ | |||
52 53 54 55 56 57 58 | execsql { BEGIN; SELECT * FROM abc; } db2 } {} do_test tkt2854-1.3 { catchsql { BEGIN EXCLUSIVE } db | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | execsql { BEGIN; SELECT * FROM abc; } db2 } {} do_test tkt2854-1.3 { catchsql { BEGIN EXCLUSIVE } db } {1 {database table is locked}} do_test tkt2854-1.4 { execsql { SELECT * FROM abc } db3 } {} do_test tkt2854-1.5 { catchsql { INSERT INTO abc VALUES(1, 2, 3) } db3 } {1 {database is locked}} do_test tkt2854-1.6 { |
︙ | ︙ | |||
95 96 97 98 99 100 101 | # at the b-tree level, not the schema level. # do_test tkt2854-1.11 { list [sqlite3_step $::STMT1] [sqlite3_finalize $::STMT1] } {SQLITE_ERROR SQLITE_LOCKED} do_test tkt2854-1.12 { list [sqlite3_step $::STMT2] [sqlite3_finalize $::STMT2] | | | | 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | # at the b-tree level, not the schema level. # do_test tkt2854-1.11 { list [sqlite3_step $::STMT1] [sqlite3_finalize $::STMT1] } {SQLITE_ERROR SQLITE_LOCKED} do_test tkt2854-1.12 { list [sqlite3_step $::STMT2] [sqlite3_finalize $::STMT2] } {SQLITE_ERROR SQLITE_LOCKED} do_test tkt2854-1.13 { list [sqlite3_step $::STMT3] [sqlite3_finalize $::STMT3] } {SQLITE_ERROR SQLITE_LOCKED} do_test tkt2854-1.14 { # A regular "BEGIN" doesn't touch any databases. So it succeeds. list [sqlite3_step $::STMT4] [sqlite3_finalize $::STMT4] } {SQLITE_DONE SQLITE_OK} do_test tkt2854-1.15 { # As does a COMMIT. list [sqlite3_step $::STMT5] [sqlite3_finalize $::STMT5] |
︙ | ︙ | |||
132 133 134 135 136 137 138 | sqlite3 db4 test2.db execsql { CREATE TABLE def(d, e, f) } db4 execsql { ATTACH 'test2.db' AS aux } db } {} do_test tkt2854-1.20 { execsql {BEGIN IMMEDIATE} db4 catchsql {BEGIN EXCLUSIVE} db | | | 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | sqlite3 db4 test2.db execsql { CREATE TABLE def(d, e, f) } db4 execsql { ATTACH 'test2.db' AS aux } db } {} do_test tkt2854-1.20 { execsql {BEGIN IMMEDIATE} db4 catchsql {BEGIN EXCLUSIVE} db } {1 {database table is locked}} do_test tkt2854-1.21 { execsql {SELECT * FROM abc} db2 } {} db close db2 close db3 close db4 close sqlite3_enable_shared_cache $::enable_shared_cache finish_test |
Changes to tool/mksqlite3c.tcl.
︙ | ︙ | |||
283 284 285 286 287 288 289 290 291 292 293 294 295 296 | parse.c tokenize.c complete.c main.c fts3.c fts3_expr.c fts3_hash.c fts3_porter.c fts3_tokenizer.c fts3_tokenizer1.c | > | 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 | parse.c tokenize.c complete.c main.c notify.c fts3.c fts3_expr.c fts3_hash.c fts3_porter.c fts3_tokenizer.c fts3_tokenizer1.c |
︙ | ︙ |