/ Check-in [30f08d58]
Login

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

Overview
Comment:Enhancements to deserialize: (1) Add the SQLITE_FCNTL_SIZE_LIMIT file control to set a maximum size for an in-memory database, defaulting to SQLITE_MEMDB_DEFAULT_MAXSIZE or 1GiB. (2) Honor the SQLITE_DESERIALIZE_READONLY flag. (3) Enhance the TCL interface to support -maxsize N and -readonly BOOLEAN. (4) Add the --maxsize option to the ".open" command and on the command-line for the CLI.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 30f08d58882819a69e353bcc1b6b349664bbfbe00aa1c115ba44a9fd899fcc5b
User & Date: drh 2019-01-22 16:06:20
Context
2019-01-22
16:11
Update dbfuzz2 to set a maximum database size of 100MiB by default, but with the new --max-db-size N option to change that limit. check-in: 21d6bb78 user: drh tags: trunk
16:06
Enhancements to deserialize: (1) Add the SQLITE_FCNTL_SIZE_LIMIT file control to set a maximum size for an in-memory database, defaulting to SQLITE_MEMDB_DEFAULT_MAXSIZE or 1GiB. (2) Honor the SQLITE_DESERIALIZE_READONLY flag. (3) Enhance the TCL interface to support -maxsize N and -readonly BOOLEAN. (4) Add the --maxsize option to the ".open" command and on the command-line for the CLI. check-in: 30f08d58 user: drh tags: trunk
13:45
Make sure cursors are opened on all indexes for an UPDATE OR REPLACE regardless of whether or not the indexes are partial or contain columns that might need to be updated. check-in: e148cdad user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Show Whitespace Changes Patch

Changes to src/memdb.c.

    30     30   */
    31     31   #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
    32     32   
    33     33   /* An open file */
    34     34   struct MemFile {
    35     35     sqlite3_file base;              /* IO methods */
    36     36     sqlite3_int64 sz;               /* Size of the file */
    37         -  sqlite3_int64 szMax;            /* Space allocated to aData */
           37  +  sqlite3_int64 szAlloc;          /* Space allocated to aData */
           38  +  sqlite3_int64 szMax;            /* Maximum allowed size of the file */
    38     39     unsigned char *aData;           /* content of the file */
    39     40     int nMmap;                      /* Number of memory mapped pages */
    40     41     unsigned mFlags;                /* Flags */
    41     42     int eLock;                      /* Most recent lock against this file */
    42     43   };
           44  +
           45  +/* The default maximum size of an in-memory database */
           46  +#ifndef SQLITE_MEMDB_DEFAULT_MAXSIZE
           47  +# define SQLITE_MEMDB_DEFAULT_MAXSIZE 1073741824
           48  +#endif
    43     49   
    44     50   /*
    45     51   ** Methods for MemFile
    46     52   */
    47     53   static int memdbClose(sqlite3_file*);
    48     54   static int memdbRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
    49     55   static int memdbWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
................................................................................
   156    162   ** Try to enlarge the memory allocation to hold at least sz bytes
   157    163   */
   158    164   static int memdbEnlarge(MemFile *p, sqlite3_int64 newSz){
   159    165     unsigned char *pNew;
   160    166     if( (p->mFlags & SQLITE_DESERIALIZE_RESIZEABLE)==0 || p->nMmap>0 ){
   161    167       return SQLITE_FULL;
   162    168     }
          169  +  if( newSz>p->szMax ){
          170  +    return SQLITE_FULL;
          171  +  }
          172  +  newSz *= 2;
          173  +  if( newSz>p->szMax ) newSz = p->szMax;
   163    174     pNew = sqlite3_realloc64(p->aData, newSz);
   164    175     if( pNew==0 ) return SQLITE_NOMEM;
   165    176     p->aData = pNew;
   166         -  p->szMax = newSz;
          177  +  p->szAlloc = newSz;
   167    178     return SQLITE_OK;
   168    179   }
   169    180   
   170    181   /*
   171    182   ** Write data to an memdb-file.
   172    183   */
   173    184   static int memdbWrite(
   174    185     sqlite3_file *pFile,
   175    186     const void *z,
   176    187     int iAmt,
   177    188     sqlite_int64 iOfst
   178    189   ){
   179    190     MemFile *p = (MemFile *)pFile;
          191  +  if( p->mFlags & SQLITE_DESERIALIZE_READONLY ) return SQLITE_READONLY;
   180    192     if( iOfst+iAmt>p->sz ){
   181    193       int rc;
   182         -    if( iOfst+iAmt>p->szMax
   183         -     && (rc = memdbEnlarge(p, (iOfst+iAmt)*2))!=SQLITE_OK
          194  +    if( iOfst+iAmt>p->szAlloc
          195  +     && (rc = memdbEnlarge(p, iOfst+iAmt))!=SQLITE_OK
   184    196       ){
   185    197         return rc;
   186    198       }
   187    199       if( iOfst>p->sz ) memset(p->aData+p->sz, 0, iOfst-p->sz);
   188    200       p->sz = iOfst+iAmt;
   189    201     }
   190    202     memcpy(p->aData+iOfst, z, iAmt);
................................................................................
   246    258   static int memdbFileControl(sqlite3_file *pFile, int op, void *pArg){
   247    259     MemFile *p = (MemFile *)pFile;
   248    260     int rc = SQLITE_NOTFOUND;
   249    261     if( op==SQLITE_FCNTL_VFSNAME ){
   250    262       *(char**)pArg = sqlite3_mprintf("memdb(%p,%lld)", p->aData, p->sz);
   251    263       rc = SQLITE_OK;
   252    264     }
          265  +  if( op==SQLITE_FCNTL_SIZE_LIMIT ){
          266  +    sqlite3_int64 iLimit = *(sqlite3_int64*)pArg;
          267  +    if( iLimit<p->sz ){
          268  +      if( iLimit<0 ){
          269  +        iLimit = p->szMax;
          270  +      }else{
          271  +        iLimit = p->sz;
          272  +      }
          273  +    }
          274  +    p->szMax = iLimit;
          275  +    *(sqlite3_int64*)pArg = iLimit;
          276  +    rc = SQLITE_OK;
          277  +  }
   253    278     return rc;
   254    279   }
   255    280   
   256    281   #if 0  /* Not used because of SQLITE_IOCAP_POWERSAFE_OVERWRITE */
   257    282   /*
   258    283   ** Return the sector-size in bytes for an memdb-file.
   259    284   */
................................................................................
   307    332       return ORIGVFS(pVfs)->xOpen(ORIGVFS(pVfs), zName, pFile, flags, pOutFlags);
   308    333     }
   309    334     memset(p, 0, sizeof(*p));
   310    335     p->mFlags = SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE;
   311    336     assert( pOutFlags!=0 );  /* True because flags==SQLITE_OPEN_MAIN_DB */
   312    337     *pOutFlags = flags | SQLITE_OPEN_MEMORY;
   313    338     p->base.pMethods = &memdb_io_methods;
          339  +  p->szMax = SQLITE_MEMDB_DEFAULT_MAXSIZE;
   314    340     return SQLITE_OK;
   315    341   }
   316    342   
   317    343   #if 0 /* Only used to delete rollback journals, master journals, and WAL
   318    344         ** files, none of which exist in memdb.  So this routine is never used */
   319    345   /*
   320    346   ** Delete the file located at zPath. If the dirSync argument is true,
................................................................................
   556    582     }
   557    583     p = memdbFromDbSchema(db, zSchema);
   558    584     if( p==0 ){
   559    585       rc = SQLITE_ERROR;
   560    586     }else{
   561    587       p->aData = pData;
   562    588       p->sz = szDb;
          589  +    p->szAlloc = szBuf;
   563    590       p->szMax = szBuf;
          591  +    if( p->szMax<SQLITE_MEMDB_DEFAULT_MAXSIZE ){
          592  +      p->szMax = SQLITE_MEMDB_DEFAULT_MAXSIZE;
          593  +    }
   564    594       p->mFlags = mFlags;
   565    595       rc = SQLITE_OK;
   566    596     }
   567    597   
   568    598   end_deserialize:
   569    599     sqlite3_finalize(pStmt);
   570    600     sqlite3_mutex_leave(db->mutex);

Changes to src/shell.c.in.

  1021   1021     int modePrior;         /* Saved mode */
  1022   1022     int cMode;             /* temporary output mode for the current query */
  1023   1023     int normalMode;        /* Output mode before ".explain on" */
  1024   1024     int writableSchema;    /* True if PRAGMA writable_schema=ON */
  1025   1025     int showHeader;        /* True to show column names in List or Column mode */
  1026   1026     int nCheck;            /* Number of ".check" commands run */
  1027   1027     unsigned shellFlgs;    /* Various flags */
         1028  +  sqlite3_int64 szMax;   /* --maxsize argument to .open */
  1028   1029     char *zDestTable;      /* Name of destination table when MODE_Insert */
  1029   1030     char *zTempFile;       /* Temporary file that might need deleting */
  1030   1031     char zTestcase[30];    /* Name of current test case */
  1031   1032     char colSeparator[20]; /* Column separator character for several modes */
  1032   1033     char rowSeparator[20]; /* Row separator character for MODE_Ascii */
  1033   1034     char colSepPrior[20];  /* Saved column separator */
  1034   1035     char rowSepPrior[20];  /* Saved row separator */
................................................................................
  3445   3446     "       -x    Open in a spreadsheet",
  3446   3447     ".open ?OPTIONS? ?FILE?   Close existing database and reopen FILE",
  3447   3448     "     Options:",
  3448   3449     "        --append        Use appendvfs to append database to the end of FILE",
  3449   3450   #ifdef SQLITE_ENABLE_DESERIALIZE
  3450   3451     "        --deserialize   Load into memory useing sqlite3_deserialize()",
  3451   3452     "        --hexdb         Load the output of \"dbtotxt\" as an in-memory database",
         3453  +  "        --maxsize N     Maximum size for --hexdb or --deserialized database",
  3452   3454   #endif
  3453   3455     "        --new           Initialize FILE to an empty database",
  3454   3456     "        --readonly      Open FILE readonly",
  3455   3457     "        --zip           FILE is a ZIP archive",
  3456   3458     ".output ?FILE?           Send output to FILE or stdout if FILE is omitted",
  3457   3459     "     If FILE begins with '|' then open it as a pipe.",
  3458   3460     ".print STRING...         Print literal STRING",
................................................................................
  3923   3925         }
  3924   3926         rc = sqlite3_deserialize(p->db, "main", aData, nData, nData,
  3925   3927                      SQLITE_DESERIALIZE_RESIZEABLE |
  3926   3928                      SQLITE_DESERIALIZE_FREEONCLOSE);
  3927   3929         if( rc ){
  3928   3930           utf8_printf(stderr, "Error: sqlite3_deserialize() returns %d\n", rc);
  3929   3931         }
         3932  +      if( p->szMax>0 ){
         3933  +        sqlite3_file_control(p->db, "main", SQLITE_FCNTL_SIZE_LIMIT, &p->szMax);
         3934  +      }
  3930   3935       }
  3931   3936   #endif
  3932   3937     }
  3933   3938   }
  3934   3939   
  3935   3940   /*
  3936   3941   ** Attempt to close the databaes connection.  Report errors.
................................................................................
  6837   6842       session_close_all(p);
  6838   6843       close_db(p->db);
  6839   6844       p->db = 0;
  6840   6845       p->zDbFilename = 0;
  6841   6846       sqlite3_free(p->zFreeOnClose);
  6842   6847       p->zFreeOnClose = 0;
  6843   6848       p->openMode = SHELL_OPEN_UNSPEC;
         6849  +    p->szMax = 0;
  6844   6850       /* Check for command-line arguments */
  6845   6851       for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){
  6846   6852         const char *z = azArg[iName];
  6847   6853         if( optionMatch(z,"new") ){
  6848   6854           newFlag = 1;
  6849   6855   #ifdef SQLITE_HAVE_ZLIB
  6850   6856         }else if( optionMatch(z, "zip") ){
................................................................................
  6855   6861         }else if( optionMatch(z, "readonly") ){
  6856   6862           p->openMode = SHELL_OPEN_READONLY;
  6857   6863   #ifdef SQLITE_ENABLE_DESERIALIZE
  6858   6864         }else if( optionMatch(z, "deserialize") ){
  6859   6865           p->openMode = SHELL_OPEN_DESERIALIZE;
  6860   6866         }else if( optionMatch(z, "hexdb") ){
  6861   6867           p->openMode = SHELL_OPEN_HEXDB;
         6868  +      }else if( optionMatch(z, "maxsize") && iName+1<nArg ){
         6869  +        p->szMax = integerValue(azArg[++iName]);
  6862   6870   #endif /* SQLITE_ENABLE_DESERIALIZE */
  6863   6871         }else if( z[0]=='-' ){
  6864   6872           utf8_printf(stderr, "unknown option: %s\n", z);
  6865   6873           rc = 1;
  6866   6874           goto meta_command_exit;
  6867   6875         }
  6868   6876       }
................................................................................
  8545   8553     "   -append              append the database to the end of the file\n"
  8546   8554     "   -ascii               set output mode to 'ascii'\n"
  8547   8555     "   -bail                stop after hitting an error\n"
  8548   8556     "   -batch               force batch I/O\n"
  8549   8557     "   -column              set output mode to 'column'\n"
  8550   8558     "   -cmd COMMAND         run \"COMMAND\" before reading stdin\n"
  8551   8559     "   -csv                 set output mode to 'csv'\n"
         8560  +#if defined(SQLITE_ENABLE_DESERIALIZE)
         8561  +  "   -deserialize         open the database using sqlite3_deserialize()\n"
         8562  +#endif
  8552   8563     "   -echo                print commands before execution\n"
  8553   8564     "   -init FILENAME       read/process named file\n"
  8554   8565     "   -[no]header          turn headers on or off\n"
  8555   8566   #if defined(SQLITE_ENABLE_MEMSYS3) || defined(SQLITE_ENABLE_MEMSYS5)
  8556   8567     "   -heap SIZE           Size of heap for memsys3 or memsys5\n"
  8557   8568   #endif
  8558   8569     "   -help                show this message\n"
  8559   8570     "   -html                set output mode to HTML\n"
  8560   8571     "   -interactive         force interactive I/O\n"
  8561   8572     "   -line                set output mode to 'line'\n"
  8562   8573     "   -list                set output mode to 'list'\n"
  8563   8574     "   -lookaside SIZE N    use N entries of SZ bytes for lookaside memory\n"
         8575  +#if defined(SQLITE_ENABLE_DESERIALIZE)
         8576  +  "   -maxsize N           maximum size for a --deserialize database\n"
         8577  +#endif
  8564   8578     "   -mmap N              default mmap size set to N\n"
  8565   8579   #ifdef SQLITE_ENABLE_MULTIPLEX
  8566   8580     "   -multiplex           enable the multiplexor VFS\n"
  8567   8581   #endif
  8568   8582     "   -newline SEP         set output row separator. Default: '\\n'\n"
  8569   8583     "   -nullvalue TEXT      set text string for NULL values. Default ''\n"
  8570   8584     "   -pagecache SIZE N    use N slots of SZ bytes each for page cache memory\n"
................................................................................
  8867   8881         data.openMode = SHELL_OPEN_ZIPFILE;
  8868   8882   #endif
  8869   8883       }else if( strcmp(z,"-append")==0 ){
  8870   8884         data.openMode = SHELL_OPEN_APPENDVFS;
  8871   8885   #ifdef SQLITE_ENABLE_DESERIALIZE
  8872   8886       }else if( strcmp(z,"-deserialize")==0 ){
  8873   8887         data.openMode = SHELL_OPEN_DESERIALIZE;
         8888  +    }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){
         8889  +      data.szMax = integerValue(argv[++i]);
  8874   8890   #endif
  8875   8891       }else if( strcmp(z,"-readonly")==0 ){
  8876   8892         data.openMode = SHELL_OPEN_READONLY;
  8877   8893   #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB)
  8878   8894       }else if( strncmp(z, "-A",2)==0 ){
  8879   8895         /* All remaining command-line arguments are passed to the ".archive"
  8880   8896         ** command, so ignore them */
................................................................................
  8968   8984         data.openMode = SHELL_OPEN_ZIPFILE;
  8969   8985   #endif
  8970   8986       }else if( strcmp(z,"-append")==0 ){
  8971   8987         data.openMode = SHELL_OPEN_APPENDVFS;
  8972   8988   #ifdef SQLITE_ENABLE_DESERIALIZE
  8973   8989       }else if( strcmp(z,"-deserialize")==0 ){
  8974   8990         data.openMode = SHELL_OPEN_DESERIALIZE;
         8991  +    }else if( strcmp(z,"-maxsize")==0 && i+1<argc ){
         8992  +      data.szMax = integerValue(argv[++i]);
  8975   8993   #endif
  8976   8994       }else if( strcmp(z,"-readonly")==0 ){
  8977   8995         data.openMode = SHELL_OPEN_READONLY;
  8978   8996       }else if( strcmp(z,"-ascii")==0 ){
  8979   8997         data.mode = MODE_Ascii;
  8980   8998         sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator,
  8981   8999                          SEP_Unit);

Changes to src/sqlite.h.in.

   819    819   ** The [SQLITE_FCNTL_SIZE_HINT] opcode is used by SQLite to give the VFS
   820    820   ** layer a hint of how large the database file will grow to be during the
   821    821   ** current transaction.  This hint is not guaranteed to be accurate but it
   822    822   ** is often close.  The underlying VFS might choose to preallocate database
   823    823   ** file space based on this hint in order to help writes to the database
   824    824   ** file run faster.
   825    825   **
          826  +** <li>[[SQLITE_FCNTL_SIZE_LIMIT]]
          827  +** The [SQLITE_FCNTL_SIZE_LIMIT] opcode is used by in-memory VFS that
          828  +** implements [sqlite3_deserialize()] to set an upper bound on the size
          829  +** of the in-memory database.  The argument is a pointer to a [sqlite3_int64].
          830  +** If the integer pointed to is negative, then it is filled in with the
          831  +** current limit.  Otherwise the limit is set to the larger of the value
          832  +** of the integer pointed to and the current database size.  The integer
          833  +** pointed to is set to the new limit.
          834  +**
   826    835   ** <li>[[SQLITE_FCNTL_CHUNK_SIZE]]
   827    836   ** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
   828    837   ** extends and truncates the database file in chunks of a size specified
   829    838   ** by the user. The fourth argument to [sqlite3_file_control()] should 
   830    839   ** point to an integer (type int) containing the new chunk-size to use
   831    840   ** for the nominated database. Allocating database file space in large
   832    841   ** chunks (say 1MB at a time), may reduce file-system fragmentation and
................................................................................
  1127   1136   #define SQLITE_FCNTL_WIN32_GET_HANDLE       29
  1128   1137   #define SQLITE_FCNTL_PDB                    30
  1129   1138   #define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE     31
  1130   1139   #define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE    32
  1131   1140   #define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE  33
  1132   1141   #define SQLITE_FCNTL_LOCK_TIMEOUT           34
  1133   1142   #define SQLITE_FCNTL_DATA_VERSION           35
         1143  +#define SQLITE_FCNTL_SIZE_LIMIT             36
  1134   1144   
  1135   1145   /* deprecated names */
  1136   1146   #define SQLITE_GET_LOCKPROXYFILE      SQLITE_FCNTL_GET_LOCKPROXYFILE
  1137   1147   #define SQLITE_SET_LOCKPROXYFILE      SQLITE_FCNTL_SET_LOCKPROXYFILE
  1138   1148   #define SQLITE_LAST_ERRNO             SQLITE_FCNTL_LAST_ERRNO
  1139   1149   
  1140   1150   

Changes to src/tclsqlite.c.

  2414   2414                          (char*)0);
  2415   2415         rc = TCL_ERROR;
  2416   2416       }
  2417   2417       break;
  2418   2418     }
  2419   2419   
  2420   2420     /*
  2421         -  **     $db deserialize ?DATABASE? VALUE
         2421  +  **     $db deserialize ?-maxsize N? ?-readonly BOOL? ?DATABASE? VALUE
  2422   2422     **
  2423   2423     ** Reopen DATABASE (default "main") using the content in $VALUE
  2424   2424     */
  2425   2425     case DB_DESERIALIZE: {
  2426   2426   #ifndef SQLITE_ENABLE_DESERIALIZE
  2427   2427       Tcl_AppendResult(interp, "MEMDB not available in this build",
  2428   2428                        (char*)0);
  2429   2429       rc = TCL_ERROR;
  2430   2430   #else
  2431         -    const char *zSchema;
  2432         -    Tcl_Obj *pValue;
         2431  +    const char *zSchema = 0;
         2432  +    Tcl_Obj *pValue = 0;
  2433   2433       unsigned char *pBA;
  2434   2434       unsigned char *pData;
  2435   2435       int len, xrc;
         2436  +    sqlite3_int64 mxSize = 0;
         2437  +    int i;
         2438  +    int isReadonly = 0;
  2436   2439       
  2437         -    if( objc==3 ){
  2438         -      zSchema = 0;
  2439         -      pValue = objv[2];
  2440         -    }else if( objc==4 ){
  2441         -      zSchema = Tcl_GetString(objv[2]);
  2442         -      pValue = objv[3];
  2443         -    }else{
         2440  +
         2441  +    if( objc<3 ){
  2444   2442         Tcl_WrongNumArgs(interp, 2, objv, "?DATABASE? VALUE");
  2445   2443         rc = TCL_ERROR;
  2446   2444         break;
  2447   2445       }
         2446  +    for(i=2; i<objc-1; i++){
         2447  +      const char *z = Tcl_GetString(objv[i]);
         2448  +      if( strcmp(z,"-maxsize")==0 && i<objc-2 ){
         2449  +        rc = Tcl_GetWideIntFromObj(interp, objv[++i], &mxSize);
         2450  +        if( rc ) goto deserialize_error;
         2451  +        continue;
         2452  +      }
         2453  +      if( strcmp(z,"-readonly")==0 && i<objc-2 ){
         2454  +        rc = Tcl_GetBooleanFromObj(interp, objv[++i], &isReadonly);
         2455  +        if( rc ) goto deserialize_error;
         2456  +        continue;
         2457  +      }
         2458  +      if( zSchema==0 && i==objc-2 && z[0]!='-' ){
         2459  +        zSchema = z;
         2460  +        continue;
         2461  +      }
         2462  +      Tcl_AppendResult(interp, "unknown option: ", z, (char*)0);
         2463  +      rc = TCL_ERROR;
         2464  +      goto deserialize_error;
         2465  +    }
         2466  +    pValue = objv[objc-1];
  2448   2467       pBA = Tcl_GetByteArrayFromObj(pValue, &len);
  2449   2468       pData = sqlite3_malloc64( len );
  2450   2469       if( pData==0 && len>0 ){
  2451   2470         Tcl_AppendResult(interp, "out of memory", (char*)0);
  2452   2471         rc = TCL_ERROR;
  2453   2472       }else{
         2473  +      int flags;
  2454   2474         if( len>0 ) memcpy(pData, pBA, len);
  2455         -      xrc = sqlite3_deserialize(pDb->db, zSchema, pData, len, len,
  2456         -                SQLITE_DESERIALIZE_FREEONCLOSE |
  2457         -                SQLITE_DESERIALIZE_RESIZEABLE);
         2475  +      if( isReadonly ){
         2476  +        flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_READONLY;
         2477  +      }else{
         2478  +        flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE;
         2479  +      }
         2480  +      xrc = sqlite3_deserialize(pDb->db, zSchema, pData, len, len, flags);
  2458   2481         if( xrc ){
  2459   2482           Tcl_AppendResult(interp, "unable to set MEMDB content", (char*)0);
  2460   2483           rc = TCL_ERROR;
  2461   2484         }
         2485  +      if( mxSize>0 ){
         2486  +        sqlite3_file_control(pDb->db, zSchema,SQLITE_FCNTL_SIZE_LIMIT,&mxSize);
  2462   2487       }
         2488  +    }
         2489  +deserialize_error:
  2463   2490   #endif
  2464   2491       break; 
  2465   2492     }
  2466   2493   
  2467   2494     /*
  2468   2495     **    $db enable_load_extension BOOLEAN
  2469   2496     **

Changes to test/memdb1.test.

    67     67     DROP TABLE t2;
    68     68     PRAGMA page_count;
    69     69   } {116}
    70     70   do_execsql_test 140 {
    71     71     VACUUM;
    72     72     PRAGMA page_count;
    73     73   } {2}
           74  +
           75  +do_test 150 {
           76  +  catch {db deserialize -unknown 1 $db1} msg
           77  +  set msg
           78  +} {unknown option: -unknown}
           79  +do_test 151 {
           80  +  db deserialize -readonly 1 $db1
           81  +  db eval {SELECT * FROM t1}
           82  +} {1 2}
           83  +do_test 152 {
           84  +  catchsql {INSERT INTO t1 VALUES(3,4);}
           85  +} {1 {attempt to write a readonly database}}
           86  +
           87  +breakpoint
           88  +do_test 160 {
           89  +  db deserialize -maxsize 32768 $db1
           90  +  db eval {SELECT * FROM t1}
           91  +} {1 2}
           92  +do_test 161 {
           93  +  db eval {INSERT INTO t1 VALUES(3,4); SELECT * FROM t1}
           94  +} {1 2 3 4}
           95  +do_test 162 {
           96  +  catchsql {INSERT INTO t1 VALUES(5,randomblob(100000))}
           97  +} {1 {database or disk is full}}
           98  +
    74     99   
    75    100   # Build a largish on-disk database and serialize it.  Verify that the
    76    101   # serialization works.
    77    102   #
    78    103   db close
    79    104   forcedelete test.db
    80    105   sqlite3 db test.db
................................................................................
   150    175   do_test 600 {
   151    176     set rc [catch {db deserialize} msg]
   152    177     lappend rc $msg
   153    178   } {1 {wrong # args: should be "db deserialize ?DATABASE? VALUE"}}
   154    179   do_test 610 {
   155    180     set rc [catch {db deserialize a b c} msg]
   156    181     lappend rc $msg
   157         -} {1 {wrong # args: should be "db deserialize ?DATABASE? VALUE"}}
          182  +} {1 {unknown option: a}}
   158    183   do_test 620 {
   159    184     set rc [catch {db serialize a b} msg]
   160    185     lappend rc $msg
   161    186   } {1 {wrong # args: should be "db serialize ?DATABASE?"}}
   162    187   
   163    188   finish_test