mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
Improve the error messages generated by the rtree module when a constraint fails.
FossilOrigin-Name: 3ad2531efb64b7c53b777ddf3681203217052b32
This commit is contained in:
@ -2800,6 +2800,53 @@ static RtreeValue rtreeValueUp(sqlite3_value *v){
|
||||
}
|
||||
#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.
|
||||
@ -2850,7 +2897,7 @@ static int rtreeUpdate(
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -2861,7 +2908,7 @@ static int rtreeUpdate(
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -2882,7 +2929,7 @@ static int rtreeUpdate(
|
||||
if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){
|
||||
rc = rtreeDeleteRowid(pRtree, cell.iRowid);
|
||||
}else{
|
||||
rc = SQLITE_CONSTRAINT;
|
||||
rc = rtreeConstraintError(pRtree, 0);
|
||||
goto constraint;
|
||||
}
|
||||
}
|
||||
|
@ -194,13 +194,13 @@ do_test rtree-2.1.3 {
|
||||
|
||||
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}
|
||||
@ -236,7 +236,7 @@ do_test rtree-3.1.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 {}}
|
||||
@ -490,11 +490,11 @@ foreach {tn sql_template testdata} {
|
||||
}
|
||||
|
||||
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}
|
||||
}
|
||||
|
||||
} {
|
||||
@ -510,7 +510,9 @@ foreach {tn sql_template testdata} {
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -47,7 +47,8 @@ ifcapable !rtree {
|
||||
#
|
||||
# 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 {
|
||||
@ -234,4 +235,32 @@ do_faultsim_test rtree3-10 -faults oom-* -prep {
|
||||
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
|
||||
|
Reference in New Issue
Block a user