| OLD | NEW |
| 1 /* | 1 /* |
| 2 ** 2010 October 28 | 2 ** 2010 October 28 |
| 3 ** | 3 ** |
| 4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
| 5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
| 6 ** | 6 ** |
| 7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
| 8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
| 9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
| 10 ** | 10 ** |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 ** for version 2. | 182 ** for version 2. |
| 183 */ | 183 */ |
| 184 sqlite3_io_methods sIoMethodsV1; | 184 sqlite3_io_methods sIoMethodsV1; |
| 185 sqlite3_io_methods sIoMethodsV2; | 185 sqlite3_io_methods sIoMethodsV2; |
| 186 | 186 |
| 187 /* True when this shim has been initialized. | 187 /* True when this shim has been initialized. |
| 188 */ | 188 */ |
| 189 int isInitialized; | 189 int isInitialized; |
| 190 | 190 |
| 191 /* For run-time access any of the other global data structures in this | 191 /* For run-time access any of the other global data structures in this |
| 192 ** shim, the following mutex must be held. | 192 ** shim, the following mutex must be held. In practice, all this mutex |
| 193 */ | 193 ** protects is add/remove operations to/from the linked list of group objects |
| 194 ** starting at pGroups below. More specifically, it protects the value of |
| 195 ** pGroups itself, and the pNext/pPrev fields of each multiplexGroup |
| 196 ** structure. */ |
| 194 sqlite3_mutex *pMutex; | 197 sqlite3_mutex *pMutex; |
| 195 | 198 |
| 196 /* List of multiplexGroup objects. | 199 /* List of multiplexGroup objects. |
| 197 */ | 200 */ |
| 198 multiplexGroup *pGroups; | 201 multiplexGroup *pGroups; |
| 199 } gMultiplex; | 202 } gMultiplex; |
| 200 | 203 |
| 201 /************************* Utility Routines *********************************/ | 204 /************************* Utility Routines *********************************/ |
| 202 /* | 205 /* |
| 203 ** Acquire and release the mutex used to serialize access to the | 206 ** Acquire and release the mutex used to serialize access to the |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 | 282 |
| 280 assert( zOut[n]=='\0' ); | 283 assert( zOut[n]=='\0' ); |
| 281 zOut[n+1] = '\0'; | 284 zOut[n+1] = '\0'; |
| 282 } | 285 } |
| 283 | 286 |
| 284 /* Compute the filename for the iChunk-th chunk | 287 /* Compute the filename for the iChunk-th chunk |
| 285 */ | 288 */ |
| 286 static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){ | 289 static int multiplexSubFilename(multiplexGroup *pGroup, int iChunk){ |
| 287 if( iChunk>=pGroup->nReal ){ | 290 if( iChunk>=pGroup->nReal ){ |
| 288 struct multiplexReal *p; | 291 struct multiplexReal *p; |
| 289 p = sqlite3_realloc(pGroup->aReal, (iChunk+1)*sizeof(*p)); | 292 p = sqlite3_realloc64(pGroup->aReal, (iChunk+1)*sizeof(*p)); |
| 290 if( p==0 ){ | 293 if( p==0 ){ |
| 291 return SQLITE_NOMEM; | 294 return SQLITE_NOMEM; |
| 292 } | 295 } |
| 293 memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal)); | 296 memset(&p[pGroup->nReal], 0, sizeof(p[0])*(iChunk+1-pGroup->nReal)); |
| 294 pGroup->aReal = p; | 297 pGroup->aReal = p; |
| 295 pGroup->nReal = iChunk+1; | 298 pGroup->nReal = iChunk+1; |
| 296 } | 299 } |
| 297 if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){ | 300 if( pGroup->zName && pGroup->aReal[iChunk].z==0 ){ |
| 298 char *z; | 301 char *z; |
| 299 int n = pGroup->nName; | 302 int n = pGroup->nName; |
| 300 pGroup->aReal[iChunk].z = z = sqlite3_malloc( n+5 ); | 303 pGroup->aReal[iChunk].z = z = sqlite3_malloc64( n+5 ); |
| 301 if( z==0 ){ | 304 if( z==0 ){ |
| 302 return SQLITE_NOMEM; | 305 return SQLITE_NOMEM; |
| 303 } | 306 } |
| 304 multiplexFilename(pGroup->zName, pGroup->nName, pGroup->flags, iChunk, z); | 307 multiplexFilename(pGroup->zName, pGroup->nName, pGroup->flags, iChunk, z); |
| 305 } | 308 } |
| 306 return SQLITE_OK; | 309 return SQLITE_OK; |
| 307 } | 310 } |
| 308 | 311 |
| 309 /* Translate an sqlite3_file* that is really a multiplexGroup* into | 312 /* Translate an sqlite3_file* that is really a multiplexGroup* into |
| 310 ** the sqlite3_file* for the underlying original VFS. | 313 ** the sqlite3_file* for the underlying original VFS. |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 SQLITE_ACCESS_EXISTS, &bExists); | 353 SQLITE_ACCESS_EXISTS, &bExists); |
| 351 if( *rc || !bExists ){ | 354 if( *rc || !bExists ){ |
| 352 if( *rc ){ | 355 if( *rc ){ |
| 353 sqlite3_log(*rc, "multiplexor.xAccess failure on %s", | 356 sqlite3_log(*rc, "multiplexor.xAccess failure on %s", |
| 354 pGroup->aReal[iChunk].z); | 357 pGroup->aReal[iChunk].z); |
| 355 } | 358 } |
| 356 return 0; | 359 return 0; |
| 357 } | 360 } |
| 358 flags &= ~SQLITE_OPEN_CREATE; | 361 flags &= ~SQLITE_OPEN_CREATE; |
| 359 } | 362 } |
| 360 pSubOpen = sqlite3_malloc( pOrigVfs->szOsFile ); | 363 pSubOpen = sqlite3_malloc64( pOrigVfs->szOsFile ); |
| 361 if( pSubOpen==0 ){ | 364 if( pSubOpen==0 ){ |
| 362 *rc = SQLITE_IOERR_NOMEM; | 365 *rc = SQLITE_IOERR_NOMEM; |
| 363 return 0; | 366 return 0; |
| 364 } | 367 } |
| 365 pGroup->aReal[iChunk].p = pSubOpen; | 368 pGroup->aReal[iChunk].p = pSubOpen; |
| 366 *rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen, | 369 *rc = pOrigVfs->xOpen(pOrigVfs, pGroup->aReal[iChunk].z, pSubOpen, |
| 367 flags, pOutFlags); | 370 flags, pOutFlags); |
| 368 if( (*rc)!=SQLITE_OK ){ | 371 if( (*rc)!=SQLITE_OK ){ |
| 369 sqlite3_log(*rc, "multiplexor.xOpen failure on %s", | 372 sqlite3_log(*rc, "multiplexor.xOpen failure on %s", |
| 370 pGroup->aReal[iChunk].z); | 373 pGroup->aReal[iChunk].z); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 399 /* | 402 /* |
| 400 ** This is the implementation of the multiplex_control() SQL function. | 403 ** This is the implementation of the multiplex_control() SQL function. |
| 401 */ | 404 */ |
| 402 static void multiplexControlFunc( | 405 static void multiplexControlFunc( |
| 403 sqlite3_context *context, | 406 sqlite3_context *context, |
| 404 int argc, | 407 int argc, |
| 405 sqlite3_value **argv | 408 sqlite3_value **argv |
| 406 ){ | 409 ){ |
| 407 int rc = SQLITE_OK; | 410 int rc = SQLITE_OK; |
| 408 sqlite3 *db = sqlite3_context_db_handle(context); | 411 sqlite3 *db = sqlite3_context_db_handle(context); |
| 409 int op; | 412 int op = 0; |
| 410 int iVal; | 413 int iVal; |
| 411 | 414 |
| 412 if( !db || argc!=2 ){ | 415 if( !db || argc!=2 ){ |
| 413 rc = SQLITE_ERROR; | 416 rc = SQLITE_ERROR; |
| 414 }else{ | 417 }else{ |
| 415 /* extract params */ | 418 /* extract params */ |
| 416 op = sqlite3_value_int(argv[0]); | 419 op = sqlite3_value_int(argv[0]); |
| 417 iVal = sqlite3_value_int(argv[1]); | 420 iVal = sqlite3_value_int(argv[1]); |
| 418 /* map function op to file_control op */ | 421 /* map function op to file_control op */ |
| 419 switch( op ){ | 422 switch( op ){ |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 ** access to this group of files. | 520 ** access to this group of files. |
| 518 */ | 521 */ |
| 519 multiplexEnter(); | 522 multiplexEnter(); |
| 520 pMultiplexOpen = (multiplexConn*)pConn; | 523 pMultiplexOpen = (multiplexConn*)pConn; |
| 521 | 524 |
| 522 if( rc==SQLITE_OK ){ | 525 if( rc==SQLITE_OK ){ |
| 523 /* allocate space for group */ | 526 /* allocate space for group */ |
| 524 nName = zName ? multiplexStrlen30(zName) : 0; | 527 nName = zName ? multiplexStrlen30(zName) : 0; |
| 525 sz = sizeof(multiplexGroup) /* multiplexGroup */ | 528 sz = sizeof(multiplexGroup) /* multiplexGroup */ |
| 526 + nName + 1; /* zName */ | 529 + nName + 1; /* zName */ |
| 527 pGroup = sqlite3_malloc( sz ); | 530 pGroup = sqlite3_malloc64( sz ); |
| 528 if( pGroup==0 ){ | 531 if( pGroup==0 ){ |
| 529 rc = SQLITE_NOMEM; | 532 rc = SQLITE_NOMEM; |
| 530 } | 533 } |
| 531 } | 534 } |
| 532 | 535 |
| 533 if( rc==SQLITE_OK ){ | 536 if( rc==SQLITE_OK ){ |
| 534 const char *zUri = (flags & SQLITE_OPEN_URI) ? zName : 0; | 537 const char *zUri = (flags & SQLITE_OPEN_URI) ? zName : 0; |
| 535 /* assign pointers to extra space allocated */ | 538 /* assign pointers to extra space allocated */ |
| 536 memset(pGroup, 0, sz); | 539 memset(pGroup, 0, sz); |
| 537 pMultiplexOpen->pGroup = pGroup; | 540 pMultiplexOpen->pGroup = pGroup; |
| 538 pGroup->bEnabled = -1; | 541 pGroup->bEnabled = (unsigned char)-1; |
| 539 pGroup->bTruncate = sqlite3_uri_boolean(zUri, "truncate", | 542 pGroup->bTruncate = sqlite3_uri_boolean(zUri, "truncate", |
| 540 (flags & SQLITE_OPEN_MAIN_DB)==0); | 543 (flags & SQLITE_OPEN_MAIN_DB)==0); |
| 541 pGroup->szChunk = (int)sqlite3_uri_int64(zUri, "chunksize", | 544 pGroup->szChunk = (int)sqlite3_uri_int64(zUri, "chunksize", |
| 542 SQLITE_MULTIPLEX_CHUNK_SIZE); | 545 SQLITE_MULTIPLEX_CHUNK_SIZE); |
| 543 pGroup->szChunk = (pGroup->szChunk+0xffff)&~0xffff; | 546 pGroup->szChunk = (pGroup->szChunk+0xffff)&~0xffff; |
| 544 if( zName ){ | 547 if( zName ){ |
| 545 char *p = (char *)&pGroup[1]; | 548 char *p = (char *)&pGroup[1]; |
| 546 pGroup->zName = p; | 549 pGroup->zName = p; |
| 547 memcpy(pGroup->zName, zName, nName+1); | 550 memcpy(pGroup->zName, zName, nName+1); |
| 548 pGroup->nName = nName; | 551 pGroup->nName = nName; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 561 pGroup->szChunk += 65536; | 564 pGroup->szChunk += 65536; |
| 562 } | 565 } |
| 563 } | 566 } |
| 564 pGroup->flags = flags; | 567 pGroup->flags = flags; |
| 565 rc = multiplexSubFilename(pGroup, 1); | 568 rc = multiplexSubFilename(pGroup, 1); |
| 566 if( rc==SQLITE_OK ){ | 569 if( rc==SQLITE_OK ){ |
| 567 pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags, 0); | 570 pSubOpen = multiplexSubOpen(pGroup, 0, &rc, pOutFlags, 0); |
| 568 if( pSubOpen==0 && rc==SQLITE_OK ) rc = SQLITE_CANTOPEN; | 571 if( pSubOpen==0 && rc==SQLITE_OK ) rc = SQLITE_CANTOPEN; |
| 569 } | 572 } |
| 570 if( rc==SQLITE_OK ){ | 573 if( rc==SQLITE_OK ){ |
| 571 sqlite3_int64 sz; | 574 sqlite3_int64 sz64; |
| 572 | 575 |
| 573 rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz); | 576 rc = pSubOpen->pMethods->xFileSize(pSubOpen, &sz64); |
| 574 if( rc==SQLITE_OK && zName ){ | 577 if( rc==SQLITE_OK && zName ){ |
| 575 int bExists; | 578 int bExists; |
| 576 if( sz==0 ){ | 579 if( flags & SQLITE_OPEN_MASTER_JOURNAL ){ |
| 580 pGroup->bEnabled = 0; |
| 581 }else |
| 582 if( sz64==0 ){ |
| 577 if( flags & SQLITE_OPEN_MAIN_JOURNAL ){ | 583 if( flags & SQLITE_OPEN_MAIN_JOURNAL ){ |
| 578 /* If opening a main journal file and the first chunk is zero | 584 /* If opening a main journal file and the first chunk is zero |
| 579 ** bytes in size, delete any subsequent chunks from the | 585 ** bytes in size, delete any subsequent chunks from the |
| 580 ** file-system. */ | 586 ** file-system. */ |
| 581 int iChunk = 1; | 587 int iChunk = 1; |
| 582 do { | 588 do { |
| 583 rc = pOrigVfs->xAccess(pOrigVfs, | 589 rc = pOrigVfs->xAccess(pOrigVfs, |
| 584 pGroup->aReal[iChunk].z, SQLITE_ACCESS_EXISTS, &bExists | 590 pGroup->aReal[iChunk].z, SQLITE_ACCESS_EXISTS, &bExists |
| 585 ); | 591 ); |
| 586 if( rc==SQLITE_OK && bExists ){ | 592 if( rc==SQLITE_OK && bExists ){ |
| (...skipping 10 matching lines...) Expand all Loading... |
| 597 ** set incorrectly. So fix it. | 603 ** set incorrectly. So fix it. |
| 598 ** | 604 ** |
| 599 ** Or, if the first overflow file does not exist and the main file is | 605 ** Or, if the first overflow file does not exist and the main file is |
| 600 ** larger than the chunk size, that means the chunk size is too small. | 606 ** larger than the chunk size, that means the chunk size is too small. |
| 601 ** But we have no way of determining the intended chunk size, so | 607 ** But we have no way of determining the intended chunk size, so |
| 602 ** just disable the multiplexor all togethre. | 608 ** just disable the multiplexor all togethre. |
| 603 */ | 609 */ |
| 604 rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z, | 610 rc = pOrigVfs->xAccess(pOrigVfs, pGroup->aReal[1].z, |
| 605 SQLITE_ACCESS_EXISTS, &bExists); | 611 SQLITE_ACCESS_EXISTS, &bExists); |
| 606 bExists = multiplexSubSize(pGroup, 1, &rc)>0; | 612 bExists = multiplexSubSize(pGroup, 1, &rc)>0; |
| 607 if( rc==SQLITE_OK && bExists && sz==(sz&0xffff0000) && sz>0 | 613 if( rc==SQLITE_OK && bExists && sz64==(sz64&0xffff0000) && sz64>0 |
| 608 && sz!=pGroup->szChunk ){ | 614 && sz64!=pGroup->szChunk ){ |
| 609 pGroup->szChunk = (int)sz; | 615 pGroup->szChunk = (int)sz64; |
| 610 }else if( rc==SQLITE_OK && !bExists && sz>pGroup->szChunk ){ | 616 }else if( rc==SQLITE_OK && !bExists && sz64>pGroup->szChunk ){ |
| 611 pGroup->bEnabled = 0; | 617 pGroup->bEnabled = 0; |
| 612 } | 618 } |
| 613 } | 619 } |
| 614 } | 620 } |
| 615 } | 621 } |
| 616 | 622 |
| 617 if( rc==SQLITE_OK ){ | 623 if( rc==SQLITE_OK ){ |
| 618 if( pSubOpen->pMethods->iVersion==1 ){ | 624 if( pSubOpen->pMethods->iVersion==1 ){ |
| 619 pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1; | 625 pMultiplexOpen->base.pMethods = &gMultiplex.sIoMethodsV1; |
| 620 }else{ | 626 }else{ |
| (...skipping 24 matching lines...) Expand all Loading... |
| 645 ){ | 651 ){ |
| 646 int rc; | 652 int rc; |
| 647 sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ | 653 sqlite3_vfs *pOrigVfs = gMultiplex.pOrigVfs; /* Real VFS */ |
| 648 rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir); | 654 rc = pOrigVfs->xDelete(pOrigVfs, zName, syncDir); |
| 649 if( rc==SQLITE_OK ){ | 655 if( rc==SQLITE_OK ){ |
| 650 /* If the main chunk was deleted successfully, also delete any subsequent | 656 /* If the main chunk was deleted successfully, also delete any subsequent |
| 651 ** chunks - starting with the last (highest numbered). | 657 ** chunks - starting with the last (highest numbered). |
| 652 */ | 658 */ |
| 653 int nName = (int)strlen(zName); | 659 int nName = (int)strlen(zName); |
| 654 char *z; | 660 char *z; |
| 655 z = sqlite3_malloc(nName + 5); | 661 z = sqlite3_malloc64(nName + 5); |
| 656 if( z==0 ){ | 662 if( z==0 ){ |
| 657 rc = SQLITE_IOERR_NOMEM; | 663 rc = SQLITE_IOERR_NOMEM; |
| 658 }else{ | 664 }else{ |
| 659 int iChunk = 0; | 665 int iChunk = 0; |
| 660 int bExists; | 666 int bExists; |
| 661 do{ | 667 do{ |
| 662 multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, ++iChunk, z); | 668 multiplexFilename(zName, nName, SQLITE_OPEN_MAIN_JOURNAL, ++iChunk, z); |
| 663 rc = pOrigVfs->xAccess(pOrigVfs, z, SQLITE_ACCESS_EXISTS, &bExists); | 669 rc = pOrigVfs->xAccess(pOrigVfs, z, SQLITE_ACCESS_EXISTS, &bExists); |
| 664 }while( rc==SQLITE_OK && bExists ); | 670 }while( rc==SQLITE_OK && bExists ); |
| 665 while( rc==SQLITE_OK && iChunk>1 ){ | 671 while( rc==SQLITE_OK && iChunk>1 ){ |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 748 */ | 754 */ |
| 749 static int multiplexRead( | 755 static int multiplexRead( |
| 750 sqlite3_file *pConn, | 756 sqlite3_file *pConn, |
| 751 void *pBuf, | 757 void *pBuf, |
| 752 int iAmt, | 758 int iAmt, |
| 753 sqlite3_int64 iOfst | 759 sqlite3_int64 iOfst |
| 754 ){ | 760 ){ |
| 755 multiplexConn *p = (multiplexConn*)pConn; | 761 multiplexConn *p = (multiplexConn*)pConn; |
| 756 multiplexGroup *pGroup = p->pGroup; | 762 multiplexGroup *pGroup = p->pGroup; |
| 757 int rc = SQLITE_OK; | 763 int rc = SQLITE_OK; |
| 758 int nMutex = 0; | |
| 759 multiplexEnter(); nMutex++; | |
| 760 if( !pGroup->bEnabled ){ | 764 if( !pGroup->bEnabled ){ |
| 761 sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0); | 765 sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0); |
| 762 multiplexLeave(); nMutex--; | |
| 763 if( pSubOpen==0 ){ | 766 if( pSubOpen==0 ){ |
| 764 rc = SQLITE_IOERR_READ; | 767 rc = SQLITE_IOERR_READ; |
| 765 }else{ | 768 }else{ |
| 766 rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst); | 769 rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, iOfst); |
| 767 } | 770 } |
| 768 }else{ | 771 }else{ |
| 769 while( iAmt > 0 ){ | 772 while( iAmt > 0 ){ |
| 770 int i = (int)(iOfst / pGroup->szChunk); | 773 int i = (int)(iOfst / pGroup->szChunk); |
| 771 sqlite3_file *pSubOpen; | 774 sqlite3_file *pSubOpen; |
| 772 if( nMutex==0 ){ multiplexEnter(); nMutex++; } | |
| 773 pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1); | 775 pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1); |
| 774 multiplexLeave(); nMutex--; | |
| 775 if( pSubOpen ){ | 776 if( pSubOpen ){ |
| 776 int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - pGroup->szChunk; | 777 int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - pGroup->szChunk; |
| 777 if( extra<0 ) extra = 0; | 778 if( extra<0 ) extra = 0; |
| 778 iAmt -= extra; | 779 iAmt -= extra; |
| 779 rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, | 780 rc = pSubOpen->pMethods->xRead(pSubOpen, pBuf, iAmt, |
| 780 iOfst % pGroup->szChunk); | 781 iOfst % pGroup->szChunk); |
| 781 if( rc!=SQLITE_OK ) break; | 782 if( rc!=SQLITE_OK ) break; |
| 782 pBuf = (char *)pBuf + iAmt; | 783 pBuf = (char *)pBuf + iAmt; |
| 783 iOfst += iAmt; | 784 iOfst += iAmt; |
| 784 iAmt = extra; | 785 iAmt = extra; |
| 785 }else{ | 786 }else{ |
| 786 rc = SQLITE_IOERR_READ; | 787 rc = SQLITE_IOERR_READ; |
| 787 break; | 788 break; |
| 788 } | 789 } |
| 789 } | 790 } |
| 790 } | 791 } |
| 791 assert( nMutex==0 || nMutex==1 ); | 792 |
| 792 if( nMutex ) multiplexLeave(); | |
| 793 return rc; | 793 return rc; |
| 794 } | 794 } |
| 795 | 795 |
| 796 /* Pass xWrite requests thru to the original VFS after | 796 /* Pass xWrite requests thru to the original VFS after |
| 797 ** determining the correct chunk to operate on. | 797 ** determining the correct chunk to operate on. |
| 798 ** Break up writes across chunk boundaries. | 798 ** Break up writes across chunk boundaries. |
| 799 */ | 799 */ |
| 800 static int multiplexWrite( | 800 static int multiplexWrite( |
| 801 sqlite3_file *pConn, | 801 sqlite3_file *pConn, |
| 802 const void *pBuf, | 802 const void *pBuf, |
| 803 int iAmt, | 803 int iAmt, |
| 804 sqlite3_int64 iOfst | 804 sqlite3_int64 iOfst |
| 805 ){ | 805 ){ |
| 806 multiplexConn *p = (multiplexConn*)pConn; | 806 multiplexConn *p = (multiplexConn*)pConn; |
| 807 multiplexGroup *pGroup = p->pGroup; | 807 multiplexGroup *pGroup = p->pGroup; |
| 808 int rc = SQLITE_OK; | 808 int rc = SQLITE_OK; |
| 809 multiplexEnter(); | |
| 810 if( !pGroup->bEnabled ){ | 809 if( !pGroup->bEnabled ){ |
| 811 sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0); | 810 sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0); |
| 812 if( pSubOpen==0 ){ | 811 if( pSubOpen==0 ){ |
| 813 rc = SQLITE_IOERR_WRITE; | 812 rc = SQLITE_IOERR_WRITE; |
| 814 }else{ | 813 }else{ |
| 815 rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst); | 814 rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, iOfst); |
| 816 } | 815 } |
| 817 }else{ | 816 }else{ |
| 818 while( rc==SQLITE_OK && iAmt>0 ){ | 817 while( rc==SQLITE_OK && iAmt>0 ){ |
| 819 int i = (int)(iOfst / pGroup->szChunk); | 818 int i = (int)(iOfst / pGroup->szChunk); |
| 820 sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1); | 819 sqlite3_file *pSubOpen = multiplexSubOpen(pGroup, i, &rc, NULL, 1); |
| 821 if( pSubOpen ){ | 820 if( pSubOpen ){ |
| 822 int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - | 821 int extra = ((int)(iOfst % pGroup->szChunk) + iAmt) - |
| 823 pGroup->szChunk; | 822 pGroup->szChunk; |
| 824 if( extra<0 ) extra = 0; | 823 if( extra<0 ) extra = 0; |
| 825 iAmt -= extra; | 824 iAmt -= extra; |
| 826 rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, | 825 rc = pSubOpen->pMethods->xWrite(pSubOpen, pBuf, iAmt, |
| 827 iOfst % pGroup->szChunk); | 826 iOfst % pGroup->szChunk); |
| 828 pBuf = (char *)pBuf + iAmt; | 827 pBuf = (char *)pBuf + iAmt; |
| 829 iOfst += iAmt; | 828 iOfst += iAmt; |
| 830 iAmt = extra; | 829 iAmt = extra; |
| 831 } | 830 } |
| 832 } | 831 } |
| 833 } | 832 } |
| 834 multiplexLeave(); | |
| 835 return rc; | 833 return rc; |
| 836 } | 834 } |
| 837 | 835 |
| 838 /* Pass xTruncate requests thru to the original VFS after | 836 /* Pass xTruncate requests thru to the original VFS after |
| 839 ** determining the correct chunk to operate on. Delete any | 837 ** determining the correct chunk to operate on. Delete any |
| 840 ** chunks above the truncate mark. | 838 ** chunks above the truncate mark. |
| 841 */ | 839 */ |
| 842 static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){ | 840 static int multiplexTruncate(sqlite3_file *pConn, sqlite3_int64 size){ |
| 843 multiplexConn *p = (multiplexConn*)pConn; | 841 multiplexConn *p = (multiplexConn*)pConn; |
| 844 multiplexGroup *pGroup = p->pGroup; | 842 multiplexGroup *pGroup = p->pGroup; |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 997 case MULTIPLEX_CTRL_SET_MAX_CHUNKS: | 995 case MULTIPLEX_CTRL_SET_MAX_CHUNKS: |
| 998 rc = SQLITE_OK; | 996 rc = SQLITE_OK; |
| 999 break; | 997 break; |
| 1000 case SQLITE_FCNTL_SIZE_HINT: | 998 case SQLITE_FCNTL_SIZE_HINT: |
| 1001 case SQLITE_FCNTL_CHUNK_SIZE: | 999 case SQLITE_FCNTL_CHUNK_SIZE: |
| 1002 /* no-op these */ | 1000 /* no-op these */ |
| 1003 rc = SQLITE_OK; | 1001 rc = SQLITE_OK; |
| 1004 break; | 1002 break; |
| 1005 case SQLITE_FCNTL_PRAGMA: { | 1003 case SQLITE_FCNTL_PRAGMA: { |
| 1006 char **aFcntl = (char**)pArg; | 1004 char **aFcntl = (char**)pArg; |
| 1005 /* |
| 1006 ** EVIDENCE-OF: R-29875-31678 The argument to the SQLITE_FCNTL_PRAGMA |
| 1007 ** file control is an array of pointers to strings (char**) in which the |
| 1008 ** second element of the array is the name of the pragma and the third |
| 1009 ** element is the argument to the pragma or NULL if the pragma has no |
| 1010 ** argument. |
| 1011 */ |
| 1007 if( aFcntl[1] && sqlite3_stricmp(aFcntl[1],"multiplex_truncate")==0 ){ | 1012 if( aFcntl[1] && sqlite3_stricmp(aFcntl[1],"multiplex_truncate")==0 ){ |
| 1008 if( aFcntl[2] && aFcntl[2][0] ){ | 1013 if( aFcntl[2] && aFcntl[2][0] ){ |
| 1009 if( sqlite3_stricmp(aFcntl[2], "on")==0 | 1014 if( sqlite3_stricmp(aFcntl[2], "on")==0 |
| 1010 || sqlite3_stricmp(aFcntl[2], "1")==0 ){ | 1015 || sqlite3_stricmp(aFcntl[2], "1")==0 ){ |
| 1011 pGroup->bTruncate = 1; | 1016 pGroup->bTruncate = 1; |
| 1012 }else | 1017 }else |
| 1013 if( sqlite3_stricmp(aFcntl[2], "off")==0 | 1018 if( sqlite3_stricmp(aFcntl[2], "off")==0 |
| 1014 || sqlite3_stricmp(aFcntl[2], "0")==0 ){ | 1019 || sqlite3_stricmp(aFcntl[2], "0")==0 ){ |
| 1015 pGroup->bTruncate = 0; | 1020 pGroup->bTruncate = 0; |
| 1016 } | 1021 } |
| 1017 } | 1022 } |
| 1023 /* EVIDENCE-OF: R-27806-26076 The handler for an SQLITE_FCNTL_PRAGMA |
| 1024 ** file control can optionally make the first element of the char** |
| 1025 ** argument point to a string obtained from sqlite3_mprintf() or the |
| 1026 ** equivalent and that string will become the result of the pragma |
| 1027 ** or the error message if the pragma fails. |
| 1028 */ |
| 1018 aFcntl[0] = sqlite3_mprintf(pGroup->bTruncate ? "on" : "off"); | 1029 aFcntl[0] = sqlite3_mprintf(pGroup->bTruncate ? "on" : "off"); |
| 1019 rc = SQLITE_OK; | 1030 rc = SQLITE_OK; |
| 1020 break; | 1031 break; |
| 1021 } | 1032 } |
| 1022 /* If the multiplexor does not handle the pragma, pass it through | 1033 /* If the multiplexor does not handle the pragma, pass it through |
| 1023 ** into the default case. */ | 1034 ** into the default case. */ |
| 1024 } | 1035 } |
| 1025 default: | 1036 default: |
| 1026 pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0); | 1037 pSubOpen = multiplexSubOpen(pGroup, 0, &rc, NULL, 0); |
| 1027 if( pSubOpen ){ | 1038 if( pSubOpen ){ |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1411 }; | 1422 }; |
| 1412 int i; | 1423 int i; |
| 1413 | 1424 |
| 1414 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ | 1425 for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){ |
| 1415 Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); | 1426 Tcl_CreateObjCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); |
| 1416 } | 1427 } |
| 1417 | 1428 |
| 1418 return TCL_OK; | 1429 return TCL_OK; |
| 1419 } | 1430 } |
| 1420 #endif | 1431 #endif |
| OLD | NEW |