Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | If an error occurs within sqlite3_step() on a statement prepared using sqlite3_prepare_v2(), transfer both the error code and error message to the database handle before sqlite3_step() returns (so that they are available via sqlite3_errcode() and sqlite3_errmsg(). Prior to this commit, only the error code was transfered. The error message was not available until after either sqlite3_reset() or sqlite3_finalize() had been called on the statement handle. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
8f88cc4e616b4b30ed349f89e148f782 |
User & Date: | dan 2011-10-27 15:19:58.880 |
References
2011-10-31
| ||
06:52 | Update fts3fault.test to account for the sqlite3_errmsg() related changes in [8f88cc4e61] and [dcb7879347]. (check-in: 3f2d49c678 user: dan tags: trunk) | |
2011-10-29
| ||
19:25 | Update fkey_malloc.test to account for the sqlite3_errmsg() related changes in [8f88cc4e61] and [dcb7879347]. (check-in: 5b82ec6fbb user: dan tags: trunk) | |
Context
2011-10-29
| ||
01:33 | Avoid reporting a NOMEM error if a memory allocation fails while copying the error message from a prepared statement into the database connection. (check-in: dcb7879347 user: drh tags: trunk) | |
2011-10-27
| ||
15:19 | If an error occurs within sqlite3_step() on a statement prepared using sqlite3_prepare_v2(), transfer both the error code and error message to the database handle before sqlite3_step() returns (so that they are available via sqlite3_errcode() and sqlite3_errmsg(). Prior to this commit, only the error code was transfered. The error message was not available until after either sqlite3_reset() or sqlite3_finalize() had been called on the statement handle. (check-in: 8f88cc4e61 user: dan tags: trunk) | |
2011-10-22
| ||
21:00 | Avoid a harmless reference to an uninitialized variable following an error in FTS3. This is not a bug. The change is to silence a valgrind warning. (check-in: d980c5b22f user: drh tags: trunk) | |
Changes
Changes to src/vdbeInt.h.
︙ | ︙ | |||
391 392 393 394 395 396 397 398 399 400 401 402 403 404 | int sqlite3VdbeMemFinalize(Mem*, FuncDef*); const char *sqlite3OpcodeName(int); int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); int sqlite3VdbeCloseStatement(Vdbe *, int); void sqlite3VdbeFrameDelete(VdbeFrame*); int sqlite3VdbeFrameRestore(VdbeFrame *); void sqlite3VdbeMemStoreType(Mem *pMem); #ifdef SQLITE_OMIT_MERGE_SORT # define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK # define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterClose(Y,Z) # define sqlite3VdbeSorterRowkey(Y,Z) SQLITE_OK # define sqlite3VdbeSorterRewind(X,Y,Z) SQLITE_OK | > | 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 | int sqlite3VdbeMemFinalize(Mem*, FuncDef*); const char *sqlite3OpcodeName(int); int sqlite3VdbeMemGrow(Mem *pMem, int n, int preserve); int sqlite3VdbeCloseStatement(Vdbe *, int); void sqlite3VdbeFrameDelete(VdbeFrame*); int sqlite3VdbeFrameRestore(VdbeFrame *); void sqlite3VdbeMemStoreType(Mem *pMem); int sqlite3VdbeTransferError(Vdbe *p); #ifdef SQLITE_OMIT_MERGE_SORT # define sqlite3VdbeSorterInit(Y,Z) SQLITE_OK # define sqlite3VdbeSorterWrite(X,Y,Z) SQLITE_OK # define sqlite3VdbeSorterClose(Y,Z) # define sqlite3VdbeSorterRowkey(Y,Z) SQLITE_OK # define sqlite3VdbeSorterRewind(X,Y,Z) SQLITE_OK |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
450 451 452 453 454 455 456 | ); assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE ); if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ /* If this statement was prepared using sqlite3_prepare_v2(), and an ** error has occured, then return the error code in p->rc to the ** caller. Set the error code in the database handle to the same value. */ | | | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | ); assert( p->rc!=SQLITE_ROW && p->rc!=SQLITE_DONE ); if( p->isPrepareV2 && rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ /* If this statement was prepared using sqlite3_prepare_v2(), and an ** error has occured, then return the error code in p->rc to the ** caller. Set the error code in the database handle to the same value. */ rc = sqlite3VdbeTransferError(p); } return (rc&db->errMask); } /* ** The maximum number of times that a statement will try to reparse ** itself before giving up and returning SQLITE_SCHEMA. |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 | /* ** Each VDBE holds the result of the most recent sqlite3_step() call ** in p->rc. This routine sets that result back to SQLITE_OK. */ void sqlite3VdbeResetStepResult(Vdbe *p){ p->rc = SQLITE_OK; } /* ** Clean up a VDBE after execution but do not delete the VDBE just yet. ** Write any error messages into *pzErrMsg. Return the result code. ** ** After this routine is run, the VDBE should be ready to be executed ** again. | > > > > > > > > > > > > > > > > > > > > > > | 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 | /* ** Each VDBE holds the result of the most recent sqlite3_step() call ** in p->rc. This routine sets that result back to SQLITE_OK. */ void sqlite3VdbeResetStepResult(Vdbe *p){ p->rc = SQLITE_OK; } /* ** Copy the error code and error message belonging to the VDBE passed ** as the first argument to its database handle (so that they will be ** returned by calls to sqlite3_errcode() and sqlite3_errmsg()). ** ** This function does not clear the VDBE error code or message, just ** copies them to the database handle. */ int sqlite3VdbeTransferError(Vdbe *p){ sqlite3 *db = p->db; int rc = p->rc; if( p->zErrMsg ){ sqlite3BeginBenignMalloc(); sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, SQLITE_TRANSIENT); sqlite3EndBenignMalloc(); db->errCode = rc; }else{ sqlite3Error(db, rc, 0); } return rc; } /* ** Clean up a VDBE after execution but do not delete the VDBE just yet. ** Write any error messages into *pzErrMsg. Return the result code. ** ** After this routine is run, the VDBE should be ready to be executed ** again. |
︙ | ︙ | |||
2333 2334 2335 2336 2337 2338 2339 | /* If the VDBE has be run even partially, then transfer the error code ** and error message from the VDBE into the main database structure. But ** if the VDBE has just been set to run but has not actually executed any ** instructions yet, leave the main database error information unchanged. */ if( p->pc>=0 ){ | < < < | < | | < < < < < | 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 | /* If the VDBE has be run even partially, then transfer the error code ** and error message from the VDBE into the main database structure. But ** if the VDBE has just been set to run but has not actually executed any ** instructions yet, leave the main database error information unchanged. */ if( p->pc>=0 ){ sqlite3VdbeTransferError(p); sqlite3DbFree(db, p->zErrMsg); p->zErrMsg = 0; if( p->runOnlyOnce ) p->expired = 1; }else if( p->rc && p->expired ){ /* The expired flag was set on the VDBE before the first call ** to sqlite3_step(). For consistency (since sqlite3_step() was ** called), set the database error in this case as well. */ sqlite3Error(db, p->rc, 0); |
︙ | ︙ |
Added test/errmsg.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 | # 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. # #*********************************************************************** # Test that if sqlite3_prepare_v2() is used to prepare a query, the # error-message associated with an sqlite3_step() error is available # immediately. Whereas if sqlite3_prepare() is used, it is not available # until sqlite3_finalize() or sqlite3_reset() has been called. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix errmsg # Test organization: # # errmsg-1.* User-defined SQL function errors # errmsg-2.* Errors generated by the VDBE (constraint failures etc.) # errmsg-3.* SQLITE_SCHEMA and statement recompilation errors. # proc error_messages_worker {prepare sql schema} { set ret [list] set stmt [$prepare db $sql -1 dummy] execsql $schema lappend ret [sqlite3_step $stmt] lappend ret [sqlite3_errmsg db] lappend ret [sqlite3_finalize $stmt] lappend ret [sqlite3_errmsg db] set ret } proc error_messages_v2 {sql {schema {}}} { error_messages_worker sqlite3_prepare_v2 $sql $schema } proc error_messages {sql {schema {}}} { error_messages_worker sqlite3_prepare $sql $schema } proc sql_error {msg} { error $msg } db func sql_error sql_error #------------------------------------------------------------------------- # Test error messages returned by user-defined SQL functions. # do_test 1.1 { error_messages "SELECT sql_error('custom message')" } [list {*}{ SQLITE_ERROR {SQL logic error or missing database} SQLITE_ERROR {custom message} }] do_test 1.2 { error_messages_v2 "SELECT sql_error('custom message')" } [list {*}{ SQLITE_ERROR {custom message} SQLITE_ERROR {custom message} }] #------------------------------------------------------------------------- # Test error messages generated directly by VDBE code (e.g. constraint # failures). # do_execsql_test 2.1 { CREATE TABLE t1(a PRIMARY KEY, b UNIQUE); INSERT INTO t1 VALUES('abc', 'def'); } do_test 2.2 { error_messages "INSERT INTO t1 VALUES('ghi', 'def')" } [list {*}{ SQLITE_ERROR {SQL logic error or missing database} SQLITE_CONSTRAINT {column b is not unique} }] do_test 2.3 { error_messages_v2 "INSERT INTO t1 VALUES('ghi', 'def')" } [list {*}{ SQLITE_CONSTRAINT {column b is not unique} SQLITE_CONSTRAINT {column b is not unique} }] #------------------------------------------------------------------------- # Test SQLITE_SCHEMA errors. And, for _v2(), test that if the schema # change invalidates the SQL statement itself the error message is returned # correctly. # do_execsql_test 3.1.1 { CREATE TABLE t2(a PRIMARY KEY, b UNIQUE); INSERT INTO t2 VALUES('abc', 'def'); } do_test 3.1.2 { error_messages "SELECT a FROM t2" "DROP TABLE t2" } [list {*}{ SQLITE_ERROR {SQL logic error or missing database} SQLITE_SCHEMA {database schema has changed} }] do_execsql_test 3.2.1 { CREATE TABLE t2(a PRIMARY KEY, b UNIQUE); INSERT INTO t2 VALUES('abc', 'def'); } do_test 3.2.2 { error_messages_v2 "SELECT a FROM t2" "DROP TABLE t2" } [list {*}{ SQLITE_ERROR {no such table: t2} SQLITE_ERROR {no such table: t2} }] finish_test |