]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
If an error occurs within sqlite3_step() on a statement prepared using sqlite3_prepar...
authordan <dan@noemail.net>
Thu, 27 Oct 2011 15:19:58 +0000 (15:19 +0000)
committerdan <dan@noemail.net>
Thu, 27 Oct 2011 15:19:58 +0000 (15:19 +0000)
FossilOrigin-Name: 8f88cc4e616b4b30ed349f89e148f782da5cb6c4

manifest
manifest.uuid
src/vdbeInt.h
src/vdbeapi.c
src/vdbeaux.c
test/errmsg.test [new file with mode: 0644]

index c430b8437492edbc1a9a2dbe02d862b1f9ae8047..4afcf632ed1fe839c241039f4bca004541e7df29 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Avoid\sa\sharmless\sreference\sto\san\suninitialized\svariable\sfollowing\san\nerror\sin\sFTS3.\s\sThis\sis\snot\sa\sbug.\s\sThe\schange\sis\sto\ssilence\sa\svalgrind\nwarning.
-D 2011-10-22T21:00:46.835
+C If\san\serror\soccurs\swithin\ssqlite3_step()\son\sa\sstatement\sprepared\susing\ssqlite3_prepare_v2(),\stransfer\sboth\sthe\serror\scode\sand\serror\smessage\sto\sthe\sdatabase\shandle\sbefore\ssqlite3_step()\sreturns\s(so\sthat\sthey\sare\savailable\svia\ssqlite3_errcode()\sand\ssqlite3_errmsg().\sPrior\sto\sthis\scommit,\sonly\sthe\serror\scode\swas\stransfered.\sThe\serror\smessage\swas\snot\savailable\suntil\safter\seither\ssqlite3_reset()\sor\ssqlite3_finalize()\shad\sbeen\scalled\son\sthe\sstatement\shandle.
+D 2011-10-27T15:19:58.880
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in a162fe39e249b8ed4a65ee947c30152786cfe897
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -240,9 +240,9 @@ F src/util.c df83983bd57057df4951516880066b42b7055269
 F src/vacuum.c 0c0ba2242355c6048d65e2b333abe0f7c06348fa
 F src/vdbe.c 326994a64a9a08853122200dc9f62cb96b8f0831
 F src/vdbe.h f0725ee997db869ecae5bb70a71612aabeca7755
-F src/vdbeInt.h 693d6ac6810298fc6b4c503cfbe3f99a240f40af
-F src/vdbeapi.c 11dc47987abacb76ad016dcf5abc0dc422482a98
-F src/vdbeaux.c 5bd4886b444051b779eb4a2e27e46a5deb65c0fd
+F src/vdbeInt.h 9498fc98a2c9e349a4ef13455ff5a3e898f40176
+F src/vdbeapi.c 4dbba7f94f127f6ea8d2d0505ee1f98e5ffbf546
+F src/vdbeaux.c 9cb5c1a8f6b592059372cb8a5f774bdbf5b85853
 F src/vdbeblob.c 32f2a4899d67f69634ea4dd93e3f651936d732cb
 F src/vdbemem.c 2fc78b3e0fabcc1eaa23cd79dd2e30e6dcfe1e56
 F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
@@ -392,6 +392,7 @@ F test/enc2.test 796c59832e2b9a52842f382ffda8f3e989db03ad
 F test/enc3.test 90683ad0e6ea587b9d5542ca93568af9a9858c40
 F test/enc4.test c8f1ce3618508fd0909945beb8b8831feef2c020
 F test/eqp.test f14fadd76da53405e9885e2431cacf7191d83cdb
+F test/errmsg.test 3bb606db9d040cc6854459f8f5e5a2bcd9b7fd2a
 F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
 F test/exclusive.test a1b324cb21834a490cd052d409d34789cfef57cb
 F test/exclusive2.test 372be98f6de44dd78734e364b7b626ea211761a6
@@ -971,7 +972,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
-P aed2bf7a3c828a7191389b3f8235a9387977b476
-R 581537dd5ceacce0228b1e700fb5fa3e
-U drh
-Z b9c4b650240d28ae14b5d71fc3a026c4
+P d980c5b22fd700afb3cac5de5501c9350f2f589e
+R ae51b75095c5b5f8c67203e309153d5d
+U dan
+Z bb68bef02a5a1fffaf7c3c37d61664aa
index deedc7ab0b5c7e9b504fb86e52580864cd7eb463..0f87fa2b4d49658a821faf8724e8701c98f9ca21 100644 (file)
@@ -1 +1 @@
-d980c5b22fd700afb3cac5de5501c9350f2f589e
\ No newline at end of file
+8f88cc4e616b4b30ed349f89e148f782da5cb6c4
\ No newline at end of file
index 7fbd5693fba5ef5c76efefd6111c81ca0ce48f28..803ae1630e4d4fa9f2ac9ba87d0256c72637fac7 100644 (file)
@@ -395,6 +395,7 @@ 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
index 678f0d91e7a37f333527e24d0866e445f7af0ff5..adc9dba2f10b79caa5e89f1d86840f86efb73337 100644 (file)
@@ -454,7 +454,7 @@ end_of_step:
     ** 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 = db->errCode = p->rc;
+    rc = sqlite3VdbeTransferError(p);
   }
   return (rc&db->errMask);
 }
index 15b28ab90a7006f950868ec33fbd8636935d6d69..931114e62cada52e4b49a694749c6fc73edeaf13 100644 (file)
@@ -2310,6 +2310,28 @@ 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.
@@ -2337,18 +2359,9 @@ int sqlite3VdbeReset(Vdbe *p){
   ** instructions yet, leave the main database error information unchanged.
   */
   if( p->pc>=0 ){
-    if( p->zErrMsg ){
-      sqlite3BeginBenignMalloc();
-      sqlite3ValueSetStr(db->pErr,-1,p->zErrMsg,SQLITE_UTF8,SQLITE_TRANSIENT);
-      sqlite3EndBenignMalloc();
-      db->errCode = p->rc;
-      sqlite3DbFree(db, p->zErrMsg);
-      p->zErrMsg = 0;
-    }else if( p->rc ){
-      sqlite3Error(db, p->rc, 0);
-    }else{
-      sqlite3Error(db, SQLITE_OK, 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
diff --git a/test/errmsg.test b/test/errmsg.test
new file mode 100644 (file)
index 0000000..9f8409b
--- /dev/null
@@ -0,0 +1,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