/ Check-in [c23ef5e2]
Login

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

Overview
Comment:Merge all recent changes from trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | apple-osx
Files: files | file ages | folders
SHA3-256: c23ef5e231908450da7461233bc3f4a38ab11ff351ae0c34d91e82c61ad13b3c
User & Date: drh 2017-04-08 18:24:57
Context
2017-04-24
16:14
Bring in all the latest enhancements from trunk. check-in: 031feebc user: drh tags: apple-osx
2017-04-08
18:24
Merge all recent changes from trunk. check-in: c23ef5e2 user: drh tags: apple-osx
18:18
Disallow leading zeros on numeric constants in JSON. Fix for ticket [b93be8729a895a528e2] check-in: 204e72f0 user: drh tags: trunk
00:25
Merge the latest trunk changes. check-in: dd16439e user: drh tags: apple-osx
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to ext/fts5/fts5Int.h.

   442    442     Fts5Index *p,                   /* Index to write to */
   443    443     int bDelete,                    /* True if current operation is a delete */
   444    444     i64 iDocid                      /* Docid to add or remove data from */
   445    445   );
   446    446   
   447    447   /*
   448    448   ** Flush any data stored in the in-memory hash tables to the database.
   449         -** If the bCommit flag is true, also close any open blob handles.
          449  +** Also close any open blob handles.
   450    450   */
   451         -int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit);
          451  +int sqlite3Fts5IndexSync(Fts5Index *p);
   452    452   
   453    453   /*
   454    454   ** Discard any data stored in the in-memory hash tables. Do not write it
   455    455   ** to the database. Additionally, assume that the contents of the %_data
   456    456   ** table may have changed on disk. So any in-memory caches of %_data 
   457    457   ** records must be invalidated.
   458    458   */
................................................................................
   614    614   int sqlite3Fts5StorageStmt(Fts5Storage *p, int eStmt, sqlite3_stmt**, char**);
   615    615   void sqlite3Fts5StorageStmtRelease(Fts5Storage *p, int eStmt, sqlite3_stmt*);
   616    616   
   617    617   int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol);
   618    618   int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnAvg);
   619    619   int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow);
   620    620   
   621         -int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit);
          621  +int sqlite3Fts5StorageSync(Fts5Storage *p);
   622    622   int sqlite3Fts5StorageRollback(Fts5Storage *p);
   623    623   
   624    624   int sqlite3Fts5StorageConfigValue(
   625    625       Fts5Storage *p, const char*, sqlite3_value*, int
   626    626   );
   627    627   
   628    628   int sqlite3Fts5StorageDeleteAll(Fts5Storage *p);

Changes to ext/fts5/fts5_index.c.

   624    624     if( p->pReader ){
   625    625       sqlite3_blob *pReader = p->pReader;
   626    626       p->pReader = 0;
   627    627       sqlite3_blob_close(pReader);
   628    628     }
   629    629   }
   630    630   
   631         -
   632    631   /*
   633    632   ** Retrieve a record from the %_data table.
   634    633   **
   635    634   ** If an error occurs, NULL is returned and an error left in the 
   636    635   ** Fts5Index object.
   637    636   */
   638    637   static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
................................................................................
  5127   5126     p->bDelete = bDelete;
  5128   5127     return fts5IndexReturn(p);
  5129   5128   }
  5130   5129   
  5131   5130   /*
  5132   5131   ** Commit data to disk.
  5133   5132   */
  5134         -int sqlite3Fts5IndexSync(Fts5Index *p, int bCommit){
         5133  +int sqlite3Fts5IndexSync(Fts5Index *p){
  5135   5134     assert( p->rc==SQLITE_OK );
  5136   5135     fts5IndexFlush(p);
  5137         -  if( bCommit ) fts5CloseReader(p);
         5136  +  fts5CloseReader(p);
  5138   5137     return fts5IndexReturn(p);
  5139   5138   }
  5140   5139   
  5141   5140   /*
  5142   5141   ** Discard any data stored in the in-memory hash tables. Do not write it
  5143   5142   ** to the database. Additionally, assume that the contents of the %_data
  5144   5143   ** table may have changed on disk. So any in-memory caches of %_data 

Changes to ext/fts5/fts5_main.c.

  1575   1575   */
  1576   1576   static int fts5SyncMethod(sqlite3_vtab *pVtab){
  1577   1577     int rc;
  1578   1578     Fts5Table *pTab = (Fts5Table*)pVtab;
  1579   1579     fts5CheckTransactionState(pTab, FTS5_SYNC, 0);
  1580   1580     pTab->pConfig->pzErrmsg = &pTab->base.zErrMsg;
  1581   1581     fts5TripCursors(pTab);
  1582         -  rc = sqlite3Fts5StorageSync(pTab->pStorage, 1);
         1582  +  rc = sqlite3Fts5StorageSync(pTab->pStorage);
  1583   1583     pTab->pConfig->pzErrmsg = 0;
  1584   1584     return rc;
  1585   1585   }
  1586   1586   
  1587   1587   /*
  1588   1588   ** Implementation of xBegin() method. 
  1589   1589   */
................................................................................
  2386   2386   ** Flush the contents of the pending-terms table to disk.
  2387   2387   */
  2388   2388   static int fts5SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){
  2389   2389     Fts5Table *pTab = (Fts5Table*)pVtab;
  2390   2390     UNUSED_PARAM(iSavepoint);  /* Call below is a no-op for NDEBUG builds */
  2391   2391     fts5CheckTransactionState(pTab, FTS5_SAVEPOINT, iSavepoint);
  2392   2392     fts5TripCursors(pTab);
  2393         -  return sqlite3Fts5StorageSync(pTab->pStorage, 0);
         2393  +  return sqlite3Fts5StorageSync(pTab->pStorage);
  2394   2394   }
  2395   2395   
  2396   2396   /*
  2397   2397   ** The xRelease() method.
  2398   2398   **
  2399   2399   ** This is a no-op.
  2400   2400   */
  2401   2401   static int fts5ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){
  2402   2402     Fts5Table *pTab = (Fts5Table*)pVtab;
  2403   2403     UNUSED_PARAM(iSavepoint);  /* Call below is a no-op for NDEBUG builds */
  2404   2404     fts5CheckTransactionState(pTab, FTS5_RELEASE, iSavepoint);
  2405   2405     fts5TripCursors(pTab);
  2406         -  return sqlite3Fts5StorageSync(pTab->pStorage, 0);
         2406  +  return sqlite3Fts5StorageSync(pTab->pStorage);
  2407   2407   }
  2408   2408   
  2409   2409   /*
  2410   2410   ** The xRollbackTo() method.
  2411   2411   **
  2412   2412   ** Discard the contents of the pending terms table.
  2413   2413   */

Changes to ext/fts5/fts5_storage.c.

   214    214           pConfig->zDb, pConfig->zName, zTail, zName, zTail
   215    215       );
   216    216     }
   217    217   }
   218    218   
   219    219   int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){
   220    220     Fts5Config *pConfig = pStorage->pConfig;
   221         -  int rc = sqlite3Fts5StorageSync(pStorage, 1);
          221  +  int rc = sqlite3Fts5StorageSync(pStorage);
   222    222   
   223    223     fts5StorageRenameOne(pConfig, &rc, "data", zName);
   224    224     fts5StorageRenameOne(pConfig, &rc, "idx", zName);
   225    225     fts5StorageRenameOne(pConfig, &rc, "config", zName);
   226    226     if( pConfig->bColumnsize ){
   227    227       fts5StorageRenameOne(pConfig, &rc, "docsize", zName);
   228    228     }
................................................................................
  1077   1077     }
  1078   1078     return rc;
  1079   1079   }
  1080   1080   
  1081   1081   /*
  1082   1082   ** Flush any data currently held in-memory to disk.
  1083   1083   */
  1084         -int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){
         1084  +int sqlite3Fts5StorageSync(Fts5Storage *p){
  1085   1085     int rc = SQLITE_OK;
  1086   1086     i64 iLastRowid = sqlite3_last_insert_rowid(p->pConfig->db);
  1087   1087     if( p->bTotalsValid ){
  1088   1088       rc = fts5StorageSaveTotals(p);
  1089         -    if( bCommit ) p->bTotalsValid = 0;
         1089  +    p->bTotalsValid = 0;
  1090   1090     }
  1091   1091     if( rc==SQLITE_OK ){
  1092         -    rc = sqlite3Fts5IndexSync(p->pIndex, bCommit);
         1092  +    rc = sqlite3Fts5IndexSync(p->pIndex);
  1093   1093     }
  1094   1094     sqlite3_set_last_insert_rowid(p->pConfig->db, iLastRowid);
  1095   1095     return rc;
  1096   1096   }
  1097   1097   
  1098   1098   int sqlite3Fts5StorageRollback(Fts5Storage *p){
  1099   1099     p->bTotalsValid = 0;

Changes to ext/fts5/test/fts5aa.test.

   556    556   ]
   557    557   do_test 20.1 {
   558    558     foreach id $::ids {
   559    559       execsql { INSERT INTO tmp(rowid, x) VALUES($id, 'x y z') }
   560    560     }
   561    561     execsql { SELECT rowid FROM tmp WHERE tmp MATCH 'y' }
   562    562   } $::ids
          563  +
          564  +#--------------------------------------------------------------------
          565  +# Test that a DROP TABLE may be executed within a transaction that
          566  +# writes to an FTS5 table.
          567  +#
          568  +do_execsql_test 21.0 {
          569  +  CREATE TEMP TABLE t8(a, b);
          570  +  CREATE VIRTUAL TABLE ft USING fts5(x, detail=%DETAIL%);
          571  +}
          572  +
          573  +do_execsql_test 21.1 {
          574  +  BEGIN;
          575  +    INSERT INTO ft VALUES('a b c');
          576  +    DROP TABLE t8;
          577  +  COMMIT;
          578  +}
   563    579   
   564    580   }
   565    581   
   566    582   
   567    583   finish_test
   568    584   
   569    585   

Changes to ext/misc/json1.c.

   723    723   */
   724    724   static int jsonParseValue(JsonParse *pParse, u32 i){
   725    725     char c;
   726    726     u32 j;
   727    727     int iThis;
   728    728     int x;
   729    729     JsonNode *pNode;
   730         -  while( safe_isspace(pParse->zJson[i]) ){ i++; }
   731         -  if( (c = pParse->zJson[i])=='{' ){
          730  +  const char *z = pParse->zJson;
          731  +  while( safe_isspace(z[i]) ){ i++; }
          732  +  if( (c = z[i])=='{' ){
   732    733       /* Parse object */
   733    734       iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
   734    735       if( iThis<0 ) return -1;
   735    736       for(j=i+1;;j++){
   736         -      while( safe_isspace(pParse->zJson[j]) ){ j++; }
          737  +      while( safe_isspace(z[j]) ){ j++; }
   737    738         x = jsonParseValue(pParse, j);
   738    739         if( x<0 ){
   739    740           if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
   740    741           return -1;
   741    742         }
   742    743         if( pParse->oom ) return -1;
   743    744         pNode = &pParse->aNode[pParse->nNode-1];
   744    745         if( pNode->eType!=JSON_STRING ) return -1;
   745    746         pNode->jnFlags |= JNODE_LABEL;
   746    747         j = x;
   747         -      while( safe_isspace(pParse->zJson[j]) ){ j++; }
   748         -      if( pParse->zJson[j]!=':' ) return -1;
          748  +      while( safe_isspace(z[j]) ){ j++; }
          749  +      if( z[j]!=':' ) return -1;
   749    750         j++;
   750    751         x = jsonParseValue(pParse, j);
   751    752         if( x<0 ) return -1;
   752    753         j = x;
   753         -      while( safe_isspace(pParse->zJson[j]) ){ j++; }
   754         -      c = pParse->zJson[j];
          754  +      while( safe_isspace(z[j]) ){ j++; }
          755  +      c = z[j];
   755    756         if( c==',' ) continue;
   756    757         if( c!='}' ) return -1;
   757    758         break;
   758    759       }
   759    760       pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
   760    761       return j+1;
   761    762     }else if( c=='[' ){
   762    763       /* Parse array */
   763    764       iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
   764    765       if( iThis<0 ) return -1;
   765    766       for(j=i+1;;j++){
   766         -      while( safe_isspace(pParse->zJson[j]) ){ j++; }
          767  +      while( safe_isspace(z[j]) ){ j++; }
   767    768         x = jsonParseValue(pParse, j);
   768    769         if( x<0 ){
   769    770           if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
   770    771           return -1;
   771    772         }
   772    773         j = x;
   773         -      while( safe_isspace(pParse->zJson[j]) ){ j++; }
   774         -      c = pParse->zJson[j];
          774  +      while( safe_isspace(z[j]) ){ j++; }
          775  +      c = z[j];
   775    776         if( c==',' ) continue;
   776    777         if( c!=']' ) return -1;
   777    778         break;
   778    779       }
   779    780       pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
   780    781       return j+1;
   781    782     }else if( c=='"' ){
   782    783       /* Parse string */
   783    784       u8 jnFlags = 0;
   784    785       j = i+1;
   785    786       for(;;){
   786         -      c = pParse->zJson[j];
          787  +      c = z[j];
   787    788         if( c==0 ) return -1;
   788    789         if( c=='\\' ){
   789         -        c = pParse->zJson[++j];
          790  +        c = z[++j];
   790    791           if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
   791    792              || c=='n' || c=='r' || c=='t'
   792         -           || (c=='u' && jsonIs4Hex(pParse->zJson+j+1)) ){
          793  +           || (c=='u' && jsonIs4Hex(z+j+1)) ){
   793    794             jnFlags = JNODE_ESCAPE;
   794    795           }else{
   795    796             return -1;
   796    797           }
   797    798         }else if( c=='"' ){
   798    799           break;
   799    800         }
   800    801         j++;
   801    802       }
   802         -    jsonParseAddNode(pParse, JSON_STRING, j+1-i, &pParse->zJson[i]);
          803  +    jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
   803    804       if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
   804    805       return j+1;
   805    806     }else if( c=='n'
   806         -         && strncmp(pParse->zJson+i,"null",4)==0
   807         -         && !safe_isalnum(pParse->zJson[i+4]) ){
          807  +         && strncmp(z+i,"null",4)==0
          808  +         && !safe_isalnum(z[i+4]) ){
   808    809       jsonParseAddNode(pParse, JSON_NULL, 0, 0);
   809    810       return i+4;
   810    811     }else if( c=='t'
   811         -         && strncmp(pParse->zJson+i,"true",4)==0
   812         -         && !safe_isalnum(pParse->zJson[i+4]) ){
          812  +         && strncmp(z+i,"true",4)==0
          813  +         && !safe_isalnum(z[i+4]) ){
   813    814       jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
   814    815       return i+4;
   815    816     }else if( c=='f'
   816         -         && strncmp(pParse->zJson+i,"false",5)==0
   817         -         && !safe_isalnum(pParse->zJson[i+5]) ){
          817  +         && strncmp(z+i,"false",5)==0
          818  +         && !safe_isalnum(z[i+5]) ){
   818    819       jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
   819    820       return i+5;
   820    821     }else if( c=='-' || (c>='0' && c<='9') ){
   821    822       /* Parse number */
   822    823       u8 seenDP = 0;
   823    824       u8 seenE = 0;
          825  +    assert( '-' < '0' );
          826  +    if( c<='0' ){
          827  +      j = c=='-' ? i+1 : i;
          828  +      if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
          829  +    }
   824    830       j = i+1;
   825    831       for(;; j++){
   826         -      c = pParse->zJson[j];
          832  +      c = z[j];
   827    833         if( c>='0' && c<='9' ) continue;
   828    834         if( c=='.' ){
   829         -        if( pParse->zJson[j-1]=='-' ) return -1;
          835  +        if( z[j-1]=='-' ) return -1;
   830    836           if( seenDP ) return -1;
   831    837           seenDP = 1;
   832    838           continue;
   833    839         }
   834    840         if( c=='e' || c=='E' ){
   835         -        if( pParse->zJson[j-1]<'0' ) return -1;
          841  +        if( z[j-1]<'0' ) return -1;
   836    842           if( seenE ) return -1;
   837    843           seenDP = seenE = 1;
   838         -        c = pParse->zJson[j+1];
          844  +        c = z[j+1];
   839    845           if( c=='+' || c=='-' ){
   840    846             j++;
   841         -          c = pParse->zJson[j+1];
          847  +          c = z[j+1];
   842    848           }
   843    849           if( c<'0' || c>'9' ) return -1;
   844    850           continue;
   845    851         }
   846    852         break;
   847    853       }
   848         -    if( pParse->zJson[j-1]<'0' ) return -1;
          854  +    if( z[j-1]<'0' ) return -1;
   849    855       jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
   850         -                        j - i, &pParse->zJson[i]);
          856  +                        j - i, &z[i]);
   851    857       return j;
   852    858     }else if( c=='}' ){
   853    859       return -2;  /* End of {...} */
   854    860     }else if( c==']' ){
   855    861       return -3;  /* End of [...] */
   856    862     }else if( c==0 ){
   857    863       return 0;   /* End of file */

Changes to ext/rtree/rtree.c.

  3195   3195       "ALTER TABLE %Q.'%q_parent' RENAME TO \"%w_parent\";"
  3196   3196       "ALTER TABLE %Q.'%q_rowid'  RENAME TO \"%w_rowid\";"
  3197   3197       , pRtree->zDb, pRtree->zName, zNewName 
  3198   3198       , pRtree->zDb, pRtree->zName, zNewName 
  3199   3199       , pRtree->zDb, pRtree->zName, zNewName
  3200   3200     );
  3201   3201     if( zSql ){
         3202  +    nodeBlobReset(pRtree);
  3202   3203       rc = sqlite3_exec(pRtree->db, zSql, 0, 0, 0);
  3203   3204       sqlite3_free(zSql);
  3204   3205     }
  3205   3206     return rc;
  3206   3207   }
  3207   3208   
         3209  +/*
         3210  +** The xSavepoint method.
         3211  +**
         3212  +** This module does not need to do anything to support savepoints. However,
         3213  +** it uses this hook to close any open blob handle. This is done because a 
         3214  +** DROP TABLE command - which fortunately always opens a savepoint - cannot 
         3215  +** succeed if there are any open blob handles. i.e. if the blob handle were
         3216  +** not closed here, the following would fail:
         3217  +**
         3218  +**   BEGIN;
         3219  +**     INSERT INTO rtree...
         3220  +**     DROP TABLE <tablename>;    -- Would fail with SQLITE_LOCKED
         3221  +**   COMMIT;
         3222  +*/
         3223  +static int rtreeSavepoint(sqlite3_vtab *pVtab, int iSavepoint){
         3224  +  Rtree *pRtree = (Rtree *)pVtab;
         3225  +  int iwt = pRtree->inWrTrans;
         3226  +  pRtree->inWrTrans = 0;
         3227  +  nodeBlobReset(pRtree);
         3228  +  pRtree->inWrTrans = iwt;
         3229  +  return SQLITE_OK;
         3230  +}
  3208   3231   
  3209   3232   /*
  3210   3233   ** This function populates the pRtree->nRowEst variable with an estimate
  3211   3234   ** of the number of rows in the virtual table. If possible, this is based
  3212   3235   ** on sqlite_stat1 data. Otherwise, use RTREE_DEFAULT_ROWEST.
  3213   3236   */
  3214   3237   static int rtreeQueryStat1(sqlite3 *db, Rtree *pRtree){
................................................................................
  3247   3270       sqlite3_free(zSql);
  3248   3271     }
  3249   3272   
  3250   3273     return rc;
  3251   3274   }
  3252   3275   
  3253   3276   static sqlite3_module rtreeModule = {
  3254         -  0,                          /* iVersion */
         3277  +  2,                          /* iVersion */
  3255   3278     rtreeCreate,                /* xCreate - create a table */
  3256   3279     rtreeConnect,               /* xConnect - connect to an existing table */
  3257   3280     rtreeBestIndex,             /* xBestIndex - Determine search strategy */
  3258   3281     rtreeDisconnect,            /* xDisconnect - Disconnect from a table */
  3259   3282     rtreeDestroy,               /* xDestroy - Drop a table */
  3260   3283     rtreeOpen,                  /* xOpen - open a cursor */
  3261   3284     rtreeClose,                 /* xClose - close a cursor */
................................................................................
  3267   3290     rtreeUpdate,                /* xUpdate - write data */
  3268   3291     rtreeBeginTransaction,      /* xBegin - begin transaction */
  3269   3292     rtreeEndTransaction,        /* xSync - sync transaction */
  3270   3293     rtreeEndTransaction,        /* xCommit - commit transaction */
  3271   3294     rtreeEndTransaction,        /* xRollback - rollback transaction */
  3272   3295     0,                          /* xFindFunction - function overloading */
  3273   3296     rtreeRename,                /* xRename - rename the table */
  3274         -  0,                          /* xSavepoint */
         3297  +  rtreeSavepoint,             /* xSavepoint */
  3275   3298     0,                          /* xRelease */
  3276   3299     0,                          /* xRollbackTo */
  3277   3300   };
  3278   3301   
  3279   3302   static int rtreeSqlInit(
  3280   3303     Rtree *pRtree, 
  3281   3304     sqlite3 *db, 

Changes to ext/rtree/rtree1.test.

    35     35   #   rtree-12.*: Test that on-conflict clauses are supported.
    36     36   #   rtree-13.*: Test that bug [d2889096e7bdeac6d] has been fixed.
    37     37   #   rtree-14.*: Test if a non-integer is inserted into the PK column of an
    38     38   #               r-tree table, it is converted to an integer before being
    39     39   #               inserted. Also that if a non-numeric is inserted into one
    40     40   #               of the min/max dimension columns, it is converted to the
    41     41   #               required type before being inserted.
           42  +#   rtree-15.*: Check that DROP TABLE works within a transaction that
           43  +#               writes to an r-tree table.
    42     44   #
    43     45   
    44     46   ifcapable !rtree {
    45     47     finish_test
    46     48     return
    47     49   }
    48     50   
................................................................................
   587    589   do_execsql_test 14.5 {
   588    590     SELECT * FROM t10;
   589    591   } {
   590    592     1 0 0
   591    593     2 52 81
   592    594     3 42 49
   593    595   }
          596  +
          597  +#-------------------------------------------------------------------------
          598  +#
          599  +do_execsql_test 15.0 {
          600  +  CREATE VIRTUAL TABLE rt USING rtree(id, x1,x2, y1,y2);
          601  +  CREATE TEMP TABLE t13(a, b, c);
          602  +}
          603  +do_execsql_test 15.1 {
          604  +  BEGIN;
          605  +  INSERT INTO rt VALUES(1,2,3,4,5);
          606  +}
          607  +breakpoint
          608  +do_execsql_test 15.2 {
          609  +  DROP TABLE t13;
          610  +  COMMIT;
          611  +}
   594    612   
   595    613   finish_test

Changes to src/shell.c.

  1508   1508     }while( strstr(z,zBuf)!=0 );
  1509   1509     return zBuf;
  1510   1510   }
  1511   1511   
  1512   1512   /*
  1513   1513   ** Output the given string as a quoted string using SQL quoting conventions.
  1514   1514   **
  1515         -** The "\n" and "\r" characters are converted to char(10) and char(13)
  1516         -** to prevent them from being transformed by end-of-line translators.
         1515  +** See also: output_quoted_escaped_string()
  1517   1516   */
  1518   1517   static void output_quoted_string(FILE *out, const char *z){
  1519   1518     int i;
         1519  +  char c;
         1520  +  setBinaryMode(out, 1);
         1521  +  for(i=0; (c = z[i])!=0 && c!='\''; i++){}
         1522  +  if( c==0 ){
         1523  +    utf8_printf(out,"'%s'",z);
         1524  +  }else{
         1525  +    raw_printf(out, "'");
         1526  +    while( *z ){
         1527  +      for(i=0; (c = z[i])!=0 && c!='\''; i++){}
         1528  +      if( c=='\'' ) i++;
         1529  +      if( i ){
         1530  +        utf8_printf(out, "%.*s", i, z);
         1531  +        z += i;
         1532  +      }
         1533  +      if( c=='\'' ){
         1534  +        raw_printf(out, "'");
         1535  +        continue;
         1536  +      }
         1537  +      if( c==0 ){
         1538  +        break;
         1539  +      }
         1540  +      z++;
         1541  +    }
         1542  +    raw_printf(out, "'");
         1543  +  }
         1544  +  setTextMode(out, 1);
         1545  +}
         1546  +
         1547  +/*
         1548  +** Output the given string as a quoted string using SQL quoting conventions.
         1549  +** Additionallly , escape the "\n" and "\r" characters so that they do not
         1550  +** get corrupted by end-of-line translation facilities in some operating
         1551  +** systems.
         1552  +**
         1553  +** This is like output_quoted_string() but with the addition of the \r\n
         1554  +** escape mechanism.
         1555  +*/
         1556  +static void output_quoted_escaped_string(FILE *out, const char *z){
         1557  +  int i;
  1520   1558     char c;
  1521   1559     setBinaryMode(out, 1);
  1522   1560     for(i=0; (c = z[i])!=0 && c!='\'' && c!='\n' && c!='\r'; i++){}
  1523   1561     if( c==0 ){
  1524   1562       utf8_printf(out,"'%s'",z);
  1525   1563     }else{
  1526   1564       const char *zNL = 0;
................................................................................
  2027   2065             output_csv(p, azArg[i], i<nArg-1);
  2028   2066           }
  2029   2067           utf8_printf(p->out, "%s", p->rowSeparator);
  2030   2068         }
  2031   2069         setTextMode(p->out, 1);
  2032   2070         break;
  2033   2071       }
  2034         -    case MODE_Quote:
  2035   2072       case MODE_Insert: {
  2036   2073         if( azArg==0 ) break;
  2037         -      if( p->cMode==MODE_Insert ){
  2038         -        utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
  2039         -        if( p->showHeader ){
  2040         -          raw_printf(p->out,"(");
  2041         -          for(i=0; i<nArg; i++){
  2042         -            char *zSep = i>0 ? ",": "";
  2043         -            utf8_printf(p->out, "%s%s", zSep, azCol[i]);
  2044         -          }
  2045         -          raw_printf(p->out,")");
  2046         -        }
  2047         -        raw_printf(p->out," VALUES(");
  2048         -      }else if( p->cnt==0 && p->showHeader ){
         2074  +      utf8_printf(p->out,"INSERT INTO %s",p->zDestTable);
         2075  +      if( p->showHeader ){
         2076  +        raw_printf(p->out,"(");
         2077  +        for(i=0; i<nArg; i++){
         2078  +          if( i>0 ) raw_printf(p->out, ",");
         2079  +          if( quoteChar(azCol[i]) ){
         2080  +            char *z = sqlite3_mprintf("\"%w\"", azCol[i]);
         2081  +            utf8_printf(p->out, "%s", z);
         2082  +            sqlite3_free(z);
         2083  +          }else{
         2084  +            raw_printf(p->out, "%s", azCol[i]);
         2085  +          }
         2086  +        }
         2087  +        raw_printf(p->out,")");
         2088  +      }
         2089  +      p->cnt++;
         2090  +      for(i=0; i<nArg; i++){
         2091  +        raw_printf(p->out, i>0 ? "," : " VALUES(");
         2092  +        if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
         2093  +          utf8_printf(p->out,"NULL");
         2094  +        }else if( aiType && aiType[i]==SQLITE_TEXT ){
         2095  +          output_quoted_escaped_string(p->out, azArg[i]);
         2096  +        }else if( aiType && aiType[i]==SQLITE_INTEGER ){
         2097  +          utf8_printf(p->out,"%s", azArg[i]);
         2098  +        }else if( aiType && aiType[i]==SQLITE_FLOAT ){
         2099  +          char z[50];
         2100  +          double r = sqlite3_column_double(p->pStmt, i);
         2101  +          sqlite3_snprintf(50,z,"%!.20g", r);
         2102  +          raw_printf(p->out, "%s", z);
         2103  +        }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
         2104  +          const void *pBlob = sqlite3_column_blob(p->pStmt, i);
         2105  +          int nBlob = sqlite3_column_bytes(p->pStmt, i);
         2106  +          output_hex_blob(p->out, pBlob, nBlob);
         2107  +        }else if( isNumber(azArg[i], 0) ){
         2108  +          utf8_printf(p->out,"%s", azArg[i]);
         2109  +        }else{
         2110  +          output_quoted_escaped_string(p->out, azArg[i]);
         2111  +        }
         2112  +      }
         2113  +      raw_printf(p->out,");\n");
         2114  +      break;
         2115  +    }
         2116  +    case MODE_Quote: {
         2117  +      if( azArg==0 ) break;
         2118  +      if( p->cnt==0 && p->showHeader ){
  2049   2119           for(i=0; i<nArg; i++){
  2050   2120             if( i>0 ) raw_printf(p->out, ",");
  2051   2121             output_quoted_string(p->out, azCol[i]);
  2052   2122           }
  2053   2123           raw_printf(p->out,"\n");
  2054   2124         }
  2055   2125         p->cnt++;
  2056   2126         for(i=0; i<nArg; i++){
  2057         -        char *zSep = i>0 ? ",": "";
         2127  +        if( i>0 ) raw_printf(p->out, ",");
  2058   2128           if( (azArg[i]==0) || (aiType && aiType[i]==SQLITE_NULL) ){
  2059         -          utf8_printf(p->out,"%sNULL",zSep);
         2129  +          utf8_printf(p->out,"NULL");
  2060   2130           }else if( aiType && aiType[i]==SQLITE_TEXT ){
  2061         -          if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
  2062   2131             output_quoted_string(p->out, azArg[i]);
  2063   2132           }else if( aiType && aiType[i]==SQLITE_INTEGER ){
  2064         -          utf8_printf(p->out,"%s%s",zSep, azArg[i]);
         2133  +          utf8_printf(p->out,"%s", azArg[i]);
  2065   2134           }else if( aiType && aiType[i]==SQLITE_FLOAT ){
  2066   2135             char z[50];
  2067   2136             double r = sqlite3_column_double(p->pStmt, i);
  2068   2137             sqlite3_snprintf(50,z,"%!.20g", r);
  2069         -          raw_printf(p->out, "%s%s", zSep, z);
         2138  +          raw_printf(p->out, "%s", z);
  2070   2139           }else if( aiType && aiType[i]==SQLITE_BLOB && p->pStmt ){
  2071   2140             const void *pBlob = sqlite3_column_blob(p->pStmt, i);
  2072   2141             int nBlob = sqlite3_column_bytes(p->pStmt, i);
  2073         -          if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
  2074   2142             output_hex_blob(p->out, pBlob, nBlob);
  2075   2143           }else if( isNumber(azArg[i], 0) ){
  2076         -          utf8_printf(p->out,"%s%s",zSep, azArg[i]);
         2144  +          utf8_printf(p->out,"%s", azArg[i]);
  2077   2145           }else{
  2078         -          if( zSep[0] ) utf8_printf(p->out,"%s",zSep);
  2079   2146             output_quoted_string(p->out, azArg[i]);
  2080   2147           }
  2081   2148         }
  2082         -      raw_printf(p->out,p->cMode==MODE_Quote?"\n":");\n");
         2149  +      raw_printf(p->out,"\n");
  2083   2150         break;
  2084   2151       }
  2085   2152       case MODE_Ascii: {
  2086   2153         if( p->cnt++==0 && p->showHeader ){
  2087   2154           for(i=0; i<nArg; i++){
  2088   2155             if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator);
  2089   2156             utf8_printf(p->out,"%s",azCol[i] ? azCol[i] : "");
................................................................................
  4713   4780     if( c=='d' && strncmp(azArg[0], "dbinfo", n)==0 ){
  4714   4781       rc = shell_dbinfo_command(p, nArg, azArg);
  4715   4782     }else
  4716   4783   
  4717   4784     if( c=='d' && strncmp(azArg[0], "dump", n)==0 ){
  4718   4785       const char *zLike = 0;
  4719   4786       int i;
         4787  +    int savedShowHeader = p->showHeader;
  4720   4788       ShellClearFlag(p, SHFLG_PreserveRowid);
  4721   4789       for(i=1; i<nArg; i++){
  4722   4790         if( azArg[i][0]=='-' ){
  4723   4791           const char *z = azArg[i]+1;
  4724   4792           if( z[0]=='-' ) z++;
  4725   4793           if( strcmp(z,"preserve-rowids")==0 ){
  4726   4794   #ifdef SQLITE_OMIT_VIRTUALTABLE
................................................................................
  4748   4816       open_db(p, 0);
  4749   4817       /* When playing back a "dump", the content might appear in an order
  4750   4818       ** which causes immediate foreign key constraints to be violated.
  4751   4819       ** So disable foreign-key constraint enforcement to prevent problems. */
  4752   4820       raw_printf(p->out, "PRAGMA foreign_keys=OFF;\n");
  4753   4821       raw_printf(p->out, "BEGIN TRANSACTION;\n");
  4754   4822       p->writableSchema = 0;
         4823  +    p->showHeader = 0;
  4755   4824       /* Set writable_schema=ON since doing so forces SQLite to initialize
  4756   4825       ** as much of the schema as it can even if the sqlite_master table is
  4757   4826       ** corrupt. */
  4758   4827       sqlite3_exec(p->db, "SAVEPOINT dump; PRAGMA writable_schema=ON", 0, 0, 0);
  4759   4828       p->nErr = 0;
  4760   4829       if( zLike==0 ){
  4761   4830         run_schema_dump_query(p,
................................................................................
  4789   4858       if( p->writableSchema ){
  4790   4859         raw_printf(p->out, "PRAGMA writable_schema=OFF;\n");
  4791   4860         p->writableSchema = 0;
  4792   4861       }
  4793   4862       sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0);
  4794   4863       sqlite3_exec(p->db, "RELEASE dump;", 0, 0, 0);
  4795   4864       raw_printf(p->out, p->nErr ? "ROLLBACK; -- due to errors\n" : "COMMIT;\n");
         4865  +    p->showHeader = savedShowHeader;
  4796   4866     }else
  4797   4867   
  4798   4868     if( c=='e' && strncmp(azArg[0], "echo", n)==0 ){
  4799   4869       if( nArg==2 ){
  4800   4870         setOrClearFlag(p, SHFLG_Echo, azArg[1]);
  4801   4871       }else{
  4802   4872         raw_printf(stderr, "Usage: .echo on|off\n");

Changes to src/vdbe.c.

  5383   5383   ** P3==1 then the table to be clear is in the auxiliary database file
  5384   5384   ** that is used to store tables create using CREATE TEMPORARY TABLE.
  5385   5385   **
  5386   5386   ** If AUTOVACUUM is enabled then it is possible that another root page
  5387   5387   ** might be moved into the newly deleted root page in order to keep all
  5388   5388   ** root pages contiguous at the beginning of the database.  The former
  5389   5389   ** value of the root page that moved - its value before the move occurred -
  5390         -** is stored in register P2.  If no page 
  5391         -** movement was required (because the table being dropped was already 
  5392         -** the last one in the database) then a zero is stored in register P2.
  5393         -** If AUTOVACUUM is disabled then a zero is stored in register P2.
         5390  +** is stored in register P2. If no page movement was required (because the
         5391  +** table being dropped was already the last one in the database) then a 
         5392  +** zero is stored in register P2.  If AUTOVACUUM is disabled then a zero 
         5393  +** is stored in register P2.
         5394  +**
         5395  +** This opcode throws an error if there are any active reader VMs when
         5396  +** it is invoked. This is done to avoid the difficulty associated with 
         5397  +** updating existing cursors when a root page is moved in an AUTOVACUUM 
         5398  +** database. This error is thrown even if the database is not an AUTOVACUUM 
         5399  +** db in order to avoid introducing an incompatibility between autovacuum 
         5400  +** and non-autovacuum modes.
  5394   5401   **
  5395   5402   ** See also: Clear
  5396   5403   */
  5397   5404   case OP_Destroy: {     /* out2 */
  5398   5405     int iMoved;
  5399   5406     int iDb;
  5400   5407   

Changes to test/json102.test.

   293    293   #
   294    294   for {set i 0} {$i<100} {incr i} {
   295    295     set str abcdef[string repeat \" [expr {$i+50}]]uvwxyz
   296    296     do_test json102-[format %d [expr {$i+1300}]] {
   297    297       db eval {SELECT json_extract(json_array($::str),'$[0]')==$::str}
   298    298     } {1}
   299    299   }
          300  +
          301  +#-------------------------------------------------------------------------
          302  +# 2017-04-08 ticket b93be8729a895a528e2849fca99f7
          303  +# JSON extension accepts invalid numeric values
          304  +#
          305  +# JSON does not allow leading zeros.  But the JSON extension was
          306  +# allowing them.  The following tests verify that the problem is now
          307  +# fixed.
          308  +#
          309  +do_execsql_test json102-1401 { SELECT json_valid('{"x":01}') } 0
          310  +do_execsql_test json102-1402 { SELECT json_valid('{"x":-01}') } 0
          311  +do_execsql_test json102-1403 { SELECT json_valid('{"x":0}') } 1
          312  +do_execsql_test json102-1404 { SELECT json_valid('{"x":-0}') } 1
          313  +do_execsql_test json102-1405 { SELECT json_valid('{"x":0.1}') } 1
          314  +do_execsql_test json102-1406 { SELECT json_valid('{"x":-0.1}') } 1
          315  +do_execsql_test json102-1407 { SELECT json_valid('{"x":0.0000}') } 1
          316  +do_execsql_test json102-1408 { SELECT json_valid('{"x":-0.0000}') } 1
          317  +do_execsql_test json102-1409 { SELECT json_valid('{"x":01.5}') } 0
          318  +do_execsql_test json102-1410 { SELECT json_valid('{"x":-01.5}') } 0
          319  +do_execsql_test json102-1411 { SELECT json_valid('{"x":00}') } 0
          320  +do_execsql_test json102-1412 { SELECT json_valid('{"x":-00}') } 0
   300    321   
   301    322   finish_test