/ Check-in [cdaeab46]
Login

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

Overview
Comment:Have ota use imposter tables to write to indexes instead of the sqlite3_index_writer() interface. The error handling in this version is broken in a few small ways.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | ota-update
Files: files | file ages | folders
SHA1: cdaeab467f6aa3217be161377a9b78a4eec37093
User & Date: dan 2015-01-31 20:42:04
Context
2015-02-03
15:56
Remove "PRAGMA ota_mode". check-in: 1c111447 user: dan tags: ota-update
2015-01-31
20:42
Have ota use imposter tables to write to indexes instead of the sqlite3_index_writer() interface. The error handling in this version is broken in a few small ways. check-in: cdaeab46 user: dan tags: ota-update
02:34
Merge in support for the index_xinfo pragma. check-in: f9b6dc77 user: drh tags: ota-update
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to ext/ota/otafault.test.

    60     60     ota close
    61     61   } -test {
    62     62     faultsim_test_result {0 SQLITE_DONE} \
    63     63                          {1 {SQLITE_NOMEM - out of memory}} \
    64     64                          {1 SQLITE_NOMEM} \
    65     65                          {1 SQLITE_IOERR_NOMEM} \
    66     66                          {1 {SQLITE_NOMEM - unable to open a temporary database file for storing temporary tables}}
    67         -
    68     67     if {$testrc==0} {
    69     68       sqlite3 db test.db
    70     69       faultsim_integrity_check
    71     70       set res [db eval {
    72     71         SELECT * FROM t1 UNION ALL SELECT * FROM t2;
    73     72       }]
    74     73       set expected [list {*}{

Changes to ext/ota/sqlite3ota.c.

    92     92   /*
    93     93   ** An iterator of this type is used to iterate through all objects in
    94     94   ** the target database that require updating. For each such table, the
    95     95   ** iterator visits, in order:
    96     96   **
    97     97   **     * the table itself, 
    98     98   **     * each index of the table (zero or more points to visit), and
    99         -**     * a special "cleanup table" point.
           99  +**     * a special "cleanup table" state.
   100    100   */
   101    101   struct OtaObjIter {
   102    102     sqlite3_stmt *pTblIter;         /* Iterate through tables */
   103    103     sqlite3_stmt *pIdxIter;         /* Index iterator */
   104    104     int nTblCol;                    /* Size of azTblCol[] array */
   105    105     char **azTblCol;                /* Array of quoted column names */
          106  +  char **azTblType;               /* Array of column types */
   106    107     unsigned char *abTblPk;         /* Array of flags - true for PK columns */
   107    108     int eType;
   108         -#if 0
   109         -  unsigned char bRowid;           /* True for implicit IPK tables */
   110         -  unsigned char bVtab;            /* True for a virtual table */
   111         -#endif
   112    109   
   113    110     /* Output variables. zTbl==0 implies EOF. */
   114    111     int bCleanup;                   /* True in "cleanup" state */
   115    112     const char *zTbl;               /* Name of target db table */
   116    113     const char *zIdx;               /* Name of target db index (or null) */
          114  +  int tnum;                       /* Root page of index (not table) */
          115  +  int bUnique;                    /* Current index is unique */
   117    116     int iVisit;                     /* Number of points visited, incl. current */
   118    117   
   119    118     /* Statements created by otaObjIterPrepareAll() */
   120    119     int nCol;                       /* Number of columns in current object */
   121    120     sqlite3_stmt *pSelect;          /* Source data */
   122    121     sqlite3_stmt *pInsert;          /* Statement for INSERT operations */
   123    122     sqlite3_stmt *pDelete;          /* Statement for DELETE ops */
................................................................................
   228    227   ** Free the OtaObjIter.azTblCol[] and OtaObjIter.abTblPk[] arrays allocated
   229    228   ** by an earlier call to otaObjIterGetCols().
   230    229   */
   231    230   static void otaObjIterFreeCols(OtaObjIter *pIter){
   232    231     int i;
   233    232     for(i=0; i<pIter->nTblCol; i++){
   234    233       sqlite3_free(pIter->azTblCol[i]);
          234  +    sqlite3_free(pIter->azTblType[i]);
   235    235     }
   236    236     sqlite3_free(pIter->azTblCol);
   237    237     pIter->azTblCol = 0;
          238  +  pIter->azTblType = 0;
   238    239     pIter->abTblPk = 0;
   239    240     pIter->nTblCol = 0;
   240    241     sqlite3_free(pIter->zMask);
   241    242     pIter->zMask = 0;
   242    243     pIter->eType = 0;               /* Invalid value */
   243    244   }
   244    245   
................................................................................
   303    304         rc = sqlite3_step(pIter->pIdxIter);
   304    305         if( rc!=SQLITE_ROW ){
   305    306           rc = sqlite3_reset(pIter->pIdxIter);
   306    307           pIter->bCleanup = 1;
   307    308           pIter->zIdx = 0;
   308    309         }else{
   309    310           pIter->zIdx = (const char*)sqlite3_column_text(pIter->pIdxIter, 0);
          311  +        pIter->tnum = sqlite3_column_int(pIter->pIdxIter, 1);
          312  +        pIter->bUnique = sqlite3_column_int(pIter->pIdxIter, 2);
   310    313           rc = SQLITE_OK;
   311    314         }
   312    315       }
   313    316     }
   314    317   
   315    318     if( rc!=SQLITE_OK ){
   316    319       otaObjIterFinalize(pIter);
................................................................................
   335    338     rc = prepareAndCollectError(p->db, &pIter->pTblIter, &p->zErrmsg, 
   336    339         "SELECT substr(name, 6) FROM ota.sqlite_master "
   337    340         "WHERE type='table' AND name LIKE 'data_%'"
   338    341     );
   339    342   
   340    343     if( rc==SQLITE_OK ){
   341    344       rc = prepareAndCollectError(p->db, &pIter->pIdxIter, &p->zErrmsg,
   342         -        "SELECT name FROM main.sqlite_master "
          345  +        "SELECT name, rootpage, sql IS NULL OR substr(8, 6)=='UNIQUE' "
          346  +        "  FROM main.sqlite_master "
   343    347           "WHERE type='index' AND tbl_name = ?"
   344    348       );
   345    349     }
   346    350   
   347    351     pIter->bCleanup = 1;
   348    352     p->rc = rc;
   349    353     return otaObjIterNext(p, pIter);
................................................................................
   424    428   
   425    429   /*
   426    430   ** Allocate and zero the pIter->azTblCol[] and abTblPk[] arrays so that
   427    431   ** there is room for at least nCol elements. If an OOM occurs, store an
   428    432   ** error code in the OTA handle passed as the first argument.
   429    433   */
   430    434   static void otaAllocateIterArrays(sqlite3ota *p, OtaObjIter *pIter, int nCol){
   431         -  int nByte = sizeof(char*) * nCol + sizeof(unsigned char*) * nCol;
          435  +  int nByte = sizeof(char*) * nCol * 2 + sizeof(unsigned char*) * nCol;
   432    436     char **azNew;
   433    437   
   434    438     assert( p->rc==SQLITE_OK );
   435    439     azNew = (char**)sqlite3_malloc(nByte);
   436    440     if( azNew ){
   437    441       memset(azNew, 0, nByte);
   438    442       pIter->azTblCol = azNew;
   439         -    pIter->abTblPk = (unsigned char*)&pIter->azTblCol[nCol];
          443  +    pIter->azTblType = &azNew[nCol];
          444  +    pIter->abTblPk = (unsigned char*)&pIter->azTblType[nCol];
   440    445     }else{
   441    446       p->rc = SQLITE_NOMEM;
   442    447     }
   443    448   }
          449  +
          450  +static char *otaStrndup(const char *zStr, int nStr, int *pRc){
          451  +  char *zRet = 0;
          452  +  assert( *pRc==SQLITE_OK );
          453  +
          454  +  if( zStr ){
          455  +    int nCopy = nStr;
          456  +    if( nCopy<0 ) nCopy = strlen(zStr) + 1;
          457  +    zRet = (char*)sqlite3_malloc(nCopy);
          458  +    if( zRet ){
          459  +      memcpy(zRet, zStr, nCopy);
          460  +    }else{
          461  +      *pRc = SQLITE_NOMEM;
          462  +    }
          463  +  }
          464  +
          465  +  return zRet;
          466  +}
          467  +
   444    468   
   445    469   /*
   446    470   ** Return true if zTab is the name of a virtual table within the target
   447    471   ** database.
   448    472   */
   449    473   static int otaIsVtab(sqlite3ota *p, const char *zTab){
   450    474     int res = 0;
................................................................................
   527    551         if( i==pIter->nTblCol ){
   528    552           p->rc = SQLITE_ERROR;
   529    553           p->zErrmsg = sqlite3_mprintf("column missing from data_%q: %s",
   530    554               pIter->zTbl, zName
   531    555           );
   532    556         }else{
   533    557           int iPk = sqlite3_column_int(pStmt, 5);
          558  +        const char *zType = (const char*)sqlite3_column_text(pStmt, 2);
          559  +        pIter->azTblType[i] = otaStrndup(zType, -1, &p->rc);
   534    560           pIter->abTblPk[i] = (iPk!=0);
   535    561           if( iPk ){
   536    562             pIter->eType = (iPk<0) ? OTA_PK_EXTERNAL : OTA_PK_REAL;
   537    563           }
   538    564         }
   539    565       }
   540    566       rc2 = sqlite3_finalize(pStmt);
................................................................................
   639    665           p->rc = SQLITE_NOMEM;
   640    666           break;
   641    667         }
   642    668       }
   643    669     }
   644    670     return zList;
   645    671   }
          672  +
          673  +/*
          674  +** This function is used to create a SELECT list (the list of SQL 
          675  +** expressions that follows a SELECT keyword) for a SELECT statement 
          676  +** used to read from an ota_xxx table while updating the index object
          677  +** currently indicated by the iterator object passed as the second 
          678  +** argument. A "PRAGMA index_xinfo = <idxname>" statement is used to
          679  +** obtain the required information.
          680  +**
          681  +** If the index is of the following form:
          682  +**
          683  +**   CREATE INDEX i1 ON t1(c, b COLLATE nocase);
          684  +**
          685  +** and "t1" is a table with an explicit INTEGER PRIMARY KEY column 
          686  +** "ipk", the returned string is:
          687  +**
          688  +**   "`c` COLLATE 'BINARY', `b` COLLATE 'NOCASE', `ipk` COLLATE 'BINARY'"
          689  +**
          690  +** As well as the returned string, three other malloc'd strings are 
          691  +** returned via output parameters. As follows:
          692  +**
          693  +**   pzImposterCols: ...
          694  +**   pzImposterPk: ...
          695  +**   pzWhere: ...
          696  +*/
          697  +static char *otaObjIterGetIndexCols(
          698  +  sqlite3ota *p,                  /* OTA object */
          699  +  OtaObjIter *pIter,              /* Object iterator for column names */
          700  +  char **pzImposterCols,          /* OUT: Columns for imposter table */
          701  +  char **pzImposterPk,            /* OUT: Imposter PK clause */
          702  +  char **pzWhere,                 /* OUT: WHERE clause */
          703  +  int *pnBind                     /* OUT: Total number of columns */
          704  +){
          705  +  int rc = p->rc;                 /* Error code */
          706  +  int rc2;                        /* sqlite3_finalize() return code */
          707  +  char *zRet = 0;                 /* String to return */
          708  +  char *zImpCols = 0;             /* String to return via *pzImposterCols */
          709  +  char *zImpPK = 0;               /* String to return via *pzImposterPK */
          710  +  char *zWhere = 0;               /* String to return via *pzWhere */
          711  +  int nBind = 0;                  /* Value to return via *pnBind */
          712  +  const char *zComma = "";        /* Set to ", " later on */
          713  +  const char *zAnd = "";          /* Set to " AND " later on */
          714  +  sqlite3_stmt *pXInfo = 0;       /* PRAGMA index_xinfo = ? */
          715  +
          716  +  if( rc==SQLITE_OK ){
          717  +    assert( p->zErrmsg==0 );
          718  +    rc = prepareFreeAndCollectError(p->db, &pXInfo, &p->zErrmsg,
          719  +        sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", pIter->zIdx)
          720  +    );
          721  +  }
          722  +
          723  +  while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){
          724  +    const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4);
          725  +    int iCid = sqlite3_column_int(pXInfo, 1);
          726  +    const char *zCol;
          727  +    const char *zType;
          728  +
          729  +    if( iCid<0 ){
          730  +      /* An integer primary key. If the table has an explicit IPK, use
          731  +      ** its name. Otherwise, use "ota_rowid".  */
          732  +      if( pIter->eType==OTA_PK_REAL ){
          733  +        int i;
          734  +        for(i=0; i<pIter->nTblCol && pIter->abTblPk[i]==0; i++);
          735  +        assert( i<pIter->nTblCol );
          736  +        zCol = pIter->azTblCol[i];
          737  +      }else{
          738  +        zCol = "ota_rowid";
          739  +      }
          740  +      zType = "INTEGER";
          741  +    }else{
          742  +      zCol = pIter->azTblCol[iCid];
          743  +      zType = pIter->azTblType[iCid];
          744  +    }
          745  +
          746  +    zRet = sqlite3_mprintf("%z%s%s COLLATE %Q", zRet, zComma, zCol, zCollate);
          747  +    if( pIter->bUnique==0 || sqlite3_column_int(pXInfo, 5) ){
          748  +      zImpPK = sqlite3_mprintf("%z%sc%d", zImpPK, zComma, nBind);
          749  +    }
          750  +    zImpCols = sqlite3_mprintf(
          751  +        "%z%sc%d %s COLLATE %Q", zImpCols, zComma, nBind, zType, zCollate
          752  +    );
          753  +    zWhere = sqlite3_mprintf("%z%sc%d IS ?", zWhere, zAnd, nBind);
          754  +    if( zRet==0 || zImpPK==0 || zImpCols==0 || zWhere==0 ) rc = SQLITE_NOMEM;
          755  +    zComma = ", ";
          756  +    zAnd = " AND ";
          757  +    nBind++;
          758  +  }
          759  +
          760  +  rc2 = sqlite3_finalize(pXInfo);
          761  +  if( rc==SQLITE_OK ) rc = rc2;
          762  +
          763  +  if( rc!=SQLITE_OK ){
          764  +    sqlite3_free(zRet);
          765  +    sqlite3_free(zImpCols);
          766  +    sqlite3_free(zImpPK);
          767  +    sqlite3_free(zWhere);
          768  +    zRet = 0;
          769  +    zImpCols = 0;
          770  +    zImpPK = 0;
          771  +    zWhere = 0;
          772  +    p->rc = rc;
          773  +  }
          774  +
          775  +  *pzImposterCols = zImpCols;
          776  +  *pzImposterPk = zImpPK;
          777  +  *pzWhere = zWhere;
          778  +  *pnBind = nBind;
          779  +  return zRet;
          780  +}
   646    781   
   647    782   /*
   648    783   ** Assuming the current table columns are "a", "b" and "c", and the zObj
   649    784   ** paramter is passed "old", return a string of the form:
   650    785   **
   651    786   **     "old.a, old.b, old.b"
   652    787   **
................................................................................
   788    923   static int otaObjIterPrepareAll(
   789    924     sqlite3ota *p, 
   790    925     OtaObjIter *pIter,
   791    926     int nOffset                     /* Add "LIMIT -1 OFFSET $nOffset" to SELECT */
   792    927   ){
   793    928     assert( pIter->bCleanup==0 );
   794    929     if( pIter->pSelect==0 && otaObjIterGetCols(p, pIter)==SQLITE_OK ){
          930  +    const int tnum = pIter->tnum;
   795    931       char *zCollist = 0;           /* List of indexed columns */
   796    932       char **pz = &p->zErrmsg;
   797    933       const char *zIdx = pIter->zIdx;
   798    934       char *zLimit = 0;
   799    935   
   800    936       if( nOffset ){
   801    937         zLimit = sqlite3_mprintf(" LIMIT -1 OFFSET %d", nOffset);
   802    938         if( !zLimit ) p->rc = SQLITE_NOMEM;
   803    939       }
   804    940   
   805    941       if( zIdx ){
   806         -      int *aiCol;                 /* Column map */
   807         -      const char **azColl;        /* Collation sequences */
          942  +      char *zImposterCols = 0;
          943  +      char *zImposterPK = 0;
          944  +      char *zWhere = 0;
          945  +      char *zBind = 0;
          946  +      int nBind = 0;
   808    947   
   809    948         assert( pIter->eType!=OTA_PK_VTAB );
   810         -
   811         -      /* Create the index writers */
   812         -      if( p->rc==SQLITE_OK ){
   813         -        p->rc = sqlite3_index_writer(
   814         -            p->db, 0, zIdx, &pIter->pInsert, &azColl, &aiCol, &pIter->nCol
   815         -        );
   816         -      }
   817         -      if( p->rc==SQLITE_OK ){
   818         -        p->rc = sqlite3_index_writer(
   819         -            p->db, 1, zIdx, &pIter->pDelete, &azColl, &aiCol, &pIter->nCol
   820         -        );
   821         -      }
   822         -
   823         -      /* Create the SELECT statement to read keys in sorted order */
   824         -      zCollist = otaObjIterGetCollist(p, pIter, pIter->nCol, aiCol, azColl);
          949  +      zCollist = otaObjIterGetIndexCols(
          950  +          p, pIter, &zImposterCols, &zImposterPK, &zWhere, &nBind
          951  +      );
          952  +      zBind = otaObjIterGetBindlist(p, nBind);
          953  +
          954  +      /* Create the imposter table used to write to this index. */
          955  +      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 1);
          956  +      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum);
          957  +      otaMPrintfExec(p, 
          958  +          "CREATE TABLE ota_imposter( %s, PRIMARY KEY( %s ) ) WITHOUT ROWID",
          959  +          zImposterCols, zImposterPK
          960  +      );
          961  +      sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0);
          962  +
          963  +      /* Create the statement to insert index entries */
          964  +      pIter->nCol = nBind;
          965  +      if( p->rc==SQLITE_OK ){
          966  +        p->rc = prepareFreeAndCollectError(p->db, &pIter->pInsert, &p->zErrmsg,
          967  +          sqlite3_mprintf("INSERT INTO ota_imposter VALUES(%s)", zBind)
          968  +        );
          969  +      }
          970  +
          971  +      /* And to delete index entries */
          972  +      if( p->rc==SQLITE_OK ){
          973  +        p->rc = prepareFreeAndCollectError(p->db, &pIter->pDelete, &p->zErrmsg,
          974  +          sqlite3_mprintf("DELETE FROM ota_imposter WHERE %s", zWhere)
          975  +        );
          976  +      }
          977  +
          978  +      /* Create the SELECT statement to read keys in sorted order */
   825    979         if( p->rc==SQLITE_OK ){
   826    980           char *zSql;
   827    981           if( pIter->eType==OTA_PK_EXTERNAL || pIter->eType==OTA_PK_NONE ){
   828    982             zSql = sqlite3_mprintf(
   829    983                 "SELECT %s, ota_control FROM ota.'ota_tmp_%q' ORDER BY %s%s",
   830    984                 zCollist, pIter->zTbl,
   831    985                 zCollist, zLimit
................................................................................
   840    994                 zCollist, pIter->zTbl, 
   841    995                 zCollist, pIter->zTbl, 
   842    996                 zCollist, zLimit
   843    997             );
   844    998           }
   845    999           p->rc = prepareFreeAndCollectError(p->db, &pIter->pSelect, pz, zSql);
   846   1000         }
         1001  +
         1002  +      sqlite3_free(zImposterCols);
         1003  +      sqlite3_free(zImposterPK);
         1004  +      sqlite3_free(zWhere);
         1005  +      sqlite3_free(zBind);
   847   1006       }else{
   848   1007         int bOtaRowid = (pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE);
   849   1008         const char *zTbl = pIter->zTbl;
   850   1009         char *zWhere = otaObjIterGetWhere(p, pIter);
   851   1010         char *zOldlist = otaObjIterGetOldlist(p, pIter, "old");
   852   1011         char *zNewlist = otaObjIterGetOldlist(p, pIter, "new");
   853   1012         char *zBindings = otaObjIterGetBindlist(p, pIter->nTblCol + bOtaRowid);
................................................................................
  1201   1360         sqlite3_step(pWriter);
  1202   1361         p->rc = resetAndCollectError(pWriter, &p->zErrmsg);
  1203   1362       }else if( eType==OTA_UPDATE ){
  1204   1363         sqlite3_value *pVal;
  1205   1364         sqlite3_stmt *pUpdate = 0;
  1206   1365         otaGetUpdateStmt(p, pIter, zMask, &pUpdate);
  1207   1366         if( pUpdate ){
  1208         -        for(i=0; i<pIter->nCol; i++){
         1367  +        for(i=0; p->rc==SQLITE_OK && i<pIter->nCol; i++){
  1209   1368             pVal = sqlite3_column_value(pIter->pSelect, i);
  1210   1369             sqlite3_bind_value(pUpdate, i+1, pVal);
  1211   1370           }
  1212   1371           if( pIter->eType==OTA_PK_VTAB || pIter->eType==OTA_PK_NONE ){
  1213   1372             /* Bind the ota_rowid value to column _rowid_ */
  1214   1373             assertColumnName(pIter->pSelect, pIter->nCol+1, "ota_rowid");
  1215   1374             pVal = sqlite3_column_value(pIter->pSelect, pIter->nCol+1);
................................................................................
  1371   1530     }
  1372   1531   
  1373   1532     if( rc!=SQLITE_OK ){
  1374   1533       p->rc = rc;
  1375   1534     }
  1376   1535   }
  1377   1536   
  1378         -static char *otaStrndup(char *zStr, int nStr, int *pRc){
  1379         -  char *zRet = 0;
  1380         -  assert( *pRc==SQLITE_OK );
  1381         -
  1382         -  if( zStr ){
  1383         -    int nCopy = nStr;
  1384         -    if( nCopy<0 ) nCopy = strlen(zStr) + 1;
  1385         -    zRet = (char*)sqlite3_malloc(nCopy);
  1386         -    if( zRet ){
  1387         -      memcpy(zRet, zStr, nCopy);
  1388         -    }else{
  1389         -      *pRc = SQLITE_NOMEM;
  1390         -    }
  1391         -  }
  1392         -
  1393         -  return zRet;
  1394         -}
  1395         -
  1396   1537   static void otaFreeState(OtaState *p){
  1397   1538     if( p ){
  1398   1539       sqlite3_free(p->zTbl);
  1399   1540       sqlite3_free(p->zIdx);
  1400   1541       sqlite3_free(p->pCkptState);
  1401   1542       sqlite3_free(p);
  1402   1543     }
................................................................................
  1736   1877   
  1737   1878       case 2: /* create_ota_delta */ {
  1738   1879         sqlite3 *db = sqlite3ota_db(pOta);
  1739   1880         int rc = sqlite3_create_function(
  1740   1881             db, "ota_delta", -1, SQLITE_UTF8, (void*)interp, test_ota_delta, 0, 0
  1741   1882         );
  1742   1883         Tcl_SetObjResult(interp, Tcl_NewStringObj(sqlite3ErrName(rc), -1));
         1884  +      sqlite3_exec(db, "PRAGMA vdbe_trace = 1", 0, 0, 0);
  1743   1885         ret = (rc==SQLITE_OK ? TCL_OK : TCL_ERROR);
  1744   1886         break;
  1745   1887       }
  1746   1888   
  1747   1889       default: /* seems unlikely */
  1748   1890         assert( !"cannot happen" );
  1749   1891         break;

Changes to src/main.c.

  3640   3640       **
  3641   3641       ** If onOff==0 and tnum>0 then reset the schema for all databases, causing
  3642   3642       ** the schema to be reparsed the next time it is needed.  This has the
  3643   3643       ** effect of erasing all imposter tables.
  3644   3644       */
  3645   3645       case SQLITE_TESTCTRL_IMPOSTER: {
  3646   3646         sqlite3 *db = va_arg(ap, sqlite3*);
         3647  +      sqlite3_mutex_enter(db->mutex);
  3647   3648         db->init.iDb = sqlite3FindDbName(db, va_arg(ap,const char*));
  3648   3649         db->init.busy = db->init.imposterTable = va_arg(ap,int);
  3649   3650         db->init.newTnum = va_arg(ap,int);
  3650   3651         if( db->init.busy==0 && db->init.newTnum>0 ){
  3651   3652           sqlite3ResetAllSchemasOfConnection(db);
  3652   3653         }
         3654  +      sqlite3_mutex_leave(db->mutex);
  3653   3655         break;
  3654   3656       }
  3655   3657     }
  3656   3658     va_end(ap);
  3657   3659   #endif /* SQLITE_OMIT_BUILTIN_TEST */
  3658   3660     return rc;
  3659   3661   }