From 37ed48ed2fd1918b43f8ffdbf96dce8fcf8fb64c Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 5 Aug 2003 13:13:38 +0000 Subject: [PATCH] Provide a more informative error message when a uniqueness constraint fails. Ticket #419. (CVS 1068) FossilOrigin-Name: 086aa1c9922b7bf399b3ee8b73ba7353d126b119 --- manifest | 28 ++++++++++++++-------------- manifest.uuid | 2 +- src/insert.c | 26 ++++++++++++++++++++++++-- test/capi2.test | 6 +++--- test/conflict.test | 28 ++++++++++++++-------------- test/copy.test | 4 ++-- test/memdb.test | 4 ++-- test/misc1.test | 4 ++-- test/trigger2.test | 12 ++++++------ test/unique.test | 41 ++++++++++++++++++++++++++++++++++++----- test/update.test | 6 +++--- 11 files changed, 107 insertions(+), 54 deletions(-) diff --git a/manifest b/manifest index 65e7fbdc58..c640f49a85 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C The\s{quote:\sSrcList}\sobject\swas\snot\sbeing\sexpanded\scorrectly\sby\sa\scall\sto\r\nsqliteSrcListAppend()\sif\sthe\s{quote:\sSrcList}\shad\spreviously\sbeen\sduplicated\sby\r\na\scall\sto\ssqliteSrcListDup().\s\sTicket\s#416.\sThis\scheck-in\sfixes\sthat\sproblem\r\nby\skeeping\sa\sseparate\snAlloc\sfield\son\s{quote:\sSrcList}.\s\sA\ssimilar\schange\sis\smade\r\nto\s{quote:\sIdList}\sand\s{quote:\sExprList}\sto\savoid\sfuture\sproblems.\s(CVS\s1067) -D 2003-07-30T12:34:12 +C Provide\sa\smore\sinformative\serror\smessage\swhen\sa\suniqueness\sconstraint\nfails.\s\sTicket\s#419.\s(CVS\s1068) +D 2003-08-05T13:13:38 F Makefile.in 9ad23ed4ca97f9670c4496432e3fbd4b3760ebde F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -32,7 +32,7 @@ F src/expr.c 03c321ac66c1e998c2e0faf22184b5a808b559ca F src/func.c 6b23578d48a8be98a664db145a635c2fa9ddb57b F src/hash.c 058f077c1f36f266581aa16f907a3903abf64aa3 F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8 -F src/insert.c fc4c26a0bb505fb802babfb9a7b7a1d4be2e3061 +F src/insert.c dc200ae04a36bd36e575272a069e20c528b7fbdf F src/main.c 2500392bad5629b6d70b06ac5a076958acb49b92 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 F src/os.c b0ae51da6e2ec7dd9f48f92ac88985d5fde8c1d5 @@ -74,9 +74,9 @@ F test/btree3.test e597fb59be2ac0ea69c62aaa2064e998e528b665 F test/btree3rb.test 127efcf5cdfcc352054e7db12622b01cdd8b36ac F test/btree4.test fa955a3d7a8bc91d6084b7f494f9e5d1bdfb15b6 F test/btree4rb.test ae6f0438512edcb45cf483471cd6070a765963a9 -F test/capi2.test 9634deaa27449e684f4b69ea2ccd8a77ee130bb8 -F test/conflict.test 0a66a573b8b4f8b781b2ebb7d4f27dcfd9e87312 -F test/copy.test c860847f1bd66175ef7cb724326a1700e0295820 +F test/capi2.test ec96e0e235d87b53cbaef3d8e3e0f8ccf32c71ca +F test/conflict.test 0911bb2f079046914a6e9c3341b36658c4e2103e +F test/copy.test cfd2e9cd738081d9c0a3977acd9e4d0538afde84 F test/delete.test 92256384f1801760180ded129f7427884cf28886 F test/expr.test 48bc6400627532ec97e233809e33d336468bc84c F test/fkey1.test d65c824459916249bee501532d6154ddab0b5db7 @@ -93,10 +93,10 @@ F test/limit.test fa2a8b3fe377ebe60e0bc9a6a35af9ac4eb3d2b3 F test/lock.test 388a3a10962d2d571c0c1821cc35bf069ee73473 F test/main.test 6a851b5992c4881a725a3d9647e629199df8de9d F test/malloc.test 7ba32a9ebd3aeed52ae4aaa6d42ca37e444536fd -F test/memdb.test cd4580f466f34c42354612a375c5adb90447e4c4 +F test/memdb.test 6ece25c7c0e6500199d3662607a3edca081abb2a F test/memleak.test a18e6810cae96d2f6f5136920267adbefc8e1e90 F test/minmax.test 6d9b6d6ee34f42e2a58dffece1f76d35f446b3af -F test/misc1.test c7dc2f2bd702d8283e885a64ec0714be26cfb051 +F test/misc1.test 0b98d493b0cf55cb5f53e1f3df8107c166eecb5a F test/misc2.test 6400032fe041360f717f501930585498853d79ae F test/misuse.test a3aa2b18a97e4c409a1fcaff5151a4dd804a0162 F test/notnull.test 7a08117a71e74b0321aaa937dbeb41a09d6eb1d0 @@ -122,11 +122,11 @@ F test/temptable.test c82bd6f800f10e8cf96921af6315e5f1c21e2692 F test/tester.tcl 2671536d3650c29e7c105219f277568b0884cb58 F test/trans.test 75e7a171b5d2d94ee56766459113e2ad0e5f809d F test/trigger1.test 6efd402da3b74e2d9e6a42b8a97413575fbf48f6 -F test/trigger2.test b17223c35fe97bdca542a049774a2496afef0bb9 +F test/trigger2.test 22aa0519ae18cf83568c7fba7b8cee893dd6b824 F test/trigger3.test a95ccace88291449f5eae7139ec438a42f90654d F test/trigger4.test 542afce45774e8f8e1130b96b8675f414d6e4bd8 -F test/unique.test 426580d01af47d44bea67aaf66007bd41a63e841 -F test/update.test 3ddb0ece1f99ae4deeaa6e6798a0608e167f9444 +F test/unique.test 0e38d4cc7affeef2527720d1dafd1f6870f02f2b +F test/update.test 2ef5a6655f2966f0aef733a9f4495b3fe8e16809 F test/vacuum.test 4d8c8af30338577af03e563bc815d7898ae65258 F test/version.test 605fd0d7e7d571370c32b12dbf395b58953de246 F test/view.test 1ee12c6f8f4791a2c0655120d5562a49400cfe53 @@ -168,7 +168,7 @@ F www/speed.tcl 2f6b1155b99d39adb185f900456d1d592c4832b3 F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 -P 09c10fe3c99cffc64ed02c2929f206d99c8e3309 -R d2bc63b0694faef8c02f9403066fd889 +P da6273255471673841fdcadc688aeac80722e130 +R 1c0d64f5eac1f91d3d759569b9f6d88e U drh -Z 6699c88f8cb611bb62eca292eb62c177 +Z cf08853c7690373b766f29a37d61c34c diff --git a/manifest.uuid b/manifest.uuid index 744565273d..038e22f133 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -da6273255471673841fdcadc688aeac80722e130 \ No newline at end of file +086aa1c9922b7bf399b3ee8b73ba7353d126b119 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index 7c2b61175e..b61572caf4 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.88 2003/06/04 16:24:39 drh Exp $ +** $Id: insert.c,v 1.89 2003/08/05 13:13:38 drh Exp $ */ #include "sqliteInt.h" @@ -817,8 +817,30 @@ void sqliteGenerateConstraintChecks( case OE_Rollback: case OE_Abort: case OE_Fail: { + int j, n1, n2; + char zErrMsg[200]; + strcpy(zErrMsg, pIdx->nColumn>1 ? "columns " : "column "); + n1 = strlen(zErrMsg); + for(j=0; jnColumn && n1aCol[pIdx->aiColumn[j]].zName; + n2 = strlen(zCol); + if( j>0 ){ + strcpy(&zErrMsg[n1], ", "); + n1 += 2; + } + if( n1+n2>sizeof(zErrMsg)-30 ){ + strcpy(&zErrMsg[n1], "..."); + n1 += 3; + break; + }else{ + strcpy(&zErrMsg[n1], zCol); + n1 += n2; + } + } + strcpy(&zErrMsg[n1], + pIdx->nColumn>1 ? " are not unique" : " is not unique"); sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError); - sqliteVdbeChangeP3(v, -1, "uniqueness constraint failed", P3_STATIC); + sqliteVdbeChangeP3(v, -1, sqliteStrDup(zErrMsg), P3_DYNAMIC); break; } case OE_Ignore: { diff --git a/test/capi2.test b/test/capi2.test index d6866a45a1..92073e0ac5 100644 --- a/test/capi2.test +++ b/test/capi2.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script testing the callback-free C/C++ API. # -# $Id: capi2.test,v 1.9 2003/07/09 00:28:15 drh Exp $ +# $Id: capi2.test,v 1.10 2003/08/05 13:13:38 drh Exp $ # set testdir [file dirname $argv0] @@ -178,7 +178,7 @@ do_test capi2-3.13 { do_test capi2-3.13b {db changes} {0} do_test capi2-3.14 { list [catch {sqlite_finalize $VM} msg] [set msg] -} {1 {(19) uniqueness constraint failed}} +} {1 {(19) column a is not unique}} do_test capi2-3.15 { set VM [sqlite_compile $DB {CREATE TABLE t2(a NOT NULL, b)} TAIL] set TAIL @@ -386,7 +386,7 @@ do_test capi2-6.27 { INSERT INTO t1 VALUES(2,4,5); SELECT * FROM t1; } -} {1 {uniqueness constraint failed}} +} {1 {column a is not unique}} do_test capi2-6.28 { list [sqlite_step $VM1 N VALUE COLNAME] [set N] [set VALUE] [set COLNAME] } {SQLITE_ROW 1 13 {x counter}} diff --git a/test/conflict.test b/test/conflict.test index 95b042d84b..925c161fab 100644 --- a/test/conflict.test +++ b/test/conflict.test @@ -13,7 +13,7 @@ # This file implements tests for the conflict resolution extension # to SQLite. # -# $Id: conflict.test,v 1.18 2003/06/15 23:42:25 drh Exp $ +# $Id: conflict.test,v 1.19 2003/08/05 13:13:39 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -363,7 +363,7 @@ foreach {i conf1 conf2 cmd t0 t1 t2} { 25 IGNORE ABORT UPDATE 1 {1 2 3 4} 1 26 REPLACE ROLLBACK UPDATE 1 {1 2 3 4} 0 } { - if {$t0} {set t1 {uniqueness constraint failed}} + if {$t0} {set t1 {column a is not unique}} do_test conflict-6.$i { if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"} if {$conf2!=""} {set conf2 "ON CONFLICT $conf2"} @@ -539,13 +539,13 @@ do_test conflict-9.5 { INSERT INTO t2 VALUES(3,1,3,3,3); SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column b is not unique}} do_test conflict-9.6 { catchsql { UPDATE t2 SET b=b+1 WHERE b=1; SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column b is not unique}} do_test conflict-9.7 { catchsql { BEGIN; @@ -553,7 +553,7 @@ do_test conflict-9.7 { INSERT INTO t2 VALUES(3,1,3,3,3); SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column b is not unique}} do_test conflict-9.8 { execsql {COMMIT} execsql {SELECT * FROM t3} @@ -565,7 +565,7 @@ do_test conflict-9.9 { UPDATE t2 SET b=b+1 WHERE b=1; SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column b is not unique}} do_test conflict-9.10 { execsql {COMMIT} execsql {SELECT * FROM t3} @@ -575,13 +575,13 @@ do_test conflict-9.11 { INSERT INTO t2 VALUES(3,3,3,1,3); SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column d is not unique}} do_test conflict-9.12 { catchsql { UPDATE t2 SET d=d+1 WHERE d=1; SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column d is not unique}} do_test conflict-9.13 { catchsql { BEGIN; @@ -589,7 +589,7 @@ do_test conflict-9.13 { INSERT INTO t2 VALUES(3,3,3,1,3); SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column d is not unique}} do_test conflict-9.14 { execsql {COMMIT} execsql {SELECT * FROM t3} @@ -601,7 +601,7 @@ do_test conflict-9.15 { UPDATE t2 SET d=d+1 WHERE d=1; SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column d is not unique}} do_test conflict-9.16 { execsql {COMMIT} execsql {SELECT * FROM t3} @@ -611,13 +611,13 @@ do_test conflict-9.17 { INSERT INTO t2 VALUES(3,3,3,3,1); SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column e is not unique}} do_test conflict-9.18 { catchsql { UPDATE t2 SET e=e+1 WHERE e=1; SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column e is not unique}} do_test conflict-9.19 { catchsql { BEGIN; @@ -625,7 +625,7 @@ do_test conflict-9.19 { INSERT INTO t2 VALUES(3,3,3,3,1); SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column e is not unique}} do_test conflict-9.20 { catch {execsql {COMMIT}} execsql {SELECT * FROM t3} @@ -637,7 +637,7 @@ do_test conflict-9.21 { UPDATE t2 SET e=e+1 WHERE e=1; SELECT * FROM t2; } -} {1 {uniqueness constraint failed}} +} {1 {column e is not unique}} do_test conflict-9.22 { catch {execsql {COMMIT}} execsql {SELECT * FROM t3} diff --git a/test/copy.test b/test/copy.test index d439b51b63..37301c9f30 100644 --- a/test/copy.test +++ b/test/copy.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the COPY statement. # -# $Id: copy.test,v 1.14 2003/06/02 22:50:27 drh Exp $ +# $Id: copy.test,v 1.15 2003/08/05 13:13:39 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -196,7 +196,7 @@ do_test copy-5.2 { COPY t1 FROM 'data6.txt' USING DELIMITERS '|'; SELECT * FROM t1; } -} {1 {uniqueness constraint failed}} +} {1 {column b is not unique}} do_test copy-5.3 { set fd [open data6.txt w] puts $fd "33|22|44" diff --git a/test/memdb.test b/test/memdb.test index b03d0caaa3..383b927ecd 100644 --- a/test/memdb.test +++ b/test/memdb.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is in-memory database backend. # -# $Id: memdb.test,v 1.5 2003/06/15 23:42:25 drh Exp $ +# $Id: memdb.test,v 1.6 2003/08/05 13:13:39 drh Exp $ set testdir [file dirname $argv0] @@ -253,7 +253,7 @@ foreach {i conf1 conf2 cmd t0 t1 t2} { 25 IGNORE ABORT UPDATE 1 {1 2 3 4} 1 26 REPLACE ROLLBACK UPDATE 1 {1 2 3 4} 0 } { - if {$t0} {set t1 {uniqueness constraint failed}} + if {$t0} {set t1 {column a is not unique}} do_test memdb-5.$i { if {$conf1!=""} {set conf1 "ON CONFLICT $conf1"} if {$conf2!=""} {set conf2 "ON CONFLICT $conf2"} diff --git a/test/misc1.test b/test/misc1.test index d2f1b7a7e9..4ddea47b79 100644 --- a/test/misc1.test +++ b/test/misc1.test @@ -13,7 +13,7 @@ # This file implements tests for miscellanous features that were # left out of other test files. # -# $Id: misc1.test,v 1.22 2003/06/03 01:47:12 drh Exp $ +# $Id: misc1.test,v 1.23 2003/08/05 13:13:39 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -222,7 +222,7 @@ do_test misc1-7.4 { catchsql { INSERT INTO t5 VALUES(1,2,4); } -} {1 {uniqueness constraint failed}} +} {1 {columns a, b are not unique}} do_test misc1-7.5 { catchsql { INSERT INTO t5 VALUES(0,2,4); diff --git a/test/trigger2.test b/test/trigger2.test index b0bcfdc3d9..eb3d4f63e5 100644 --- a/test/trigger2.test +++ b/test/trigger2.test @@ -472,7 +472,7 @@ do_test trigger2-6.1b { catchsql { INSERT OR ABORT INTO tbl values (2, 2, 3); } -} {1 {uniqueness constraint failed}} +} {1 {column a is not unique}} do_test trigger2-6.1c { execsql { SELECT * from tbl; @@ -482,7 +482,7 @@ do_test trigger2-6.1d { catchsql { INSERT OR FAIL INTO tbl values (2, 2, 3); } -} {1 {uniqueness constraint failed}} +} {1 {column a is not unique}} do_test trigger2-6.1e { execsql { SELECT * from tbl; @@ -498,7 +498,7 @@ do_test trigger2-6.1g { catchsql { INSERT OR ROLLBACK INTO tbl values (3, 2, 3); } -} {1 {uniqueness constraint failed}} +} {1 {column a is not unique}} do_test trigger2-6.1h { execsql { SELECT * from tbl; @@ -526,7 +526,7 @@ do_test trigger2-6.2b { catchsql { UPDATE OR ABORT tbl SET a = 4 WHERE a = 1; } -} {1 {uniqueness constraint failed}} +} {1 {column a is not unique}} do_test trigger2-6.2c { execsql { SELECT * from tbl; @@ -536,7 +536,7 @@ do_test trigger2-6.2d { catchsql { UPDATE OR FAIL tbl SET a = 4 WHERE a = 1; } -} {1 {uniqueness constraint failed}} +} {1 {column a is not unique}} do_test trigger2-6.2e { execsql { SELECT * from tbl; @@ -558,7 +558,7 @@ do_test trigger2-6.2g { catchsql { UPDATE OR ROLLBACK tbl SET a = 4 WHERE a = 1; } -} {1 {uniqueness constraint failed}} +} {1 {column a is not unique}} do_test trigger2-6.2h { execsql { SELECT * from tbl; diff --git a/test/unique.test b/test/unique.test index b483b25713..63d1c37b46 100644 --- a/test/unique.test +++ b/test/unique.test @@ -12,7 +12,7 @@ # focus of this file is testing the CREATE UNIQUE INDEX statement, # and primary keys, and the UNIQUE constraint on table columns # -# $Id: unique.test,v 1.6 2003/06/15 23:42:25 drh Exp $ +# $Id: unique.test,v 1.7 2003/08/05 13:13:39 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -47,7 +47,7 @@ do_test unique-1.3 { catchsql { INSERT INTO t1(a,b,c) VALUES(1,3,4) } -} {1 {uniqueness constraint failed}} +} {1 {column a is not unique}} do_test unique-1.4 { execsql { SELECT * FROM t1 ORDER BY a; @@ -57,7 +57,7 @@ do_test unique-1.5 { catchsql { INSERT INTO t1(a,b,c) VALUES(3,2,4) } -} {1 {uniqueness constraint failed}} +} {1 {column b is not unique}} do_test unique-1.6 { execsql { SELECT * FROM t1 ORDER BY a; @@ -98,7 +98,7 @@ do_test unique-2.3 { catchsql { INSERT INTO t2 VALUES(1,5); } -} {1 {uniqueness constraint failed}} +} {1 {column a is not unique}} do_test unique-2.4 { catchsql { SELECT * FROM t2 ORDER BY a @@ -162,7 +162,7 @@ do_test unique-3.4 { INSERT INTO t3(a,b,c,d) VALUES(1,4,3,5); SELECT * FROM t3 ORDER BY a,b,c,d; } -} {1 {uniqueness constraint failed}} +} {1 {columns a, c, d are not unique}} integrity_check unique-3.5 # Make sure NULLs are distinct as far as the UNIQUE tests are @@ -198,4 +198,35 @@ do_test unique-4.5 { } {1 2 3 {} 2 {} {} 3 4 2 2 {}} integrity_check unique-4.6 +# Test the error message generation logic. In particular, make sure we +# do not overflow the static buffer used to generate the error message. +# +do_test unique-5.1 { + execsql { + CREATE TABLE t5( + first_column_with_long_name, + second_column_with_long_name, + third_column_with_long_name, + fourth_column_with_long_name, + fifth_column_with_long_name, + sixth_column_with_long_name, + UNIQUE( + first_column_with_long_name, + second_column_with_long_name, + third_column_with_long_name, + fourth_column_with_long_name, + fifth_column_with_long_name, + sixth_column_with_long_name + ) + ); + INSERT INTO t5 VALUES(1,2,3,4,5,6); + SELECT * FROM t5; + } +} {1 2 3 4 5 6} +do_test unique-5.2 { + catchsql { + INSERT INTO t5 VALUES(1,2,3,4,5,6); + } +} {1 {columns first_column_with_long_name, second_column_with_long_name, third_column_with_long_name, fourth_column_with_long_name, fifth_column_with_long_name, ... are not unique}} + finish_test diff --git a/test/update.test b/test/update.test index c59a64039d..049370f9bf 100644 --- a/test/update.test +++ b/test/update.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this file is testing the UPDATE statement. # -# $Id: update.test,v 1.13 2003/06/15 23:42:25 drh Exp $ +# $Id: update.test,v 1.14 2003/08/05 13:13:39 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -457,7 +457,7 @@ do_test update-10.6 { UPDATE t1 SET b=2, e=12 WHERE f=7; SELECT * FROM t1; } -} {1 {uniqueness constraint failed}} +} {1 {column b is not unique}} do_test update-10.7 { catchsql { SELECT * FROM t1; @@ -474,7 +474,7 @@ do_test update-10.9 { UPDATE t1 SET c=3, d=4, e=14 WHERE f=7; SELECT * FROM t1; } -} {1 {uniqueness constraint failed}} +} {1 {columns c, d are not unique}} do_test update-10.10 { catchsql { SELECT * FROM t1;