SQLite

Check-in [ec7321ae48]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add tests to check error handling in OTA.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | ota-update
Files: files | file ages | folders
SHA1: ec7321ae482a8c4d893851a5edd17d67ef1a448b
User & Date: dan 2014-10-22 15:33:12.681
Context
2014-11-17
15:07
Fix a problem with the parameters to an OP_Affinity in one of the VM programs generated by sqlite3_index_writer() that was causing an OOB read. (check-in: 447b33b34a user: dan tags: ota-update)
2014-10-22
15:33
Add tests to check error handling in OTA. (check-in: ec7321ae48 user: dan tags: ota-update)
11:30
Sync the database file in sqlite3_ckpt_close(), even if the checkpoint has not finished. (check-in: e2729d623c user: dan tags: ota-update)
Changes
Unified Diff Ignore Whitespace Patch
Added ext/ota/otafault.test.


















































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# 2014 October 22
#
# 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.
#
#***********************************************************************
#

if {![info exists testdir]} {
  set testdir [file join [file dirname [info script]] .. .. test]
}
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix otafault

do_test 1.1 {
  forcedelete ota.db
  execsql {
    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
    CREATE INDEX t1cb ON t1(c, b);
    INSERT INTO t1 VALUES(1, 1, 1);
    INSERT INTO t1 VALUES(2, 2, 2);
    INSERT INTO t1 VALUES(3, 3, 3);
    CREATE TABLE t2(a PRIMARY KEY, b, c) WITHOUT ROWID;
    CREATE INDEX t2cb ON t1(c, b);
    INSERT INTO t2 VALUES('a', 'a', 'a');
    INSERT INTO t2 VALUES('b', 'b', 'b');
    INSERT INTO t2 VALUES('c', 'c', 'c');

    ATTACH 'ota.db' AS ota;
    CREATE TABLE ota.data_t1(a, b, c, ota_control);
    CREATE TABLE ota.data_t2(a, b, c, ota_control);

    INSERT INTO data_t1 VALUES(2, NULL, NULL, 1);
    INSERT INTO data_t1 VALUES(3, 'three', NULL, '.x.');
    INSERT INTO data_t1 VALUES(4, 4, 4, 0);

    INSERT INTO data_t2 VALUES('b', NULL, NULL, 1);
    INSERT INTO data_t2 VALUES('c', 'see', NULL, '.x.');
    INSERT INTO data_t2 VALUES('d', 'd', 'd', 0);
  }
  db close

  forcecopy test.db test.db.bak
  forcecopy ota.db ota.db.bak
} {}

do_faultsim_test 2 -faults oom-trans* -prep {
  catch { db close }
  forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal
  forcecopy test.db.bak test.db
  forcecopy ota.db.bak  ota.db
} -body {
  sqlite3ota ota test.db ota.db
  while {[ota step]=="SQLITE_OK"} {}
  ota close
} -test {
  faultsim_test_result {0 SQLITE_DONE} \
                       {1 {SQLITE_NOMEM - out of memory}} \
                       {1 SQLITE_NOMEM} \
                       {1 SQLITE_IOERR_NOMEM} \
                       {1 {SQLITE_NOMEM - unable to open a temporary database file for storing temporary tables}}

  if {$testrc==0} {
    sqlite3 db test.db
    faultsim_integrity_check
    set res [db eval {
      SELECT * FROM t1 UNION ALL SELECT * FROM t2;
    }]
    set expected [list {*}{
      1 1 1   3 three 3   4 4 4
      a a a   c see c     d d d
    }]

    if {$res != $expected} {
      puts ""
      puts "res: $res"
      puts "exp: $expected"
      error "data not as expected!"
    }
  }
}

proc copy_if_exists {src target} {
  if {[file exists $src]} {
    forcecopy $src $target
  } else {
    forcedelete $target
  }
}

for {set iStep 0} {$iStep<=21} {incr iStep} {

  forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal

  copy_if_exists test.db.bak test.db
  copy_if_exists ota.db.bak ota.db

  sqlite3ota ota test.db ota.db
  for {set x 0} {$x < $::iStep} {incr x} { ota step }
  ota close

  copy_if_exists test.db test.db.bak.2
  copy_if_exists test.db-wal test.db.bak.2-wal
  copy_if_exists test.db-oal test.db.bak.2-oal
  copy_if_exists ota.db ota.db.bak.2

  do_faultsim_test 3.$iStep -faults oom-trans* -prep {
    catch { db close }
    forcedelete test.db-journal test.db-wal ota.db-journal ota.db-wal
    copy_if_exists test.db.bak.2 test.db
    copy_if_exists test.db.bak.2-wal test.db-wal
    copy_if_exists test.db.bak.2-oal test.db-oal
    copy_if_exists ota.db.bak.2  ota.db
  } -body {
    sqlite3ota ota test.db ota.db
    while {[ota step] == "SQLITE_OK"} {}
    ota close
  } -test {
    faultsim_test_result {0 SQLITE_DONE} \
                         {1 {SQLITE_NOMEM - out of memory}} \
                         {1 SQLITE_NOMEM} \
                         {1 SQLITE_IOERR_NOMEM} \
                         {1 {SQLITE_NOMEM - unable to open a temporary database file for storing temporary tables}}
  
    if {$testrc==0} {
      sqlite3 db test.db
      faultsim_integrity_check
      set res [db eval {
        SELECT * FROM t1 UNION ALL SELECT * FROM t2;
      }]
      set expected [list {*}{
        1 1 1   3 three 3   4 4 4
        a a a   c see c     d d d
      }]
  
      if {$res != $expected} {
        puts ""
        puts "res: $res"
        puts "exp: $expected"
        error "data not as expected!"
      }
    }
  }

}

finish_test

Changes to ext/ota/sqlite3ota.c.
573
574
575
576
577
578
579




580
581
582
583
584
585
586
    }else{
      const char *zSep = "";
      for(i=0; i<pIter->nTblCol; i++){
        if( zMask[i]=='x' ){
          zList = sqlite3_mprintf("%z%s%s=?%d", 
              zList, zSep, pIter->azTblCol[i], i+1
          );




          zSep = ", ";
        }
      }
    }
  }
  return zList;
}







>
>
>
>







573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
    }else{
      const char *zSep = "";
      for(i=0; i<pIter->nTblCol; i++){
        if( zMask[i]=='x' ){
          zList = sqlite3_mprintf("%z%s%s=?%d", 
              zList, zSep, pIter->azTblCol[i], i+1
          );
          if( zList==0 ){
            p->rc = SQLITE_NOMEM;
            break;
          }
          zSep = ", ";
        }
      }
    }
  }
  return zList;
}
1075
1076
1077
1078
1079
1080
1081
1082
1083



1084
1085
1086
1087
1088
1089
1090

        break;
      }

      default:
        break;
    }
  }
  return p->rc;



}

static void otaSaveTransactionState(sqlite3ota *p){
  sqlite3_stmt *pInsert;
  int rc;

  assert( (p->rc==SQLITE_OK || p->rc==SQLITE_DONE) && p->zErrmsg==0 );







<
|
>
>
>







1079
1080
1081
1082
1083
1084
1085

1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096

        break;
      }

      default:
        break;
    }

    return p->rc;
  }else{
    return SQLITE_NOMEM;
  }
}

static void otaSaveTransactionState(sqlite3ota *p){
  sqlite3_stmt *pInsert;
  int rc;

  assert( (p->rc==SQLITE_OK || p->rc==SQLITE_DONE) && p->zErrmsg==0 );
1143
1144
1145
1146
1147
1148
1149

1150
1151
1152
1153

1154
1155
1156
1157
1158
1159
1160
    }
  }

  return zRet;
}

static void otaFreeState(OtaState *p){

  sqlite3_free(p->zTbl);
  sqlite3_free(p->zIdx);
  sqlite3_free(p->pCkptState);
  sqlite3_free(p);

}

/*
** Allocate an OtaState object and load the contents of the ota_state 
** table into it. Return a pointer to the new object. It is the 
** responsibility of the caller to eventually free the object using
** sqlite3_free().







>
|
|
|
|
>







1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
    }
  }

  return zRet;
}

static void otaFreeState(OtaState *p){
  if( p ){
    sqlite3_free(p->zTbl);
    sqlite3_free(p->zIdx);
    sqlite3_free(p->pCkptState);
    sqlite3_free(p);
  }
}

/*
** Allocate an OtaState object and load the contents of the ota_state 
** table into it. Return a pointer to the new object. It is the 
** responsibility of the caller to eventually free the object using
** sqlite3_free().
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
    if( p->rc==SQLITE_OK ){
      p->rc = sqlite3_exec(p->db, OTA_CREATE_STATE, 0, 0, &p->zErrmsg);
    }

    if( p->rc==SQLITE_OK ){
      pState = otaLoadState(p);
      assert( pState || p->rc!=SQLITE_OK );
      if( pState ){
        if( pState->eStage==0 ){ 
          otaDeleteOalFile(p);
          p->eStage = 1;
        }else{
          p->eStage = pState->eStage;
        }
        p->nProgress = pState->nProgress;







|







1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
    if( p->rc==SQLITE_OK ){
      p->rc = sqlite3_exec(p->db, OTA_CREATE_STATE, 0, 0, &p->zErrmsg);
    }

    if( p->rc==SQLITE_OK ){
      pState = otaLoadState(p);
      assert( pState || p->rc!=SQLITE_OK );
      if( p->rc==SQLITE_OK ){
        if( pState->eStage==0 ){ 
          otaDeleteOalFile(p);
          p->eStage = 1;
        }else{
          p->eStage = pState->eStage;
        }
        p->nProgress = pState->nProgress;
Changes to src/wal.c.
1604
1605
1606
1607
1608
1609
1610

1611
1612
1613
1614
1615
1616
1617
      p->aSegment[i].aPgno = (u32 *)aPgno;
    }
  }
  sqlite3ScratchFree(aTmp);

  if( rc!=SQLITE_OK ){
    walIteratorFree(p);

  }
  *pp = p;
  return rc;
}

/*
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and







>







1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
      p->aSegment[i].aPgno = (u32 *)aPgno;
    }
  }
  sqlite3ScratchFree(aTmp);

  if( rc!=SQLITE_OK ){
    walIteratorFree(p);
    p = 0;
  }
  *pp = p;
  return rc;
}

/*
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and