}
#endif /* !defined(SQLITE_RTREE_INT_ONLY) */
+/*
+** A constraint has failed while inserting a row into an rtree table.
+** Assuming no OOM error occurs, this function sets the error message
+** (at pRtree->base.zErrMsg) to an appropriate value and returns
+** SQLITE_CONSTRAINT.
+**
+** Parameter iCol is the index of the leftmost column involved in the
+** constraint failure. If it is 0, then the constraint that failed is
+** the unique constraint on the id column. Otherwise, it is the rtree
+** (c1<=c2) constraint on columns iCol and iCol+1 that has failed.
+**
+** If an OOM occurs, SQLITE_NOMEM is returned instead of SQLITE_CONSTRAINT.
+*/
+static int rtreeConstraintError(Rtree *pRtree, int iCol){
+ sqlite3_stmt *pStmt = 0;
+ char *zSql;
+ int rc;
+
+ assert( iCol==0 || iCol%2 );
+ zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", pRtree->zDb, pRtree->zName);
+ if( zSql ){
+ rc = sqlite3_prepare_v2(pRtree->db, zSql, -1, &pStmt, 0);
+ }else{
+ rc = SQLITE_NOMEM;
+ }
+ sqlite3_free(zSql);
+
+ if( rc==SQLITE_OK ){
+ if( iCol==0 ){
+ const char *zCol = sqlite3_column_name(pStmt, 0);
+ pRtree->base.zErrMsg = sqlite3_mprintf(
+ "UNIQUE constraint failed: %s.%s", pRtree->zName, zCol
+ );
+ }else{
+ const char *zCol1 = sqlite3_column_name(pStmt, iCol);
+ const char *zCol2 = sqlite3_column_name(pStmt, iCol+1);
+ pRtree->base.zErrMsg = sqlite3_mprintf(
+ "rtree constraint failed: %s.(%s<=%s)", pRtree->zName, zCol1, zCol2
+ );
+ }
+ }
+
+ sqlite3_finalize(pStmt);
+ return (rc==SQLITE_OK ? SQLITE_CONSTRAINT : rc);
+}
+
+
/*
** The xUpdate method for rtree module virtual tables.
cell.aCoord[ii].f = rtreeValueDown(azData[ii+3]);
cell.aCoord[ii+1].f = rtreeValueUp(azData[ii+4]);
if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){
- rc = SQLITE_CONSTRAINT;
+ rc = rtreeConstraintError(pRtree, ii+1);
goto constraint;
}
}
cell.aCoord[ii].i = sqlite3_value_int(azData[ii+3]);
cell.aCoord[ii+1].i = sqlite3_value_int(azData[ii+4]);
if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){
- rc = SQLITE_CONSTRAINT;
+ rc = rtreeConstraintError(pRtree, ii+1);
goto constraint;
}
}
if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
rc = rtreeDeleteRowid(pRtree, cell.iRowid);
}else{
- rc = SQLITE_CONSTRAINT;
+ rc = rtreeConstraintError(pRtree, 0);
goto constraint;
}
}
do_test rtree-2.2.1 {
catchsql { INSERT INTO t1 VALUES(2, 1, 3, 2, 4) }
-} {1 {constraint failed}}
+} {1 {UNIQUE constraint failed: t1.ii}}
do_test rtree-2.2.2 {
catchsql { INSERT INTO t1 VALUES(4, 1, 3, 4, 2) }
-} {1 {constraint failed}}
+} {1 {rtree constraint failed: t1.(y1<=y2)}}
do_test rtree-2.2.3 {
catchsql { INSERT INTO t1 VALUES(4, 3, 1, 2, 4) }
-} {1 {constraint failed}}
+} {1 {rtree constraint failed: t1.(x1<=x2)}}
do_test rtree-2.2.4 {
execsql { SELECT ii FROM t1 ORDER BY ii }
} {1 2 3}
# Test the constraint on the coordinates (c[i]<=c[i+1] where (i%2==0)):
do_test rtree-3.2.1 {
catchsql { INSERT INTO t1 VALUES(7, 2, 6, 4, 3) }
-} {1 {constraint failed}}
+} {1 {rtree constraint failed: t1.(y1<=y2)}}
do_test rtree-3.2.2 {
catchsql { INSERT INTO t1 VALUES(8, 2, 6, 3, 3) }
} {0 {}}
}
4 "INSERT %CONF% INTO t1 VALUES(2, 7, 6, 7, 7)" {
- ROLLBACK 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6}
- ABORT 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
+ ROLLBACK 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6}
+ ABORT 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
IGNORE 0 0 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
- FAIL 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
- REPLACE 0 1 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
+ FAIL 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
+ REPLACE 0 2 {1 1 2 3 4 2 2 3 4 5 3 3 4 5 6 4 4 5 6 7}
}
} {
}
set res(0) {0 {}}
- set res(1) {1 {constraint failed}}
+ set res(1) {1 {UNIQUE constraint failed: t1.idx}}
+ set res(2) {1 {rtree constraint failed: t1.(x1<=x2)}}
+
do_catchsql_test $testname.1 $sql $res($error)
do_test $testname.2 [list sql_uses_stmt db $sql] $uses
do_execsql_test $testname.3 { SELECT * FROM t1 ORDER BY idx } $data
#
# rtree3-8: Test OOM while registering the r-tree module with sqlite.
#
-
+# rtree3-11: OOM following a constraint failure
+#
do_faultsim_test rtree3-1 -faults oom* -prep {
faultsim_delete_and_reopen
} -body {
faultsim_test_result {0 2}
}
+
+do_test rtree3-11.prep {
+ faultsim_delete_and_reopen
+ execsql {
+ CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2);
+ INSERT INTO rt VALUES(1, 2, 3, 4, 5);
+ }
+ faultsim_save_and_close
+} {}
+do_faultsim_test rtree3-10.1 -faults oom-* -prep {
+ faultsim_restore_and_reopen
+ execsql { SELECT * FROM rt }
+} -body {
+ execsql { INSERT INTO rt VALUES(1, 2, 3, 4, 5) }
+} -test {
+ faultsim_test_result {1 {UNIQUE constraint failed: rt.ii}} \
+ {1 {constraint failed}}
+}
+do_faultsim_test rtree3-10.2 -faults oom-* -prep {
+ faultsim_restore_and_reopen
+ execsql { SELECT * FROM rt }
+} -body {
+ execsql { INSERT INTO rt VALUES(2, 2, 3, 5, 4) }
+} -test {
+ faultsim_test_result {1 {rtree constraint failed: rt.(y1<=y2)}} \
+ {1 {constraint failed}}
+}
+
finish_test
-C Lemon\senhancement:\savoid\sunnecessary\sreduce\sactions\sthat\sconvert\sone\nnon-terminal\sinto\sanother\sbut\shave\sno\sside\seffects.
-D 2016-05-23T16:15:02.530
+C Improve\sthe\serror\smessages\sgenerated\sby\sthe\srtree\smodule\swhen\sa\sconstraint\sfails.
+D 2016-05-23T16:16:13.470
F Makefile.in f59e0763ff448719fc1bd25513882b0567286317
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 306d73e854b1a92ea06e5d1e637faa5c44de53c7
F ext/rbu/sqlite3rbu.h 2acd0a6344a6079de15c8dc9d84d3df83a665930
F ext/rbu/test_rbu.c 9bbdf6bd8efd58fbc4f192698df50569598fbb9e
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
-F ext/rtree/rtree.c 0b870ccb7b58b734a2a8e1e2755a7c0ded070920
+F ext/rtree/rtree.c 7ebca7d18261f402d67de9e151be7fb2ed62b8f5
F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e
-F ext/rtree/rtree1.test 96a80c08440c932cd72aac50660e7af2612d2cda
+F ext/rtree/rtree1.test 42dadfc7b44a436cd74a1bebc0b9b689e4eaf7ec
F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba
-F ext/rtree/rtree3.test a494da55c30ee0bc9b01a91c80c81b387b22d2dc
+F ext/rtree/rtree3.test 2cafe8265d1ff28f206fce88d114f208349df482
F ext/rtree/rtree4.test c8fe384f60ebd49540a5fecc990041bf452eb6e0
F ext/rtree/rtree5.test 6a510494f12454bf57ef28f45bc7764ea279431e
F ext/rtree/rtree6.test 773a90db2dce6a8353dd0d5b64bca69b29761196
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P b91a5b8297756289d45c8fce0d3399c253517eb0
-R e62078de0c6378c8386e96fef92b2fe6
-U drh
-Z f3f44e1ca319aa39a93bd7b358420b1f
+P a86e782ad1aa6f5a8b2c54f9dcf0fa61960843f3
+R 656cb7a661842081cb14458e0c90ff63
+U dan
+Z 1b4990ccdee5b0865b4104871945d857
-a86e782ad1aa6f5a8b2c54f9dcf0fa61960843f3
\ No newline at end of file
+3ad2531efb64b7c53b777ddf3681203217052b32
\ No newline at end of file