/ Check-in [62dc1fff]
Login
SQLite training in Houston TX on 2019-11-05 (details)
Part of the 2019 Tcl Conference

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

Overview
Comment:Add further tests and fixes for ota.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | ota-update
Files: files | file ages | folders
SHA1: 62dc1fffc38cb157c15105098749b6dd0198eb84
User & Date: dan 2015-02-16 11:48:34
Context
2015-02-16
21:13
Add extra tests and fixes for ota. check-in: e0b71519 user: dan tags: ota-update
11:48
Add further tests and fixes for ota. check-in: 62dc1fff user: dan tags: ota-update
06:27
Move tcl test code from sqlite3ota.c to new file ext/ota/test_ota.c. check-in: f20779a6 user: dan tags: ota-update
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added ext/ota/ota11.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
# 2015 February 16
#
# 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
set ::testprefix ota11


#--------------------------------------------------------------------
# Test that the xAccess() method of an ota vfs handles queries other
# than SQLITE_ACCESS_EXISTS correctly. The test code below causes
# SQLite to call xAccess(SQLITE_ACCESS_READWRITE) on the directory
# path argument passed to "PRAGMA temp_store_directory".
#
do_test 1.1 {
  sqlite3ota_create_vfs -default ota ""
  reset_db
  catchsql { PRAGMA temp_store_directory = '/no/such/directory' }
} {1 {not a writable directory}}

do_test 1.2 {
  catchsql " PRAGMA temp_store_directory = '[pwd]' "
} {0 {}}

do_test 1.3 {
  catchsql " PRAGMA temp_store_directory = '' "
} {0 {}}

do_test 1.4 {
  db close
  sqlite3ota_destroy_vfs ota
} {}

#--------------------------------------------------------------------
# Try to trick ota into operating on a database opened in wal mode.
#
reset_db
do_execsql_test 2.1 {
  CREATE TABLE t1(a PRIMARY KEY, b, c);
  INSERT INTO t1 VALUES(1, 2, 3);
  PRAGMA journal_mode = 'wal';
  CREATE TABLE t2(d PRIMARY KEY, e, f);
} {wal}

do_test 2.2 {
  db_save 
  db close

  forcedelete ota.db
  sqlite3 dbo ota.db
  dbo eval {
    CREATE TABLE data_t1(a, b, c, ota_control);
    INSERT INTO data_t1 VALUES(4, 5, 6, 0);
    INSERT INTO data_t1 VALUES(7, 8, 9, 0);
  }
  dbo close

  db_restore 
  hexio_write test.db 18 0101
  file exists test.db-wal
} {1}

breakpoint
do_test 2.3 {
  sqlite3ota ota test.db ota.db
  ota step
} {SQLITE_ERROR}

do_test 2.4 {
  list [catch {ota close} msg] $msg
} {1 {SQLITE_ERROR - cannot update wal mode database}}

finish_test

Changes to ext/ota/ota3.test.

131
132
133
134
135
136
137


















138
139
  list [catch { run_ota test.db ota.db } msg] $msg
} {1 SQLITE_ERROR}

do_execsql_test 2.5 {
  PRAGMA integrity_check;
} {ok}



















finish_test








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  list [catch { run_ota test.db ota.db } msg] $msg
} {1 SQLITE_ERROR}

do_execsql_test 2.5 {
  PRAGMA integrity_check;
} {ok}


#-------------------------------------------------------------------------
# Test that sqlite3ota_create_vfs() returns an error if the requested 
# parent VFS is unknown.
#
# And that nothing disasterous happens if a VFS name passed to
# sqlite3ota_destroy_vfs() is unknown or not an OTA vfs.
#
do_test 3.1 {
  list [catch {sqlite3ota_create_vfs xyz nosuchparent} msg] $msg
} {1 SQLITE_NOTFOUND}

do_test 3.2 {
  sqlite3ota_destroy_vfs nosuchvfs
  sqlite3ota_destroy_vfs unix
  sqlite3ota_destroy_vfs win32
} {}

finish_test

Changes to ext/ota/otaA.test.

65
66
67
68
69
70
71

72
73
74
75
76
77
78
79
80
81
82
  ota close
} {SQLITE_OK}

do_test 2.1 {
  sqlite3 db test.db
  db eval {PRAGMA journal_mode = wal}
  db close

  sqlite3ota ota test.db ota.db
  ota step
} {SQLITE_ERROR}

do_test 2.2 {
  list [catch { ota close } msg] $msg
} {1 {SQLITE_ERROR - cannot update wal mode database}}


finish_test








>











65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
  ota close
} {SQLITE_OK}

do_test 2.1 {
  sqlite3 db test.db
  db eval {PRAGMA journal_mode = wal}
  db close
  breakpoint
  sqlite3ota ota test.db ota.db
  ota step
} {SQLITE_ERROR}

do_test 2.2 {
  list [catch { ota close } msg] $msg
} {1 {SQLITE_ERROR - cannot update wal mode database}}


finish_test

Changes to ext/ota/sqlite3ota.c.

109
110
111
112
113
114
115

116
117
118
119
120
121
122
...
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
....
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
....
2133
2134
2135
2136
2137
2138
2139






















2140
2141
2142
2143
2144
2145
2146
....
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
....
2169
2170
2171
2172
2173
2174
2175

2176
2177
2178
2179

2180
2181
2182
2183
2184

2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197















2198
2199
2200
2201
2202
2203
2204
....
2353
2354
2355
2356
2357
2358
2359

2360
2361
2362
2363
2364
2365
2366
....
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
....
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952

2953
2954
2955
2956
2957
2958
2959
2960
2961
2962

2963
2964



2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000

3001
3002
3003
3004
3005
3006
3007
3008

3009
3010
3011
3012
3013
3014
struct OtaState {
  int eStage;
  char *zTbl;
  char *zIdx;
  i64 iWalCksum;
  int nRow;
  i64 nProgress;

};

/*
** An iterator of this type is used to iterate through all objects in
** the target database that require updating. For each such table, the
** iterator visits, in order:
**
................................................................................

  const char *zWal;               /* Wal filename for this main db file */
  ota_file *pWalFd;               /* Wal file descriptor for this main db */
  ota_file *pMainNext;            /* Next MAIN_DB file */
};


static void otaCreateVfs(sqlite3ota*, const char*);
static void otaDeleteVfs(sqlite3ota*);

/*
** Prepare the SQL statement in buffer zSql against database handle db.
** If successful, set *ppStmt to point to the new statement and return
** SQLITE_OK. 
**
** Otherwise, if an error does occur, set *ppStmt to NULL and return
** an SQLite error code. Additionally, set output variable *pzErrmsg to
................................................................................
        break;

      case OTA_STATE_CKPT:
        pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
        break;

      case OTA_STATE_COOKIE:
        /* At this point (p->iCookie) contains the value of the change-counter
        ** cookie (the thing that gets incremented when a transaction is 
        ** committed in rollback mode) currently stored on page 1 of the 
        ** database file. */
        if( pRet->eStage==OTA_STAGE_OAL 
         && p->pTargetFd->iCookie!=(u32)sqlite3_column_int64(pStmt, 1) 
        ){
          rc = SQLITE_BUSY;
          p->zErrmsg = sqlite3_mprintf("database modified during ota update");
        }
        break;

      default:
        rc = SQLITE_CORRUPT;
        break;
    }
  }
................................................................................
*/
static void otaDeleteOalFile(sqlite3ota *p){
  char *zOal = sqlite3_mprintf("%s-oal", p->zTarget);
  assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
  unlink(zOal);
  sqlite3_free(zOal);
}























/*
** Open and return a new OTA handle. 
*/
sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
  sqlite3ota *p;
  int nTarget = strlen(zTarget);
................................................................................

  p = (sqlite3ota*)sqlite3_malloc(sizeof(sqlite3ota)+nTarget+1+nOta+1);
  if( p ){
    OtaState *pState = 0;

    /* Create the custom VFS. */
    memset(p, 0, sizeof(sqlite3ota));
    otaCreateVfs(p, 0);

    /* Open the target database */
    if( p->rc==SQLITE_OK ){
      p->zTarget = (char*)&p[1];
      memcpy(p->zTarget, zTarget, nTarget+1);
      p->zOta = &p->zTarget[nTarget+1];
      memcpy(p->zOta, zOta, nOta+1);
................................................................................
    }

    /* Check that this is not a wal mode database. If it is, it cannot be
    ** updated. There is also a check for a live *-wal file in otaVfsAccess()
    ** function, on the off chance that the target is a wal database for
    ** which the first page of the db file has been overwritten by garbage
    ** during an earlier failed checkpoint.  */

    if( p->rc==SQLITE_OK && p->pTargetFd->iWriteVer>1 ){
      p->rc = SQLITE_ERROR;
      p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
    }


    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 = OTA_STAGE_OAL;
        }else{
          p->eStage = pState->eStage;
        }
        p->nProgress = pState->nProgress;
      }
    }
    assert( p->rc!=SQLITE_OK || p->eStage!=0 );

    if( p->rc==SQLITE_OK ){
      if( p->eStage==OTA_STAGE_OAL ){
















        /* Open the transaction */
        if( p->rc==SQLITE_OK ){
          p->rc = sqlite3_exec(p->db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
        }
  
        /* Point the object iterator at the first object */
................................................................................

  if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
    ota_file **pp;
    sqlite3_mutex_enter(p->pOtaVfs->mutex);
    for(pp=&p->pOtaVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
    *pp = p->pMainNext;
    sqlite3_mutex_leave(p->pOtaVfs->mutex);

  }

  /* Close the underlying file handle */
  rc = p->pReal->pMethods->xClose(p->pReal);
  return rc;
}

................................................................................

static int otaVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
  return 0;
}

void sqlite3ota_destroy_vfs(const char *zName){
  sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
  if( pVfs ){
    sqlite3_vfs_unregister(pVfs);
    sqlite3_free(pVfs);
  }
}

int sqlite3ota_create_vfs(const char *zName, const char *zParent){

................................................................................
    otaVfsSleep,                  /* xSleep */
    otaVfsCurrentTime,            /* xCurrentTime */
    otaVfsGetLastError,           /* xGetLastError */
    0,                            /* xCurrentTimeInt64 (version 2) */
    0, 0, 0                       /* Unimplemented version 3 methods */
  };

  sqlite3_vfs *pParent;           /* Parent VFS */
  ota_vfs *pNew = 0;              /* Newly allocated VFS */
  int nName;
  int rc = SQLITE_OK;


  nName = strlen(zName);
  pParent = sqlite3_vfs_find(zParent);
  if( pParent==0 ){
    rc = SQLITE_NOTFOUND;
  }else{
    int nByte = sizeof(ota_vfs) + nName + 1;
    pNew = (ota_vfs*)sqlite3_malloc(nByte);
    if( pNew==0 ){
      rc = SQLITE_NOMEM;
    }else{

      memset(pNew, 0, nByte);
    }



  }

  if( rc==SQLITE_OK ){
    char *zSpace;
    memcpy(&pNew->base, &vfs_template, sizeof(sqlite3_vfs));
    pNew->base.mxPathname = pParent->mxPathname;
    pNew->base.szOsFile = sizeof(ota_file) + pParent->szOsFile;
    pNew->pRealVfs = pParent;

    pNew->base.zName = (const char*)(zSpace = (char*)&pNew[1]);
    memcpy(zSpace, zName, nName);

    /* Register the new VFS (not as the default) */
    rc = sqlite3_vfs_register(&pNew->base, 0);
    if( rc ){
      sqlite3_free(pNew);
    }
  }

  return rc;
}

static void otaCreateVfs(sqlite3ota *p, const char *zParent){
  int rnd;
  char zRnd[64];

  assert( p->rc==SQLITE_OK );
  sqlite3_randomness(sizeof(int), (void*)&rnd);
  sprintf(zRnd, "ota_vfs_%d", rnd);
  p->rc = sqlite3ota_create_vfs(zRnd, zParent);
  if( p->rc==SQLITE_NOTFOUND ){
    p->zErrmsg = sqlite3_mprintf("no such vfs: %s", zParent);
  }else if( p->rc==SQLITE_OK ){
    sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
    assert( pVfs );
    p->zVfsName = pVfs->zName;

  }
}

static void otaDeleteVfs(sqlite3ota *p){
  if( p->zVfsName ){
    sqlite3ota_destroy_vfs(p->zVfsName);
    p->zVfsName = 0;
  }

}


/**************************************************************************/

#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_OTA) */







>







 







<
<
<







 







<
<
<
<
<
|
<
<
<
<







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







>




>





>













>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>







 







|







 







<




>

<
<
<
<
|
|
|
|
|
>
|
<
>
>
>
|
<
<
|
|
|
|
|

|
|

|
|
<
<



<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
>

<
<
<
<
<
<
<
>






109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
...
232
233
234
235
236
237
238



239
240
241
242
243
244
245
....
2063
2064
2065
2066
2067
2068
2069





2070




2071
2072
2073
2074
2075
2076
2077
....
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
....
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
....
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
....
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
....
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
....
2971
2972
2973
2974
2975
2976
2977

2978
2979
2980
2981
2982
2983




2984
2985
2986
2987
2988
2989
2990

2991
2992
2993
2994


2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005


3006
3007
3008













3009



3010
3011







3012
3013
3014
3015
3016
3017
3018
struct OtaState {
  int eStage;
  char *zTbl;
  char *zIdx;
  i64 iWalCksum;
  int nRow;
  i64 nProgress;
  u32 iCookie;
};

/*
** An iterator of this type is used to iterate through all objects in
** the target database that require updating. For each such table, the
** iterator visits, in order:
**
................................................................................

  const char *zWal;               /* Wal filename for this main db file */
  ota_file *pWalFd;               /* Wal file descriptor for this main db */
  ota_file *pMainNext;            /* Next MAIN_DB file */
};





/*
** Prepare the SQL statement in buffer zSql against database handle db.
** If successful, set *ppStmt to point to the new statement and return
** SQLITE_OK. 
**
** Otherwise, if an error does occur, set *ppStmt to NULL and return
** an SQLite error code. Additionally, set output variable *pzErrmsg to
................................................................................
        break;

      case OTA_STATE_CKPT:
        pRet->iWalCksum = sqlite3_column_int64(pStmt, 1);
        break;

      case OTA_STATE_COOKIE:





        pRet->iCookie = (u32)sqlite3_column_int64(pStmt, 1);




        break;

      default:
        rc = SQLITE_CORRUPT;
        break;
    }
  }
................................................................................
*/
static void otaDeleteOalFile(sqlite3ota *p){
  char *zOal = sqlite3_mprintf("%s-oal", p->zTarget);
  assert( p->rc==SQLITE_OK && p->zErrmsg==0 );
  unlink(zOal);
  sqlite3_free(zOal);
}

static void otaCreateVfs(sqlite3ota *p){
  int rnd;
  char zRnd[64];

  assert( p->rc==SQLITE_OK );
  sqlite3_randomness(sizeof(int), (void*)&rnd);
  sprintf(zRnd, "ota_vfs_%d", rnd);
  p->rc = sqlite3ota_create_vfs(zRnd, 0);
  if( p->rc==SQLITE_OK ){
    sqlite3_vfs *pVfs = sqlite3_vfs_find(zRnd);
    assert( pVfs );
    p->zVfsName = pVfs->zName;
  }
}

static void otaDeleteVfs(sqlite3ota *p){
  if( p->zVfsName ){
    sqlite3ota_destroy_vfs(p->zVfsName);
    p->zVfsName = 0;
  }
}

/*
** Open and return a new OTA handle. 
*/
sqlite3ota *sqlite3ota_open(const char *zTarget, const char *zOta){
  sqlite3ota *p;
  int nTarget = strlen(zTarget);
................................................................................

  p = (sqlite3ota*)sqlite3_malloc(sizeof(sqlite3ota)+nTarget+1+nOta+1);
  if( p ){
    OtaState *pState = 0;

    /* Create the custom VFS. */
    memset(p, 0, sizeof(sqlite3ota));
    otaCreateVfs(p);

    /* Open the target database */
    if( p->rc==SQLITE_OK ){
      p->zTarget = (char*)&p[1];
      memcpy(p->zTarget, zTarget, nTarget+1);
      p->zOta = &p->zTarget[nTarget+1];
      memcpy(p->zOta, zOta, nOta+1);
................................................................................
    }

    /* Check that this is not a wal mode database. If it is, it cannot be
    ** updated. There is also a check for a live *-wal file in otaVfsAccess()
    ** function, on the off chance that the target is a wal database for
    ** which the first page of the db file has been overwritten by garbage
    ** during an earlier failed checkpoint.  */
#if 0
    if( p->rc==SQLITE_OK && p->pTargetFd->iWriteVer>1 ){
      p->rc = SQLITE_ERROR;
      p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
    }
#endif

    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 = OTA_STAGE_OAL;
        }else{
          p->eStage = pState->eStage;
        }
        p->nProgress = pState->nProgress;
      }
    }
    assert( p->rc!=SQLITE_OK || p->eStage!=0 );

    if( p->rc==SQLITE_OK ){
      if( p->eStage==OTA_STAGE_OAL ){
        if( p->pTargetFd->pWalFd ){
          p->rc = SQLITE_ERROR;
          p->zErrmsg = sqlite3_mprintf("cannot update wal mode database");
        }

        /* At this point (pTargetFd->iCookie) contains the value of the
        ** change-counter cookie (the thing that gets incremented when a 
        ** transaction is committed in rollback mode) currently stored on 
        ** page 1 of the database file. */
        else if( pState->eStage==OTA_STAGE_OAL 
         && p->pTargetFd->iCookie!=pState->iCookie 
        ){
          p->rc = SQLITE_BUSY;
          p->zErrmsg = sqlite3_mprintf("database modified during ota update");
        }

        /* Open the transaction */
        if( p->rc==SQLITE_OK ){
          p->rc = sqlite3_exec(p->db, "BEGIN IMMEDIATE", 0, 0, &p->zErrmsg);
        }
  
        /* Point the object iterator at the first object */
................................................................................

  if( p->openFlags & SQLITE_OPEN_MAIN_DB ){
    ota_file **pp;
    sqlite3_mutex_enter(p->pOtaVfs->mutex);
    for(pp=&p->pOtaVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext));
    *pp = p->pMainNext;
    sqlite3_mutex_leave(p->pOtaVfs->mutex);
    p->pReal->pMethods->xShmUnmap(p->pReal, 0);
  }

  /* Close the underlying file handle */
  rc = p->pReal->pMethods->xClose(p->pReal);
  return rc;
}

................................................................................

static int otaVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){
  return 0;
}

void sqlite3ota_destroy_vfs(const char *zName){
  sqlite3_vfs *pVfs = sqlite3_vfs_find(zName);
  if( pVfs && pVfs->xOpen==otaVfsOpen ){
    sqlite3_vfs_unregister(pVfs);
    sqlite3_free(pVfs);
  }
}

int sqlite3ota_create_vfs(const char *zName, const char *zParent){

................................................................................
    otaVfsSleep,                  /* xSleep */
    otaVfsCurrentTime,            /* xCurrentTime */
    otaVfsGetLastError,           /* xGetLastError */
    0,                            /* xCurrentTimeInt64 (version 2) */
    0, 0, 0                       /* Unimplemented version 3 methods */
  };


  ota_vfs *pNew = 0;              /* Newly allocated VFS */
  int nName;
  int rc = SQLITE_OK;

  int nByte;
  nName = strlen(zName);




  nByte = sizeof(ota_vfs) + nName + 1;
  pNew = (ota_vfs*)sqlite3_malloc(nByte);
  if( pNew==0 ){
    rc = SQLITE_NOMEM;
  }else{
    sqlite3_vfs *pParent;           /* Parent VFS */
    memset(pNew, 0, nByte);

    pParent = sqlite3_vfs_find(zParent);
    if( pParent==0 ){
      rc = SQLITE_NOTFOUND;
    }else{


      char *zSpace;
      memcpy(&pNew->base, &vfs_template, sizeof(sqlite3_vfs));
      pNew->base.mxPathname = pParent->mxPathname;
      pNew->base.szOsFile = sizeof(ota_file) + pParent->szOsFile;
      pNew->pRealVfs = pParent;

      pNew->base.zName = (const char*)(zSpace = (char*)&pNew[1]);
      memcpy(zSpace, zName, nName);

      /* Register the new VFS (not as the default) */
      rc = sqlite3_vfs_register(&pNew->base, 0);


    }
  }














  if( rc!=SQLITE_OK ){



    sqlite3_free(pNew);
  }







  return rc;
}


/**************************************************************************/

#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_OTA) */