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 |