| OLD | NEW |
| 1 /* | 1 /* |
| 2 ** 2007 May 1 | 2 ** 2007 May 1 |
| 3 ** | 3 ** |
| 4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
| 5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
| 6 ** | 6 ** |
| 7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
| 8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
| 9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
| 10 ** | 10 ** |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 | 57 |
| 58 /* Set the value of the SQL statements only variable to integer iRow. | 58 /* Set the value of the SQL statements only variable to integer iRow. |
| 59 ** This is done directly instead of using sqlite3_bind_int64() to avoid | 59 ** This is done directly instead of using sqlite3_bind_int64() to avoid |
| 60 ** triggering asserts related to mutexes. | 60 ** triggering asserts related to mutexes. |
| 61 */ | 61 */ |
| 62 assert( v->aVar[0].flags&MEM_Int ); | 62 assert( v->aVar[0].flags&MEM_Int ); |
| 63 v->aVar[0].u.i = iRow; | 63 v->aVar[0].u.i = iRow; |
| 64 | 64 |
| 65 rc = sqlite3_step(p->pStmt); | 65 rc = sqlite3_step(p->pStmt); |
| 66 if( rc==SQLITE_ROW ){ | 66 if( rc==SQLITE_ROW ){ |
| 67 u32 type = v->apCsr[0]->aType[p->iCol]; | 67 VdbeCursor *pC = v->apCsr[0]; |
| 68 u32 type = pC->aType[p->iCol]; |
| 68 if( type<12 ){ | 69 if( type<12 ){ |
| 69 zErr = sqlite3MPrintf(p->db, "cannot open value of type %s", | 70 zErr = sqlite3MPrintf(p->db, "cannot open value of type %s", |
| 70 type==0?"null": type==7?"real": "integer" | 71 type==0?"null": type==7?"real": "integer" |
| 71 ); | 72 ); |
| 72 rc = SQLITE_ERROR; | 73 rc = SQLITE_ERROR; |
| 73 sqlite3_finalize(p->pStmt); | 74 sqlite3_finalize(p->pStmt); |
| 74 p->pStmt = 0; | 75 p->pStmt = 0; |
| 75 }else{ | 76 }else{ |
| 76 p->iOffset = v->apCsr[0]->aOffset[p->iCol]; | 77 p->iOffset = pC->aType[p->iCol + pC->nField]; |
| 77 p->nByte = sqlite3VdbeSerialTypeLen(type); | 78 p->nByte = sqlite3VdbeSerialTypeLen(type); |
| 78 p->pCsr = v->apCsr[0]->pCursor; | 79 p->pCsr = pC->pCursor; |
| 79 sqlite3BtreeEnterCursor(p->pCsr); | 80 sqlite3BtreeIncrblobCursor(p->pCsr); |
| 80 sqlite3BtreeCacheOverflow(p->pCsr); | |
| 81 sqlite3BtreeLeaveCursor(p->pCsr); | |
| 82 } | 81 } |
| 83 } | 82 } |
| 84 | 83 |
| 85 if( rc==SQLITE_ROW ){ | 84 if( rc==SQLITE_ROW ){ |
| 86 rc = SQLITE_OK; | 85 rc = SQLITE_OK; |
| 87 }else if( p->pStmt ){ | 86 }else if( p->pStmt ){ |
| 88 rc = sqlite3_finalize(p->pStmt); | 87 rc = sqlite3_finalize(p->pStmt); |
| 89 p->pStmt = 0; | 88 p->pStmt = 0; |
| 90 if( rc==SQLITE_OK ){ | 89 if( rc==SQLITE_OK ){ |
| 91 zErr = sqlite3MPrintf(p->db, "no such rowid: %lld", iRow); | 90 zErr = sqlite3MPrintf(p->db, "no such rowid: %lld", iRow); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 125 ** | 124 ** |
| 126 ** After seeking the cursor, the vdbe executes an OP_ResultRow. | 125 ** After seeking the cursor, the vdbe executes an OP_ResultRow. |
| 127 ** Code external to the Vdbe then "borrows" the b-tree cursor and | 126 ** Code external to the Vdbe then "borrows" the b-tree cursor and |
| 128 ** uses it to implement the blob_read(), blob_write() and | 127 ** uses it to implement the blob_read(), blob_write() and |
| 129 ** blob_bytes() functions. | 128 ** blob_bytes() functions. |
| 130 ** | 129 ** |
| 131 ** The sqlite3_blob_close() function finalizes the vdbe program, | 130 ** The sqlite3_blob_close() function finalizes the vdbe program, |
| 132 ** which closes the b-tree cursor and (possibly) commits the | 131 ** which closes the b-tree cursor and (possibly) commits the |
| 133 ** transaction. | 132 ** transaction. |
| 134 */ | 133 */ |
| 134 static const int iLn = VDBE_OFFSET_LINENO(4); |
| 135 static const VdbeOpList openBlob[] = { | 135 static const VdbeOpList openBlob[] = { |
| 136 {OP_Transaction, 0, 0, 0}, /* 0: Start a transaction */ | 136 /* {OP_Transaction, 0, 0, 0}, // 0: Inserted separately */ |
| 137 {OP_VerifyCookie, 0, 0, 0}, /* 1: Check the schema cookie */ | 137 {OP_TableLock, 0, 0, 0}, /* 1: Acquire a read or write lock */ |
| 138 {OP_TableLock, 0, 0, 0}, /* 2: Acquire a read or write lock */ | |
| 139 | |
| 140 /* One of the following two instructions is replaced by an OP_Noop. */ | 138 /* One of the following two instructions is replaced by an OP_Noop. */ |
| 141 {OP_OpenRead, 0, 0, 0}, /* 3: Open cursor 0 for reading */ | 139 {OP_OpenRead, 0, 0, 0}, /* 2: Open cursor 0 for reading */ |
| 142 {OP_OpenWrite, 0, 0, 0}, /* 4: Open cursor 0 for read/write */ | 140 {OP_OpenWrite, 0, 0, 0}, /* 3: Open cursor 0 for read/write */ |
| 143 | 141 {OP_Variable, 1, 1, 1}, /* 4: Push the rowid to the stack */ |
| 144 {OP_Variable, 1, 1, 1}, /* 5: Push the rowid to the stack */ | 142 {OP_NotExists, 0, 10, 1}, /* 5: Seek the cursor */ |
| 145 {OP_NotExists, 0, 10, 1}, /* 6: Seek the cursor */ | 143 {OP_Column, 0, 0, 1}, /* 6 */ |
| 146 {OP_Column, 0, 0, 1}, /* 7 */ | 144 {OP_ResultRow, 1, 0, 0}, /* 7 */ |
| 147 {OP_ResultRow, 1, 0, 0}, /* 8 */ | 145 {OP_Goto, 0, 4, 0}, /* 8 */ |
| 148 {OP_Goto, 0, 5, 0}, /* 9 */ | 146 {OP_Close, 0, 0, 0}, /* 9 */ |
| 149 {OP_Close, 0, 0, 0}, /* 10 */ | 147 {OP_Halt, 0, 0, 0}, /* 10 */ |
| 150 {OP_Halt, 0, 0, 0}, /* 11 */ | |
| 151 }; | 148 }; |
| 152 | 149 |
| 153 int rc = SQLITE_OK; | 150 int rc = SQLITE_OK; |
| 154 char *zErr = 0; | 151 char *zErr = 0; |
| 155 Table *pTab; | 152 Table *pTab; |
| 156 Parse *pParse = 0; | 153 Parse *pParse = 0; |
| 157 Incrblob *pBlob = 0; | 154 Incrblob *pBlob = 0; |
| 158 | 155 |
| 159 flags = !!flags; /* flags = (flags ? 1 : 0); */ | 156 flags = !!flags; /* flags = (flags ? 1 : 0); */ |
| 160 *ppBlob = 0; | 157 *ppBlob = 0; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 171 pParse->db = db; | 168 pParse->db = db; |
| 172 sqlite3DbFree(db, zErr); | 169 sqlite3DbFree(db, zErr); |
| 173 zErr = 0; | 170 zErr = 0; |
| 174 | 171 |
| 175 sqlite3BtreeEnterAll(db); | 172 sqlite3BtreeEnterAll(db); |
| 176 pTab = sqlite3LocateTable(pParse, 0, zTable, zDb); | 173 pTab = sqlite3LocateTable(pParse, 0, zTable, zDb); |
| 177 if( pTab && IsVirtual(pTab) ){ | 174 if( pTab && IsVirtual(pTab) ){ |
| 178 pTab = 0; | 175 pTab = 0; |
| 179 sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable); | 176 sqlite3ErrorMsg(pParse, "cannot open virtual table: %s", zTable); |
| 180 } | 177 } |
| 178 if( pTab && !HasRowid(pTab) ){ |
| 179 pTab = 0; |
| 180 sqlite3ErrorMsg(pParse, "cannot open table without rowid: %s", zTable); |
| 181 } |
| 181 #ifndef SQLITE_OMIT_VIEW | 182 #ifndef SQLITE_OMIT_VIEW |
| 182 if( pTab && pTab->pSelect ){ | 183 if( pTab && pTab->pSelect ){ |
| 183 pTab = 0; | 184 pTab = 0; |
| 184 sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable); | 185 sqlite3ErrorMsg(pParse, "cannot open view: %s", zTable); |
| 185 } | 186 } |
| 186 #endif | 187 #endif |
| 187 if( !pTab ){ | 188 if( !pTab ){ |
| 188 if( pParse->zErrMsg ){ | 189 if( pParse->zErrMsg ){ |
| 189 sqlite3DbFree(db, zErr); | 190 sqlite3DbFree(db, zErr); |
| 190 zErr = pParse->zErrMsg; | 191 zErr = pParse->zErrMsg; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 for(j=0; j<pFKey->nCol; j++){ | 229 for(j=0; j<pFKey->nCol; j++){ |
| 229 if( pFKey->aCol[j].iFrom==iCol ){ | 230 if( pFKey->aCol[j].iFrom==iCol ){ |
| 230 zFault = "foreign key"; | 231 zFault = "foreign key"; |
| 231 } | 232 } |
| 232 } | 233 } |
| 233 } | 234 } |
| 234 } | 235 } |
| 235 #endif | 236 #endif |
| 236 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ | 237 for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| 237 int j; | 238 int j; |
| 238 for(j=0; j<pIdx->nColumn; j++){ | 239 for(j=0; j<pIdx->nKeyCol; j++){ |
| 239 if( pIdx->aiColumn[j]==iCol ){ | 240 if( pIdx->aiColumn[j]==iCol ){ |
| 240 zFault = "indexed"; | 241 zFault = "indexed"; |
| 241 } | 242 } |
| 242 } | 243 } |
| 243 } | 244 } |
| 244 if( zFault ){ | 245 if( zFault ){ |
| 245 sqlite3DbFree(db, zErr); | 246 sqlite3DbFree(db, zErr); |
| 246 zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault); | 247 zErr = sqlite3MPrintf(db, "cannot open %s column for writing", zFault); |
| 247 rc = SQLITE_ERROR; | 248 rc = SQLITE_ERROR; |
| 248 sqlite3BtreeLeaveAll(db); | 249 sqlite3BtreeLeaveAll(db); |
| 249 goto blob_open_out; | 250 goto blob_open_out; |
| 250 } | 251 } |
| 251 } | 252 } |
| 252 | 253 |
| 253 pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(db); | 254 pBlob->pStmt = (sqlite3_stmt *)sqlite3VdbeCreate(pParse); |
| 254 assert( pBlob->pStmt || db->mallocFailed ); | 255 assert( pBlob->pStmt || db->mallocFailed ); |
| 255 if( pBlob->pStmt ){ | 256 if( pBlob->pStmt ){ |
| 256 Vdbe *v = (Vdbe *)pBlob->pStmt; | 257 Vdbe *v = (Vdbe *)pBlob->pStmt; |
| 257 int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); | 258 int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| 258 | 259 |
| 259 sqlite3VdbeAddOpList(v, sizeof(openBlob)/sizeof(VdbeOpList), openBlob); | |
| 260 | 260 |
| 261 | 261 sqlite3VdbeAddOp4Int(v, OP_Transaction, iDb, flags, |
| 262 /* Configure the OP_Transaction */ | 262 pTab->pSchema->schema_cookie, |
| 263 sqlite3VdbeChangeP1(v, 0, iDb); | 263 pTab->pSchema->iGeneration); |
| 264 sqlite3VdbeChangeP2(v, 0, flags); | 264 sqlite3VdbeChangeP5(v, 1); |
| 265 | 265 sqlite3VdbeAddOpList(v, ArraySize(openBlob), openBlob, iLn); |
| 266 /* Configure the OP_VerifyCookie */ | |
| 267 sqlite3VdbeChangeP1(v, 1, iDb); | |
| 268 sqlite3VdbeChangeP2(v, 1, pTab->pSchema->schema_cookie); | |
| 269 sqlite3VdbeChangeP3(v, 1, pTab->pSchema->iGeneration); | |
| 270 | 266 |
| 271 /* Make sure a mutex is held on the table to be accessed */ | 267 /* Make sure a mutex is held on the table to be accessed */ |
| 272 sqlite3VdbeUsesBtree(v, iDb); | 268 sqlite3VdbeUsesBtree(v, iDb); |
| 273 | 269 |
| 274 /* Configure the OP_TableLock instruction */ | 270 /* Configure the OP_TableLock instruction */ |
| 275 #ifdef SQLITE_OMIT_SHARED_CACHE | 271 #ifdef SQLITE_OMIT_SHARED_CACHE |
| 276 sqlite3VdbeChangeToNoop(v, 2, 1); | 272 sqlite3VdbeChangeToNoop(v, 1); |
| 277 #else | 273 #else |
| 278 sqlite3VdbeChangeP1(v, 2, iDb); | 274 sqlite3VdbeChangeP1(v, 1, iDb); |
| 279 sqlite3VdbeChangeP2(v, 2, pTab->tnum); | 275 sqlite3VdbeChangeP2(v, 1, pTab->tnum); |
| 280 sqlite3VdbeChangeP3(v, 2, flags); | 276 sqlite3VdbeChangeP3(v, 1, flags); |
| 281 sqlite3VdbeChangeP4(v, 2, pTab->zName, P4_TRANSIENT); | 277 sqlite3VdbeChangeP4(v, 1, pTab->zName, P4_TRANSIENT); |
| 282 #endif | 278 #endif |
| 283 | 279 |
| 284 /* Remove either the OP_OpenWrite or OpenRead. Set the P2 | 280 /* Remove either the OP_OpenWrite or OpenRead. Set the P2 |
| 285 ** parameter of the other to pTab->tnum. */ | 281 ** parameter of the other to pTab->tnum. */ |
| 286 sqlite3VdbeChangeToNoop(v, 4 - flags, 1); | 282 sqlite3VdbeChangeToNoop(v, 3 - flags); |
| 287 sqlite3VdbeChangeP2(v, 3 + flags, pTab->tnum); | 283 sqlite3VdbeChangeP2(v, 2 + flags, pTab->tnum); |
| 288 sqlite3VdbeChangeP3(v, 3 + flags, iDb); | 284 sqlite3VdbeChangeP3(v, 2 + flags, iDb); |
| 289 | 285 |
| 290 /* Configure the number of columns. Configure the cursor to | 286 /* Configure the number of columns. Configure the cursor to |
| 291 ** think that the table has one more column than it really | 287 ** think that the table has one more column than it really |
| 292 ** does. An OP_Column to retrieve this imaginary column will | 288 ** does. An OP_Column to retrieve this imaginary column will |
| 293 ** always return an SQL NULL. This is useful because it means | 289 ** always return an SQL NULL. This is useful because it means |
| 294 ** we can invoke OP_Column to fill in the vdbe cursors type | 290 ** we can invoke OP_Column to fill in the vdbe cursors type |
| 295 ** and offset cache without causing any IO. | 291 ** and offset cache without causing any IO. |
| 296 */ | 292 */ |
| 297 sqlite3VdbeChangeP4(v, 3+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32); | 293 sqlite3VdbeChangeP4(v, 2+flags, SQLITE_INT_TO_PTR(pTab->nCol+1),P4_INT32); |
| 298 sqlite3VdbeChangeP2(v, 7, pTab->nCol); | 294 sqlite3VdbeChangeP2(v, 6, pTab->nCol); |
| 299 if( !db->mallocFailed ){ | 295 if( !db->mallocFailed ){ |
| 300 sqlite3VdbeMakeReady(v, 1, 1, 1, 0, 0, 0); | 296 pParse->nVar = 1; |
| 297 pParse->nMem = 1; |
| 298 pParse->nTab = 1; |
| 299 sqlite3VdbeMakeReady(v, pParse); |
| 301 } | 300 } |
| 302 } | 301 } |
| 303 | 302 |
| 304 pBlob->flags = flags; | 303 pBlob->flags = flags; |
| 305 pBlob->iCol = iCol; | 304 pBlob->iCol = iCol; |
| 306 pBlob->db = db; | 305 pBlob->db = db; |
| 307 sqlite3BtreeLeaveAll(db); | 306 sqlite3BtreeLeaveAll(db); |
| 308 if( db->mallocFailed ){ | 307 if( db->mallocFailed ){ |
| 309 goto blob_open_out; | 308 goto blob_open_out; |
| 310 } | 309 } |
| 311 sqlite3_bind_int64(pBlob->pStmt, 1, iRow); | 310 sqlite3_bind_int64(pBlob->pStmt, 1, iRow); |
| 312 rc = blobSeekToRow(pBlob, iRow, &zErr); | 311 rc = blobSeekToRow(pBlob, iRow, &zErr); |
| 313 } while( (++nAttempt)<5 && rc==SQLITE_SCHEMA ); | 312 } while( (++nAttempt)<SQLITE_MAX_SCHEMA_RETRY && rc==SQLITE_SCHEMA ); |
| 314 | 313 |
| 315 blob_open_out: | 314 blob_open_out: |
| 316 if( rc==SQLITE_OK && db->mallocFailed==0 ){ | 315 if( rc==SQLITE_OK && db->mallocFailed==0 ){ |
| 317 *ppBlob = (sqlite3_blob *)pBlob; | 316 *ppBlob = (sqlite3_blob *)pBlob; |
| 318 }else{ | 317 }else{ |
| 319 if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt); | 318 if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt); |
| 320 sqlite3DbFree(db, pBlob); | 319 sqlite3DbFree(db, pBlob); |
| 321 } | 320 } |
| 322 sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr); | 321 sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); |
| 323 sqlite3DbFree(db, zErr); | 322 sqlite3DbFree(db, zErr); |
| 323 sqlite3ParserReset(pParse); |
| 324 sqlite3StackFree(db, pParse); | 324 sqlite3StackFree(db, pParse); |
| 325 rc = sqlite3ApiExit(db, rc); | 325 rc = sqlite3ApiExit(db, rc); |
| 326 sqlite3_mutex_leave(db->mutex); | 326 sqlite3_mutex_leave(db->mutex); |
| 327 return rc; | 327 return rc; |
| 328 } | 328 } |
| 329 | 329 |
| 330 /* | 330 /* |
| 331 ** Close a blob handle that was previously created using | 331 ** Close a blob handle that was previously created using |
| 332 ** sqlite3_blob_open(). | 332 ** sqlite3_blob_open(). |
| 333 */ | 333 */ |
| (...skipping 30 matching lines...) Expand all Loading... |
| 364 sqlite3 *db; | 364 sqlite3 *db; |
| 365 | 365 |
| 366 if( p==0 ) return SQLITE_MISUSE_BKPT; | 366 if( p==0 ) return SQLITE_MISUSE_BKPT; |
| 367 db = p->db; | 367 db = p->db; |
| 368 sqlite3_mutex_enter(db->mutex); | 368 sqlite3_mutex_enter(db->mutex); |
| 369 v = (Vdbe*)p->pStmt; | 369 v = (Vdbe*)p->pStmt; |
| 370 | 370 |
| 371 if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){ | 371 if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){ |
| 372 /* Request is out of range. Return a transient error. */ | 372 /* Request is out of range. Return a transient error. */ |
| 373 rc = SQLITE_ERROR; | 373 rc = SQLITE_ERROR; |
| 374 sqlite3Error(db, SQLITE_ERROR, 0); | 374 sqlite3Error(db, SQLITE_ERROR); |
| 375 }else if( v==0 ){ | 375 }else if( v==0 ){ |
| 376 /* If there is no statement handle, then the blob-handle has | 376 /* If there is no statement handle, then the blob-handle has |
| 377 ** already been invalidated. Return SQLITE_ABORT in this case. | 377 ** already been invalidated. Return SQLITE_ABORT in this case. |
| 378 */ | 378 */ |
| 379 rc = SQLITE_ABORT; | 379 rc = SQLITE_ABORT; |
| 380 }else{ | 380 }else{ |
| 381 /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is | 381 /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is |
| 382 ** returned, clean-up the statement handle. | 382 ** returned, clean-up the statement handle. |
| 383 */ | 383 */ |
| 384 assert( db == v->db ); | 384 assert( db == v->db ); |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 | 444 |
| 445 if( p->pStmt==0 ){ | 445 if( p->pStmt==0 ){ |
| 446 /* If there is no statement handle, then the blob-handle has | 446 /* If there is no statement handle, then the blob-handle has |
| 447 ** already been invalidated. Return SQLITE_ABORT in this case. | 447 ** already been invalidated. Return SQLITE_ABORT in this case. |
| 448 */ | 448 */ |
| 449 rc = SQLITE_ABORT; | 449 rc = SQLITE_ABORT; |
| 450 }else{ | 450 }else{ |
| 451 char *zErr; | 451 char *zErr; |
| 452 rc = blobSeekToRow(p, iRow, &zErr); | 452 rc = blobSeekToRow(p, iRow, &zErr); |
| 453 if( rc!=SQLITE_OK ){ | 453 if( rc!=SQLITE_OK ){ |
| 454 sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr); | 454 sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); |
| 455 sqlite3DbFree(db, zErr); | 455 sqlite3DbFree(db, zErr); |
| 456 } | 456 } |
| 457 assert( rc!=SQLITE_SCHEMA ); | 457 assert( rc!=SQLITE_SCHEMA ); |
| 458 } | 458 } |
| 459 | 459 |
| 460 rc = sqlite3ApiExit(db, rc); | 460 rc = sqlite3ApiExit(db, rc); |
| 461 assert( rc==SQLITE_OK || p->pStmt==0 ); | 461 assert( rc==SQLITE_OK || p->pStmt==0 ); |
| 462 sqlite3_mutex_leave(db->mutex); | 462 sqlite3_mutex_leave(db->mutex); |
| 463 return rc; | 463 return rc; |
| 464 } | 464 } |
| 465 | 465 |
| 466 #endif /* #ifndef SQLITE_OMIT_INCRBLOB */ | 466 #endif /* #ifndef SQLITE_OMIT_INCRBLOB */ |
| OLD | NEW |