mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
Prevent ota updates from violating NOT NULL constraints. Add a comment to the "limitations" section of sqlite3ota.h saying that CHECK constraints are not enforced.
FossilOrigin-Name: 74e073dd604142212f3d3e1931065d124daabd80
This commit is contained in:
@ -117,6 +117,59 @@ ifcapable fts3 {
|
||||
} {1 {SQLITE_ERROR - SQL logic error or missing database}}
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Test that it is not possible to violate a NOT NULL constraint by
|
||||
# applying an OTA update.
|
||||
#
|
||||
do_execsql_test 4.1 {
|
||||
CREATE TABLE t2(a INTEGER NOT NULL, b TEXT NOT NULL, c PRIMARY KEY);
|
||||
CREATE TABLE t3(a INTEGER NOT NULL, b TEXT NOT NULL, c INTEGER PRIMARY KEY);
|
||||
CREATE TABLE t4(a, b, PRIMARY KEY(a, b)) WITHOUT ROWID;
|
||||
|
||||
INSERT INTO t2 VALUES(10, 10, 10);
|
||||
INSERT INTO t3 VALUES(10, 10, 10);
|
||||
INSERT INTO t4 VALUES(10, 10);
|
||||
|
||||
}
|
||||
|
||||
foreach {tn error ota} {
|
||||
2 {SQLITE_CONSTRAINT - NOT NULL constraint failed: t2.a} {
|
||||
INSERT INTO data_t2 VALUES(NULL, 'abc', 1, 0);
|
||||
}
|
||||
3 {SQLITE_CONSTRAINT - NOT NULL constraint failed: t2.b} {
|
||||
INSERT INTO data_t2 VALUES(2, NULL, 1, 0);
|
||||
}
|
||||
4 {SQLITE_CONSTRAINT - NOT NULL constraint failed: t2.c} {
|
||||
INSERT INTO data_t2 VALUES(1, 'abc', NULL, 0);
|
||||
}
|
||||
5 {SQLITE_MISMATCH - datatype mismatch} {
|
||||
INSERT INTO data_t3 VALUES(1, 'abc', NULL, 0);
|
||||
}
|
||||
6 {SQLITE_CONSTRAINT - NOT NULL constraint failed: t4.b} {
|
||||
INSERT INTO data_t4 VALUES('a', NULL, 0);
|
||||
}
|
||||
7 {SQLITE_CONSTRAINT - NOT NULL constraint failed: t4.a} {
|
||||
INSERT INTO data_t4 VALUES(NULL, 'a', 0);
|
||||
}
|
||||
8 {SQLITE_CONSTRAINT - NOT NULL constraint failed: t2.a} {
|
||||
INSERT INTO data_t2 VALUES(NULL, 0, 10, 'x..');
|
||||
}
|
||||
9 {SQLITE_CONSTRAINT - NOT NULL constraint failed: t3.b} {
|
||||
INSERT INTO data_t3 VALUES(10, NULL, 10, '.x.');
|
||||
}
|
||||
} {
|
||||
set ota "
|
||||
CREATE TABLE data_t2(a, b, c, ota_control);
|
||||
CREATE TABLE data_t3(a, b, c, ota_control);
|
||||
CREATE TABLE data_t4(a, b, ota_control);
|
||||
$ota
|
||||
"
|
||||
do_test 4.$tn {
|
||||
list [catch { apply_ota $ota } msg] $msg
|
||||
} [list 1 $error]
|
||||
}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
||||
|
@ -112,6 +112,7 @@ struct OtaObjIter {
|
||||
char **azTblType; /* Array of target column types */
|
||||
int *aiSrcOrder; /* src table col -> target table col */
|
||||
unsigned char *abTblPk; /* Array of flags, set on target PK columns */
|
||||
unsigned char *abNotNull; /* Array of flags, set on NOT NULL columns */
|
||||
int eType; /* Table type - an OTA_PK_XXX value */
|
||||
|
||||
/* Output variables. zTbl==0 implies EOF. */
|
||||
@ -255,6 +256,7 @@ static void otaObjIterFreeCols(OtaObjIter *pIter){
|
||||
pIter->azTblType = 0;
|
||||
pIter->aiSrcOrder = 0;
|
||||
pIter->abTblPk = 0;
|
||||
pIter->abNotNull = 0;
|
||||
pIter->nTblCol = 0;
|
||||
sqlite3_free(pIter->zMask);
|
||||
pIter->zMask = 0;
|
||||
@ -417,7 +419,7 @@ static int otaMPrintfExec(sqlite3ota *p, const char *zFmt, ...){
|
||||
** error code in the OTA handle passed as the first argument.
|
||||
*/
|
||||
static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){
|
||||
int nByte = (sizeof(char*) * 2 + sizeof(int) + sizeof(unsigned char)) * nCol;
|
||||
int nByte = (2*sizeof(char*) + sizeof(int) + 2*sizeof(unsigned char)) * nCol;
|
||||
char **azNew;
|
||||
|
||||
assert( p->rc==SQLITE_OK );
|
||||
@ -428,6 +430,7 @@ static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){
|
||||
pIter->azTblType = &azNew[nCol];
|
||||
pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol];
|
||||
pIter->abTblPk = (unsigned char*)&pIter->aiSrcOrder[nCol];
|
||||
pIter->abNotNull = (unsigned char*)&pIter->abTblPk[nCol];
|
||||
}else{
|
||||
p->rc = SQLITE_NOMEM;
|
||||
}
|
||||
@ -655,6 +658,7 @@ static int otaObjIterCacheTableInfo(sqlite3ota *p, OtaObjIter *pIter){
|
||||
);
|
||||
}else{
|
||||
int iPk = sqlite3_column_int(pStmt, 5);
|
||||
int bNotNull = sqlite3_column_int(pStmt, 3);
|
||||
const char *zType = (const char*)sqlite3_column_text(pStmt, 2);
|
||||
|
||||
if( i!=iOrder ){
|
||||
@ -664,6 +668,7 @@ static int otaObjIterCacheTableInfo(sqlite3ota *p, OtaObjIter *pIter){
|
||||
|
||||
pIter->azTblType[iOrder] = otaStrndup(zType, -1, &p->rc);
|
||||
pIter->abTblPk[iOrder] = (iPk!=0);
|
||||
pIter->abNotNull[iOrder] = (unsigned char)bNotNull || (iPk!=0);
|
||||
iOrder++;
|
||||
}
|
||||
}
|
||||
@ -1141,8 +1146,9 @@ static void otaCreateImposterTable(sqlite3ota *p, OtaObjIter *pIter){
|
||||
** "PRIMARY KEY" to the imposter table column declaration. */
|
||||
zPk = "PRIMARY KEY ";
|
||||
}
|
||||
zSql = otaMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %s",
|
||||
zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl
|
||||
zSql = otaMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %s%s",
|
||||
zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl,
|
||||
(pIter->abNotNull[iCol] ? " NOT NULL" : "")
|
||||
);
|
||||
zComma = ", ";
|
||||
}
|
||||
|
@ -71,6 +71,8 @@
|
||||
**
|
||||
** * No foreign key violations are detected or reported.
|
||||
**
|
||||
** * CHECK constraints are not enforced.
|
||||
**
|
||||
** * No constraint handling mode except for "OR ROLLBACK" is supported.
|
||||
**
|
||||
**
|
||||
|
Reference in New Issue
Block a user