/ Check-in [03a70c3d]
Login

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

Overview
Comment:Merge the nx-devkit changes into trunk.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:03a70c3dae8d912fccd9d72c575dc372b198d238
User & Date: drh 2011-12-13 15:37:12
Context
2011-12-14
00:37
Treat a zero return value from the Win32 APIs MultiByteToWideChar and WideCharToMultiByte as an error condition. check-in: c65e5a36 user: mistachkin tags: trunk
2011-12-13
15:37
Merge the nx-devkit changes into trunk. check-in: 03a70c3d user: drh tags: trunk
15:25
Update the multiplex.test script to conform to that found in the "experimental" branch off of trunk. check-in: 2eb79efb user: drh tags: nx-devkit
2011-12-12
19:48
Fix os_unix.c so that, unless 8.3 filenames are actually in use, journal and wal file permissions are assigned correctly even if SQLITE_ENABLE_8_3_NAMES is defined. check-in: 169e1229 user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/loadext.c.

621
622
623
624
625
626
627

628
629
630
631
632
633
634
...
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
** Load all automatic extensions.
**
** If anything goes wrong, set an error in the database connection.
*/
void sqlite3AutoLoadExtensions(sqlite3 *db){
  int i;
  int go = 1;

  int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);

  wsdAutoextInit;
  if( wsdAutoext.nExt==0 ){
    /* Common case: early out without every having to acquire a mutex */
    return;
  }
................................................................................
      go = 0;
    }else{
      xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
              wsdAutoext.aExt[i];
    }
    sqlite3_mutex_leave(mutex);
    zErrmsg = 0;
    if( xInit && xInit(db, &zErrmsg, &sqlite3Apis) ){
      sqlite3Error(db, SQLITE_ERROR,
            "automatic extension loading failed: %s", zErrmsg);
      go = 0;
    }
    sqlite3_free(zErrmsg);
  }
}







>







 







|
|






621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
...
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
** Load all automatic extensions.
**
** If anything goes wrong, set an error in the database connection.
*/
void sqlite3AutoLoadExtensions(sqlite3 *db){
  int i;
  int go = 1;
  int rc;
  int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);

  wsdAutoextInit;
  if( wsdAutoext.nExt==0 ){
    /* Common case: early out without every having to acquire a mutex */
    return;
  }
................................................................................
      go = 0;
    }else{
      xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
              wsdAutoext.aExt[i];
    }
    sqlite3_mutex_leave(mutex);
    zErrmsg = 0;
    if( xInit && (rc = xInit(db, &zErrmsg, &sqlite3Apis))!=0 ){
      sqlite3Error(db, rc,
            "automatic extension loading failed: %s", zErrmsg);
      go = 0;
    }
    sqlite3_free(zErrmsg);
  }
}

Changes to src/main.c.

253
254
255
256
257
258
259




260
261
262
263
264
265
266
....
2235
2236
2237
2238
2239
2240
2241


2242
2243
2244
2245
2246

2247
2248
2249
2250
2251
2252
2253
** while any part of SQLite is otherwise in use in any thread.  This
** routine is not threadsafe.  But it is safe to invoke this routine
** on when SQLite is already shut down.  If SQLite is already shut down
** when this routine is invoked, then this routine is a harmless no-op.
*/
int sqlite3_shutdown(void){
  if( sqlite3GlobalConfig.isInit ){




    sqlite3_os_end();
    sqlite3_reset_auto_extension();
    sqlite3GlobalConfig.isInit = 0;
  }
  if( sqlite3GlobalConfig.isPCacheInit ){
    sqlite3PcacheShutdown();
    sqlite3GlobalConfig.isPCacheInit = 0;
................................................................................
  */
  sqlite3Error(db, SQLITE_OK, 0);
  sqlite3RegisterBuiltinFunctions(db);

  /* Load automatic extensions - extensions that have been registered
  ** using the sqlite3_automatic_extension() API.
  */


  sqlite3AutoLoadExtensions(db);
  rc = sqlite3_errcode(db);
  if( rc!=SQLITE_OK ){
    goto opendb_out;
  }


#ifdef SQLITE_ENABLE_FTS1
  if( !db->mallocFailed ){
    extern int sqlite3Fts1Init(sqlite3*);
    rc = sqlite3Fts1Init(db);
  }
#endif







>
>
>
>







 







>
>





>







253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
....
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
** while any part of SQLite is otherwise in use in any thread.  This
** routine is not threadsafe.  But it is safe to invoke this routine
** on when SQLite is already shut down.  If SQLite is already shut down
** when this routine is invoked, then this routine is a harmless no-op.
*/
int sqlite3_shutdown(void){
  if( sqlite3GlobalConfig.isInit ){
#ifdef SQLITE_EXTRA_SHUTDOWN
    void SQLITE_EXTRA_SHUTDOWN(void);
    SQLITE_EXTRA_SHUTDOWN();
#endif
    sqlite3_os_end();
    sqlite3_reset_auto_extension();
    sqlite3GlobalConfig.isInit = 0;
  }
  if( sqlite3GlobalConfig.isPCacheInit ){
    sqlite3PcacheShutdown();
    sqlite3GlobalConfig.isPCacheInit = 0;
................................................................................
  */
  sqlite3Error(db, SQLITE_OK, 0);
  sqlite3RegisterBuiltinFunctions(db);

  /* Load automatic extensions - extensions that have been registered
  ** using the sqlite3_automatic_extension() API.
  */
  rc = sqlite3_errcode(db);
  if( rc==SQLITE_OK ){
    sqlite3AutoLoadExtensions(db);
    rc = sqlite3_errcode(db);
    if( rc!=SQLITE_OK ){
      goto opendb_out;
    }
  }

#ifdef SQLITE_ENABLE_FTS1
  if( !db->mallocFailed ){
    extern int sqlite3Fts1Init(sqlite3*);
    rc = sqlite3Fts1Init(db);
  }
#endif

Changes to src/test_multiplex.c.

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
...
457
458
459
460
461
462
463

464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502



503
504
505
506
507
508
509
...
514
515
516
517
518
519
520
521
522
523

524
525
526
527
528
529
530
...
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827

828
829
830



831

832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
....
1187
1188
1189
1190
1191
1192
1193

1194
1195
1196



1197
1198
1199
1200
1201
1202
1203
static int multiplexStrlen30(const char *z){
  const char *z2 = z;
  if( z==0 ) return 0;
  while( *z2 ){ z2++; }
  return 0x3fffffff & (int)(z2 - z);
}

/*
** Create a temporary file name in zBuf.  zBuf must be big enough to
** hold at pOrigVfs->mxPathname characters.  This function departs
** from the traditional temporary name generation in the os_win
** and os_unix VFS in several ways, but is necessary so that 
** the file name is known for temporary files (like those used 
** during vacuum.)
**
** N.B. This routine assumes your underlying VFS is ok with using
** "/" as a directory seperator.  This is the default for UNIXs
** and is allowed (even mixed) for most versions of Windows.
*/
static int multiplexGetTempname(sqlite3_vfs *pOrigVfs, int nBuf, char *zBuf){
  static char zChars[] =
    "abcdefghijklmnopqrstuvwxyz"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "0123456789";
  int i,j;
  int attempts = 0;
  int exists = 0;
  int rc = SQLITE_ERROR;

  /* Check that the output buffer is large enough for 
  ** pVfs->mxPathname characters.
  */
  if( pOrigVfs->mxPathname <= nBuf ){
    char *zTmp = sqlite3_malloc(pOrigVfs->mxPathname);
    if( zTmp==0 ) return SQLITE_NOMEM;

    /* sqlite3_temp_directory should always be less than
    ** pVfs->mxPathname characters.
    */
    sqlite3_snprintf(pOrigVfs->mxPathname,
                     zTmp,
                     "%s/",
                     sqlite3_temp_directory ? sqlite3_temp_directory : ".");
    rc = pOrigVfs->xFullPathname(pOrigVfs, zTmp, nBuf, zBuf);
    sqlite3_free(zTmp);
    if( rc ) return rc;

    /* Check that the output buffer is large enough for the temporary file 
    ** name.
    */
    j = multiplexStrlen30(zBuf);
    if( (j + 8 + 1 + 3 + 1) <= nBuf ){
      /* Make 3 attempts to generate a unique name. */
      do {
        attempts++;
        sqlite3_randomness(8, &zBuf[j]);
        for(i=0; i<8; i++){
          unsigned char uc = (unsigned char)zBuf[j+i];
          zBuf[j+i] = (char)zChars[uc%(sizeof(zChars)-1)];
        }
        memcpy(&zBuf[j+i], ".tmp", 5);
        rc = pOrigVfs->xAccess(pOrigVfs, zBuf, SQLITE_ACCESS_EXISTS, &exists);
      } while ( (rc==SQLITE_OK) && exists && (attempts<3) );
      if( rc==SQLITE_OK && exists ){
        rc = SQLITE_ERROR;
      }
    }
  }

  return rc;
}

/* Compute the filename for the iChunk-th chunk
*/
static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
  if( iChunk>=pGroup->nReal ){
    struct multiplexReal *p;
    p = sqlite3_realloc(pGroup->aReal, (iChunk+1)*sizeof(*p));
    if( p==0 ){
      return SQLITE_NOMEM;
    }
    memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal));
    pGroup->aReal = p;
    pGroup->nReal = iChunk+1;
  }
  if( pGroup->aReal[iChunk].z==0 ){
    char *z;
    int n = pGroup->nName;
    pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+4 );
    if( z==0 ){
      return SQLITE_NOMEM;
    }
    memcpy(z, pGroup->zName, n+1);
................................................................................
  sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
  int nName;
  int sz;
  char *zToFree = 0;

  UNUSED_PARAMETER(pVfs);
  memset(pConn, 0, pVfs->szOsFile);


  /* We need to create a group structure and manage
  ** access to this group of files.
  */
  multiplexEnter();
  pMultiplexOpen = (multiplexConn*)pConn;

  /* If the second argument to this function is NULL, generate a 
  ** temporary file name to use.  This will be handled by the
  ** original xOpen method.  We just need to allocate space for
  ** it.
  */
  if( !zName ){
    zName = zToFree = sqlite3_malloc( pOrigVfs->mxPathname + 10 );
    if( zName==0 ){
      rc = SQLITE_NOMEM;
    }else{
      rc = multiplexGetTempname(pOrigVfs, pOrigVfs->mxPathname, zToFree);
    }
  }

  if( rc==SQLITE_OK ){
    /* allocate space for group */
    nName = multiplexStrlen30(zName);
    sz = sizeof(multiplexGroup)                             /* multiplexGroup */
       + nName + 1;                                         /* zName */
    pGroup = sqlite3_malloc( sz );
    if( pGroup==0 ){
      rc = SQLITE_NOMEM;
    }
  }

  if( rc==SQLITE_OK ){
    /* assign pointers to extra space allocated */
    char *p = (char *)&pGroup[1];
    pMultiplexOpen->pGroup = pGroup;
    memset(pGroup, 0, sz);
    pGroup->bEnabled = -1;
    pGroup->szChunk = SQLITE_MULTIPLEX_CHUNK_SIZE;



    if( flags & SQLITE_OPEN_URI ){
      const char *zChunkSize;
      zChunkSize = sqlite3_uri_parameter(zName, "chunksize");
      if( zChunkSize ){
        unsigned int n = 0;
        int i;
        for(i=0; zChunkSize[i]>='0' && zChunkSize[i]<='9'; i++){
................................................................................
        }else{
          /* A zero or negative chunksize disabled the multiplexor */
          pGroup->bEnabled = 0;
        }
      }
    }
    pGroup->zName = p;
    /* save off base filename, name length, and original open flags  */
    memcpy(pGroup->zName, zName, nName+1);
    pGroup->nName = nName;

    pGroup->flags = flags;
    rc = multiplexSubFilename(pGroup, 1);
    if( rc==SQLITE_OK ){
      pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags);
    }
    if( pSubOpen ){
      int exists, rc2, rc3;
................................................................................
/* Pass xFileSize requests through to the original VFS.
** Aggregate the size of all the chunks before returning.
*/
static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
  multiplexConn *p = (multiplexConn*)pConn;
  multiplexGroup *pGroup = p->pGroup;
  int rc = SQLITE_OK;
  int rc2;
  int i;
  multiplexEnter();
  if( !pGroup->bEnabled ){
    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
    if( pSubOpen==0 ){
      rc = SQLITE_IOERR_FSTAT;
    }else{
      rc = pSubOpen->pMethods->xFileSize(pSubOpen, pSize);
    }
  }else{
    sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;
    *pSize = 0;
    for(i=0; 1; i++){
      sqlite3_file *pSubOpen = 0;
      int exists = 0;
      rc = multiplexSubFilename(pGroup, i);
      if( rc ) break;
      if( pGroup->flags & SQLITE_OPEN_DELETEONCLOSE ){
        exists = pGroup->nReal>=i && pGroup->aReal[i].p!=0;
        rc2 = SQLITE_OK;
      }else{
        rc2 = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[i].z,
            SQLITE_ACCESS_EXISTS, &exists);
      }
      if( rc2==SQLITE_OK && exists){
        /* if it exists, open it */
        pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
      }else{

        /* stop at first "gap" */
        break;
      }



      if( pSubOpen ){

        sqlite3_int64 sz;
        rc2 = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);
        if( rc2!=SQLITE_OK ){
          rc = rc2;
        }else{
          if( sz>pGroup->szChunk ){
            rc = SQLITE_IOERR_FSTAT;
          }
          *pSize += sz;
        }
      }else{
        break;
      }
    }
  }
  multiplexLeave();
  return rc;
}

/* Pass xLock requests through to the original VFS unchanged.
................................................................................
  UNUSED_PARAMETER(objv);

  pResult = Tcl_NewObj();
  multiplexEnter();
  for(pGroup=gMultiplex.pGroups; pGroup; pGroup=pGroup->pNext){
    pGroupTerm = Tcl_NewObj();


    pGroup->zName[pGroup->nName] = '\0';
    Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewStringObj(pGroup->zName, -1));



    Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewIntObj(pGroup->nName));
    Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewIntObj(pGroup->flags));

    /* count number of chunks with open handles */
    for(i=0; i<pGroup->nReal; i++){







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<













|







 







>







<
<
<
<
<
<
<
<
<
<
<
<
<
<


|










|

<


>
>
>







 







<
|
|
>







 







<












|



|
|
|
|
<
|
|

<
<
<
<
>
|


>
>
>
|
>
|
|
<
<
<
|




<
<
<







 







>



>
>
>







209
210
211
212
213
214
215

































































216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
...
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406














407
408
409
410
411
412
413
414
415
416
417
418
419
420
421

422
423
424
425
426
427
428
429
430
431
432
433
...
438
439
440
441
442
443
444

445
446
447
448
449
450
451
452
453
454
...
716
717
718
719
720
721
722

723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742

743
744
745




746
747
748
749
750
751
752
753
754
755
756



757
758
759
760
761



762
763
764
765
766
767
768
....
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
static int multiplexStrlen30(const char *z){
  const char *z2 = z;
  if( z==0 ) return 0;
  while( *z2 ){ z2++; }
  return 0x3fffffff & (int)(z2 - z);
}


































































/* Compute the filename for the iChunk-th chunk
*/
static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){
  if( iChunk>=pGroup->nReal ){
    struct multiplexReal *p;
    p = sqlite3_realloc(pGroup->aReal, (iChunk+1)*sizeof(*p));
    if( p==0 ){
      return SQLITE_NOMEM;
    }
    memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal));
    pGroup->aReal = p;
    pGroup->nReal = iChunk+1;
  }
  if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){
    char *z;
    int n = pGroup->nName;
    pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+4 );
    if( z==0 ){
      return SQLITE_NOMEM;
    }
    memcpy(z, pGroup->zName, n+1);
................................................................................
  sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;   /* Real VFS */
  int nName;
  int sz;
  char *zToFree = 0;

  UNUSED_PARAMETER(pVfs);
  memset(pConn, 0, pVfs->szOsFile);
  assert( zName || (flags & SQLITE_OPEN_DELETEONCLOSE) );

  /* We need to create a group structure and manage
  ** access to this group of files.
  */
  multiplexEnter();
  pMultiplexOpen = (multiplexConn*)pConn;















  if( rc==SQLITE_OK ){
    /* allocate space for group */
    nName = zName ? multiplexStrlen30(zName) : 0;
    sz = sizeof(multiplexGroup)                             /* multiplexGroup */
       + nName + 1;                                         /* zName */
    pGroup = sqlite3_malloc( sz );
    if( pGroup==0 ){
      rc = SQLITE_NOMEM;
    }
  }

  if( rc==SQLITE_OK ){
    /* assign pointers to extra space allocated */
    memset(pGroup, 0, sz);
    pMultiplexOpen->pGroup = pGroup;

    pGroup->bEnabled = -1;
    pGroup->szChunk = SQLITE_MULTIPLEX_CHUNK_SIZE;

    if( zName ){
      char *p = (char *)&pGroup[1];
      if( flags & SQLITE_OPEN_URI ){
        const char *zChunkSize;
        zChunkSize = sqlite3_uri_parameter(zName, "chunksize");
        if( zChunkSize ){
          unsigned int n = 0;
          int i;
          for(i=0; zChunkSize[i]>='0' && zChunkSize[i]<='9'; i++){
................................................................................
          }else{
            /* A zero or negative chunksize disabled the multiplexor */
            pGroup->bEnabled = 0;
          }
        }
      }
      pGroup->zName = p;

      memcpy(pGroup->zName, zName, nName+1);
      pGroup->nName = nName;
    }
    pGroup->flags = flags;
    rc = multiplexSubFilename(pGroup, 1);
    if( rc==SQLITE_OK ){
      pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags);
    }
    if( pSubOpen ){
      int exists, rc2, rc3;
................................................................................
/* Pass xFileSize requests through to the original VFS.
** Aggregate the size of all the chunks before returning.
*/
static int multiplexFileSize(sqlite3_file *pConn, sqlite3_int64 *pSize){
  multiplexConn *p = (multiplexConn*)pConn;
  multiplexGroup *pGroup = p->pGroup;
  int rc = SQLITE_OK;

  int i;
  multiplexEnter();
  if( !pGroup->bEnabled ){
    sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL);
    if( pSubOpen==0 ){
      rc = SQLITE_IOERR_FSTAT;
    }else{
      rc = pSubOpen->pMethods->xFileSize(pSubOpen, pSize);
    }
  }else{
    sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs;
    *pSize = 0;
    for(i=0; rc==SQLITE_OK; i++){
      sqlite3_file *pSubOpen = 0;
      int exists = 0;
      rc = multiplexSubFilename(pGroup, i);
      if( rc!=SQLITE_OK ) break;
      if( pGroup->nReal>i && pGroup->aReal[i].p!=0 ){
        exists = 1;
      }else if( (pGroup->flags & SQLITE_OPEN_DELETEONCLOSE)==0 ){

        const char *zReal = pGroup->aReal[i].z;
        rc = pOrigVfs->xAccess(pOrigVfs, zReal, SQLITE_ACCESS_EXISTS, &exists);
      }




      if( exists==0 ){
        /* stop at first "gap" or IO error. */
        break;
      }
      if( rc==SQLITE_OK ){
        pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL);
      }
      assert( pSubOpen || rc!=SQLITE_OK );
      if( rc==SQLITE_OK ){
        sqlite3_int64 sz = 0;
        rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz);



        if( rc==SQLITE_OK && sz>pGroup->szChunk ){
          rc = SQLITE_IOERR_FSTAT;
        }
        *pSize += sz;
      }



    }
  }
  multiplexLeave();
  return rc;
}

/* Pass xLock requests through to the original VFS unchanged.
................................................................................
  UNUSED_PARAMETER(objv);

  pResult = Tcl_NewObj();
  multiplexEnter();
  for(pGroup=gMultiplex.pGroups; pGroup; pGroup=pGroup->pNext){
    pGroupTerm = Tcl_NewObj();

    if( pGroup->zName ){
      pGroup->zName[pGroup->nName] = '\0';
      Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewStringObj(pGroup->zName, -1));
    }else{
      Tcl_ListObjAppendElement(interp, pGroupTerm, Tcl_NewObj());
    }
    Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewIntObj(pGroup->nName));
    Tcl_ListObjAppendElement(interp, pGroupTerm,
          Tcl_NewIntObj(pGroup->flags));

    /* count number of chunks with open handles */
    for(i=0; i<pGroup->nReal; i++){

Changes to test/multiplex.test.

9
10
11
12
13
14
15










16
17
18
19
20
21
22
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl











set g_chunk_size [ expr ($::SQLITE_MAX_PAGE_SIZE*16384) ]
set g_max_chunks 32

# This handles appending the chunk number
# to the end of the filename.  if 
# SQLITE_MULTIPLEX_EXT_OVWR is defined, then







>
>
>
>
>
>
>
>
>
>







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#
#***********************************************************************
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl

# The tests in this file assume that SQLite is compiled without
# ENABLE_8_3_NAMES.
#
ifcapable 8_3_names {
  puts -nonewline "SQLite compiled with SQLITE_ENABLE_8_3_NAMES. "
  puts            "Skipping tests multiplex-*."
  finish_test
  return
}

set g_chunk_size [ expr ($::SQLITE_MAX_PAGE_SIZE*16384) ]
set g_max_chunks 32

# This handles appending the chunk number
# to the end of the filename.  if 
# SQLITE_MULTIPLEX_EXT_OVWR is defined, then

Added test/multiplex3.test.





































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98

# 2011 December 13
#
# 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.
#
#***********************************************************************
#
# This file contains tests for error (IO, OOM etc.) handling when using
# the multiplexor extension with 8.3 filenames.
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set ::testprefix multiplex3

ifcapable !8_3_names {
  puts -nonewline "SQLite compiled without SQLITE_ENABLE_8_3_NAMES. "
  puts            "Skipping tests multiplex3-*."
  finish_test
  return
}

db close
sqlite3_shutdown
sqlite3_config_uri 1
autoinstall_test_functions

sqlite3_multiplex_initialize "" 1

proc destroy_vfs_stack {} {
  generic_unregister stack
  sqlite3_multiplex_shutdown
}

proc multiplex_delete_db {} {
  forcedelete test.db
  for {set i 1} {$i <= 1000} {incr i} {
    forcedelete test.[format %03d $i]
  }
}

# Procs to save and restore the current muliplexed database.
#
proc multiplex_save_db {} {
  foreach f [glob -nocomplain sv_test.*] { forcedelete $f }
  foreach f [glob -nocomplain test.*]    { forcecopy $f "sv_$f" }
}
proc multiplex_restore_db {} {
  foreach f [glob -nocomplain test.*]    {forcedelete $f}
  foreach f [glob -nocomplain sv_test.*] {forcecopy $f [string range $f 3 end]} }


do_test 1.0 {
  multiplex_delete_db
  sqlite3 db file:test.db?8_3_names=1
  sqlite3_multiplex_control db main chunk_size [expr 256*1024]
  execsql {
    CREATE TABLE t1(a PRIMARY KEY, b);
    INSERT INTO t1 VALUES(randomblob(15), randomblob(2000));
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --   2
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --   4
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --   8
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --  16
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --  32
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    --  64
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    -- 128
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    -- 256
    INSERT INTO t1 SELECT randomblob(15), randomblob(2000) FROM t1;    -- 512
  }
  set ::cksum1 [execsql {SELECT md5sum(a, b) FROM t1 ORDER BY a}]
  db close
  multiplex_save_db
} {}

do_faultsim_test 1 -prep {
  multiplex_restore_db
  sqlite3 db file:test.db?8_3_names=1
  sqlite3_multiplex_control db main chunk_size [expr 256*1024]
} -body {
  execsql "UPDATE t1 SET a=randomblob(12), b=randomblob(1500) WHERE (rowid%32)=0"
} -test {
  faultsim_test_result {0 {}}
  if {$testrc!=0} {
    set cksum2 [execsql {SELECT md5sum(a, b) FROM t1 ORDER BY a}]
    if {$cksum2 != $::cksum1} { error "data mismatch" }
  }
}

catch { db close }

sqlite3_multiplex_shutdown
finish_test