Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Make the OsFile structure opaque with its internal structure known only to the appropriate os_*.c implementation. Omit the os_unix.h and os_win.h include files. The crash tests are broken by this patch. (CVS 2791) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
058f31753871b16b40fe4048e3adcee4 |
User & Date: | drh 2005-11-29 03:13:21.000 |
Context
2005-11-29
| ||
18:37 | The crash tests now compile, at least. But they get wrong results. The problem is fundamental and suggests I need to completely rethink how the new OS backend should work. (CVS 2792) (check-in: 966bc68e1b user: drh tags: trunk) | |
03:13 | Make the OsFile structure opaque with its internal structure known only to the appropriate os_*.c implementation. Omit the os_unix.h and os_win.h include files. The crash tests are broken by this patch. (CVS 2791) (check-in: 058f317538 user: drh tags: trunk) | |
2005-11-28
| ||
12:36 | Replace a call to sprintf() with sqlite3MPrintf() since on some embedded platforms, sprintf() is busted. Need to go through and do similar replacements elsewhere in the code. (CVS 2790) (check-in: 1b4f2d89bb user: drh tags: trunk) | |
Changes
Changes to Makefile.in.
︙ | ︙ | |||
201 202 203 204 205 206 207 | HDR = \ sqlite3.h \ $(TOP)/src/btree.h \ $(TOP)/src/hash.h \ opcodes.h \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ | < < | 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | HDR = \ sqlite3.h \ $(TOP)/src/btree.h \ $(TOP)/src/hash.h \ opcodes.h \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ $(TOP)/src/sqliteInt.h \ $(TOP)/src/vdbe.h \ parse.h # Header files used by the VDBE submodule # VDBEHDR = \ |
︙ | ︙ |
Changes to main.mk.
︙ | ︙ | |||
143 144 145 146 147 148 149 | HDR = \ sqlite3.h \ $(TOP)/src/btree.h \ $(TOP)/src/hash.h \ opcodes.h \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ | < < | 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | HDR = \ sqlite3.h \ $(TOP)/src/btree.h \ $(TOP)/src/hash.h \ opcodes.h \ $(TOP)/src/os.h \ $(TOP)/src/os_common.h \ $(TOP)/src/sqliteInt.h \ $(TOP)/src/vdbe.h \ parse.h # Header files used by the VDBE submodule # VDBEHDR = \ |
︙ | ︙ |
Changes to src/expr.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** ** $Id: expr.c,v 1.240 2005/11/29 03:13:22 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** Return the 'affinity' of the expression pExpr if any. ** |
︙ | ︙ | |||
1270 1271 1272 1273 1274 1275 1276 | struct QueryCoder { Parse *pParse; /* The parsing context */ NameContext *pNC; /* Namespace of first enclosing query */ }; /* | | < | | | > | | < | | 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 | struct QueryCoder { Parse *pParse; /* The parsing context */ NameContext *pNC; /* Namespace of first enclosing query */ }; /* ** Generate code for scalar subqueries used as an expression ** and IN operators. Examples: ** ** (SELECT a FROM b) -- subquery ** EXISTS (SELECT a FROM b) -- EXISTS subquery ** x IN (4,5,11) -- IN operator with list on right-hand side ** x IN (SELECT a FROM b) -- IN operator with subquery on the right ** ** The pExpr parameter describes the expression that contains the IN ** operator or subquery. */ #ifndef SQLITE_OMIT_SUBQUERY void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ int testAddr = 0; /* One-time test address */ Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; |
︙ | ︙ |
Changes to src/os.h.
︙ | ︙ | |||
39 40 41 42 43 44 45 | #else # ifndef OS_WIN # define OS_WIN 0 # endif #endif /* | | | < < < < < < < < < < < > > | < > > > | 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 | #else # ifndef OS_WIN # define OS_WIN 0 # endif #endif /* ** The OsFile object describes an open disk file in an OS-dependent way. */ typedef struct OsFile OsFile; /* ** Define the maximum size of a temporary filename */ #if OS_WIN # define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) #else # define SQLITE_TEMPNAME_SIZE 200 #endif /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op */ #ifndef SET_FULLSYNC # define SET_FULLSYNC(x,y) |
︙ | ︙ | |||
175 176 177 178 179 180 181 | /* ** A single global instance of the following structure holds pointers to the ** various disk I/O routines. */ extern struct sqlite3IoVtbl { int (*xDelete)(const char*); int (*xFileExists)(const char*); | | | | | > > | | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | /* ** A single global instance of the following structure holds pointers to the ** various disk I/O routines. */ extern struct sqlite3IoVtbl { int (*xDelete)(const char*); int (*xFileExists)(const char*); int (*xOpenReadWrite)(const char*, OsFile**, int*); int (*xOpenExclusive)(const char*, OsFile**, int); int (*xOpenReadOnly)(const char*, OsFile**); int (*xOpenDirectory)(const char*, OsFile*); int (*xSyncDirectory)(const char*); int (*xTempFileName)(char*); int (*xIsDirWritable)(char*); int (*xClose)(OsFile**); int (*xRead)(OsFile*, void*, int amt); int (*xWrite)(OsFile*, const void*, int amt); int (*xSeek)(OsFile*, i64 offset); int (*xSync)(OsFile*, int); int (*xTruncate)(OsFile*, i64 size); int (*xFileSize)(OsFile*, i64 *pSize); char *(*xFullPathname)(const char*); int (*xLock)(OsFile*, int); int (*xUnlock)(OsFile*, int); int (*xCheckReservedLock)(OsFile *id); void (*xSetFullSync)(OsFile *id, int setting); int (*xFileHandle)(OsFile *id); int (*xLockState)(OsFile *id); } sqlite3Io; /* The interface for file I/O is above. Other miscellaneous functions ** are below */ int sqlite3OsRandomSeed(char*); int sqlite3OsSleep(int ms); int sqlite3OsCurrentTime(double*); void sqlite3OsEnterMutex(void); void sqlite3OsLeaveMutex(void); #endif /* _SQLITE_OS_H_ */ |
Changes to src/os_unix.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ****************************************************************************** ** ** This file contains code that is specific to Unix systems. */ #include "sqliteInt.h" #include "os.h" #if OS_UNIX /* This file is used on unix only */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 99 100 | ****************************************************************************** ** ** This file contains code that is specific to Unix systems. */ #include "sqliteInt.h" #include "os.h" #if OS_UNIX /* This file is used on unix only */ /* ** These #defines should enable >2GB file support on Posix if the ** underlying operating system supports it. If the OS lacks ** large file support, or if the OS is windows, these should be no-ops. ** ** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch ** on the compiler command line. This is necessary if you are compiling ** on a recent machine (ex: RedHat 7.2) but you want your code to work ** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2 ** without this option, LFS is enable. But LFS does not exist in the kernel ** in RedHat 6.0, so the code won't work. Hence, for maximum binary ** portability you should omit LFS. ** ** Similar is true for MacOS. LFS is only supported on MacOS 9 and later. */ #ifndef SQLITE_DISABLE_LFS # define _LARGE_FILE 1 # ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 # endif # define _LARGEFILE_SOURCE 1 #endif /* ** standard include files. */ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <time.h> #include <sys/time.h> #include <errno.h> /* ** Macros used to determine whether or not to use threads. The ** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for ** Posix threads and SQLITE_W32_THREADS is defined if we are ** synchronizing using Win32 threads. */ #if defined(THREADSAFE) && THREADSAFE # include <pthread.h> # define SQLITE_UNIX_THREADS 1 #endif /* ** Default permissions when creating a new file */ #ifndef SQLITE_DEFAULT_FILE_PERMISSIONS # define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 #endif /* ** The OsFile structure is a operating-system dependent representation ** of an open file handle. It is defined differently for each architecture. ** ** This is the definition for Unix. ** ** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK, ** PENDING_LOCK or EXCLUSIVE_LOCK. */ struct OsFile { struct openCnt *pOpen; /* Info about all open fd's on this inode */ struct lockInfo *pLock; /* Info about locks on this inode */ int h; /* The file descriptor */ unsigned char locktype; /* The type of lock held on this fd */ unsigned char isOpen; /* True if needs to be closed */ unsigned char fullSync; /* Use F_FULLSYNC if available */ int dirfd; /* File descriptor for the directory */ #ifdef SQLITE_UNIX_THREADS pthread_t tid; /* The thread authorized to use this OsFile */ #endif }; /* ** Do not include any of the File I/O interface procedures if the ** SQLITE_OMIT_DISKIO macro is defined (indicating that there database ** will be in-memory only) */ #ifndef SQLITE_OMIT_DISKIO |
︙ | ︙ | |||
78 79 80 81 82 83 84 | ** same thread is operating on the OsFile. Some operating systems do ** not allow locks to be overridden by other threads and that restriction ** means that sqlite3* database handles cannot be moved from one thread ** to another. This logic makes sure a user does not try to do that ** by mistake. */ #if defined(SQLITE_UNIX_THREADS) && !defined(SQLITE_ALLOW_XTHREAD_CONNECTIONS) | | | | 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | ** same thread is operating on the OsFile. Some operating systems do ** not allow locks to be overridden by other threads and that restriction ** means that sqlite3* database handles cannot be moved from one thread ** to another. This logic makes sure a user does not try to do that ** by mistake. */ #if defined(SQLITE_UNIX_THREADS) && !defined(SQLITE_ALLOW_XTHREAD_CONNECTIONS) # define SET_THREADID(X) (X)->tid = pthread_self() # define CHECK_THREADID(X) (!pthread_equal((X)->tid, pthread_self())) #else # define SET_THREADID(X) # define CHECK_THREADID(X) 0 #endif /* ** Here is the dirt on POSIX advisory locks: ANSI STD 1003.1 (1996) |
︙ | ︙ | |||
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 | /* ** Return TRUE if the named file exists. */ static int unixFileExists(const char *zFilename){ return access(zFilename, 0)==0; } /* ** Attempt to open a file for both reading and writing. If that ** fails, try opening it read-only. If the file does not exist, ** try to create it. ** ** On success, a handle for the open file is written to *id ** and *pReadonly is set to 0 if the file was opened for reading and ** writing or 1 if the file was opened read-only. The function returns ** SQLITE_OK. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id and *pReadonly unchanged. */ static int unixOpenReadWrite( const char *zFilename, | > > > > > > > > > > > > > > > > | > > | | | | | | | | | | < | > > > > | | > | > > | | | | | | | | < | > > > > | | > | > > | | | | | | | | < | > > > > | | > | | | 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 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 | /* ** Return TRUE if the named file exists. */ static int unixFileExists(const char *zFilename){ return access(zFilename, 0)==0; } /* ** Allocate memory for an OsFile. Initialize the new OsFile ** to the value given in pInit and return a pointer to the new ** OsFile. If we run out of memory, close the file and return NULL. */ static OsFile *allocateOsFile(OsFile *pInit){ OsFile *pNew; pNew = sqliteMalloc( sizeof(OsFile) ); if( pNew==0 ){ close(pInit->h); }else{ *pNew = *pInit; } return pNew; } /* ** Attempt to open a file for both reading and writing. If that ** fails, try opening it read-only. If the file does not exist, ** try to create it. ** ** On success, a handle for the open file is written to *id ** and *pReadonly is set to 0 if the file was opened for reading and ** writing or 1 if the file was opened read-only. The function returns ** SQLITE_OK. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id and *pReadonly unchanged. */ static int unixOpenReadWrite( const char *zFilename, OsFile **pId, int *pReadonly ){ int rc; OsFile f; assert( 0==*pId ); f.dirfd = -1; SET_THREADID(&f); f.h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, SQLITE_DEFAULT_FILE_PERMISSIONS); if( f.h<0 ){ #ifdef EISDIR if( errno==EISDIR ){ return SQLITE_CANTOPEN; } #endif f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); if( f.h<0 ){ return SQLITE_CANTOPEN; } *pReadonly = 1; }else{ *pReadonly = 0; } sqlite3OsEnterMutex(); rc = findLockInfo(f.h, &f.pLock, &f.pOpen); sqlite3OsLeaveMutex(); if( rc ){ close(f.h); return SQLITE_NOMEM; } f.locktype = 0; TRACE3("OPEN %-3d %s\n", f.h, zFilename); *pId = allocateOsFile(&f); if( *pId==0 ){ return SQLITE_NOMEM; }else{ OpenCounter(+1); return SQLITE_OK; } } /* ** Attempt to open a new file for exclusive access by this process. ** The file will be opened for both reading and writing. To avoid ** a potential security problem, we do not allow the file to have ** previously existed. Nor do we allow the file to be a symbolic ** link. ** ** If delFlag is true, then make arrangements to automatically delete ** the file when it is closed. ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ static int unixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ int rc; OsFile f; assert( 0==*pId ); if( access(zFilename, 0)==0 ){ return SQLITE_CANTOPEN; } SET_THREADID(&f); f.dirfd = -1; f.h = open(zFilename, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, SQLITE_DEFAULT_FILE_PERMISSIONS); if( f.h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); rc = findLockInfo(f.h, &f.pLock, &f.pOpen); sqlite3OsLeaveMutex(); if( rc ){ close(f.h); unlink(zFilename); return SQLITE_NOMEM; } f.locktype = 0; if( delFlag ){ unlink(zFilename); } TRACE3("OPEN-EX %-3d %s\n", f.h, zFilename); *pId = allocateOsFile(&f); if( *pId==0 ){ return SQLITE_NOMEM; }else{ OpenCounter(+1); return SQLITE_OK; } } /* ** Attempt to open a new file for read-only access. ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ static int unixOpenReadOnly(const char *zFilename, OsFile **pId){ int rc; OsFile f; assert( 0==*pId ); SET_THREADID(&f); f.dirfd = -1; f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); if( f.h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); rc = findLockInfo(f.h, &f.pLock, &f.pOpen); sqlite3OsLeaveMutex(); if( rc ){ close(f.h); return SQLITE_NOMEM; } f.locktype = 0; TRACE3("OPEN-RO %-3d %s\n", f.h, zFilename); *pId = allocateOsFile(&f); if( *pId==0 ){ return SQLITE_NOMEM; }else{ OpenCounter(+1); return SQLITE_OK; } } /* ** Attempt to open a file descriptor for the directory that contains a ** file. This file descriptor can be used to fsync() the directory ** in order to make sure the creation of a new file is actually written ** to disk. ** ** This routine is only meaningful for Unix. It is a no-op under ** windows since windows does not support hard links. ** ** On success, a handle for a previously open file at *id is ** updated with the new directory file descriptor and SQLITE_OK is ** returned. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id unchanged. */ static int unixOpenDirectory( const char *zDirname, OsFile *id ){ if( id==0 ){ /* Do not open the directory if the corresponding file is not already ** open. */ return SQLITE_CANTOPEN; } SET_THREADID(id); assert( id->dirfd<0 ); id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0); |
︙ | ︙ | |||
723 724 725 726 727 728 729 | /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ static int unixRead(OsFile *id, void *pBuf, int amt){ int got; | | | | 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 852 853 854 855 856 857 858 859 860 861 862 | /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ static int unixRead(OsFile *id, void *pBuf, int amt){ int got; assert( id ); SimulateIOError(SQLITE_IOERR); TIMER_START; got = read(id->h, pBuf, amt); TIMER_END; TRACE5("READ %-3d %5d %7d %d\n", id->h, got, last_page, TIMER_ELAPSED); SEEK(0); /* if( got<0 ) got = 0; */ if( got==amt ){ return SQLITE_OK; }else{ return SQLITE_IOERR; } } /* ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ static int unixWrite(OsFile *id, const void *pBuf, int amt){ int wrote = 0; assert( id ); assert( amt>0 ); SimulateIOError(SQLITE_IOERR); SimulateDiskfullError; TIMER_START; while( amt>0 && (wrote = write(id->h, pBuf, amt))>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; |
︙ | ︙ | |||
766 767 768 769 770 771 772 | return SQLITE_OK; } /* ** Move the read/write pointer in a file. */ static int unixSeek(OsFile *id, i64 offset){ | | | 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 | return SQLITE_OK; } /* ** Move the read/write pointer in a file. */ static int unixSeek(OsFile *id, i64 offset){ assert( id ); SEEK(offset/1024 + 1); #ifdef SQLITE_TEST if( offset ) SimulateDiskfullError #endif lseek(id->h, offset, SEEK_SET); return SQLITE_OK; } |
︙ | ︙ | |||
860 861 862 863 864 865 866 | ** If we do not do this and we encounter a power failure, the directory ** entry for the journal might not exist after we reboot. The next ** SQLite to access the file will not know that the journal exists (because ** the directory entry for the journal was never created) and the transaction ** will not roll back - possibly leading to database corruption. */ static int unixSync(OsFile *id, int dataOnly){ | | | 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 | ** If we do not do this and we encounter a power failure, the directory ** entry for the journal might not exist after we reboot. The next ** SQLite to access the file will not know that the journal exists (because ** the directory entry for the journal was never created) and the transaction ** will not roll back - possibly leading to database corruption. */ static int unixSync(OsFile *id, int dataOnly){ assert( id ); SimulateIOError(SQLITE_IOERR); TRACE2("SYNC %-3d\n", id->h); if( full_fsync(id->h, id->fullSync, dataOnly) ){ return SQLITE_IOERR; } if( id->dirfd>=0 ){ TRACE2("DIRSYNC %-3d\n", id->dirfd); |
︙ | ︙ | |||
909 910 911 912 913 914 915 | #endif } /* ** Truncate an open file to a specified size */ static int unixTruncate(OsFile *id, i64 nByte){ | | | | | 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 | #endif } /* ** Truncate an open file to a specified size */ static int unixTruncate(OsFile *id, i64 nByte){ assert( id ); SimulateIOError(SQLITE_IOERR); return ftruncate(id->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR; } /* ** Determine the current size of a file in bytes */ static int unixFileSize(OsFile *id, i64 *pSize){ struct stat buf; assert( id ); SimulateIOError(SQLITE_IOERR); if( fstat(id->h, &buf)!=0 ){ return SQLITE_IOERR; } *pSize = buf.st_size; return SQLITE_OK; } /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, return ** non-zero. If the file is unlocked or holds only SHARED locks, then ** return zero. */ static int unixCheckReservedLock(OsFile *id){ int r = 0; assert( id ); if( CHECK_THREADID(id) ) return SQLITE_MISUSE; sqlite3OsEnterMutex(); /* Needed because id->pLock is shared across threads */ /* Check if a thread in this process holds such a lock */ if( id->pLock->locktype>SHARED_LOCK ){ r = 1; } |
︙ | ︙ | |||
1052 1053 1054 1055 1056 1057 1058 | ** even if the locking primitive used is always a write-lock. */ int rc = SQLITE_OK; struct lockInfo *pLock = id->pLock; struct flock lock; int s; | | | 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 | ** even if the locking primitive used is always a write-lock. */ int rc = SQLITE_OK; struct lockInfo *pLock = id->pLock; struct flock lock; int s; assert( id ); TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype), locktypeName(id->locktype), locktypeName(pLock->locktype), pLock->cnt ,getpid() ); if( CHECK_THREADID(id) ) return SQLITE_MISUSE; /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as |
︙ | ︙ | |||
1209 1210 1211 1212 1213 1214 1215 | ** might return SQLITE_IOERR instead of SQLITE_OK. */ static int unixUnlock(OsFile *id, int locktype){ struct lockInfo *pLock; struct flock lock; int rc = SQLITE_OK; | | | 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 | ** might return SQLITE_IOERR instead of SQLITE_OK. */ static int unixUnlock(OsFile *id, int locktype){ struct lockInfo *pLock; struct flock lock; int rc = SQLITE_OK; assert( id ); TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype, id->pLock->locktype, id->pLock->cnt, getpid()); if( CHECK_THREADID(id) ) return SQLITE_MISUSE; assert( locktype<=SHARED_LOCK ); if( id->locktype<=locktype ){ return SQLITE_OK; |
︙ | ︙ | |||
1287 1288 1289 1290 1291 1292 1293 | id->locktype = locktype; return rc; } /* ** Close a file. */ | | > | | 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 | id->locktype = locktype; return rc; } /* ** Close a file. */ static int unixClose(OsFile **pId){ OsFile *id = *pId; if( !id ) return SQLITE_OK; if( CHECK_THREADID(id) ) return SQLITE_MISUSE; sqlite3Io.xUnlock(id, NO_LOCK); if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1; sqlite3OsEnterMutex(); if( id->pOpen->nLock ){ /* If there are outstanding locks, do not actually close the file just |
︙ | ︙ | |||
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 | } releaseLockInfo(id->pLock); releaseOpenCnt(id->pOpen); sqlite3OsLeaveMutex(); id->isOpen = 0; TRACE2("CLOSE %-3d\n", id->h); OpenCounter(-1); return SQLITE_OK; } /* ** Turn a relative pathname into a full pathname. Return a pointer ** to the full pathname stored in space obtained from sqliteMalloc(). ** The calling function is responsible for freeing this space once it | > > | 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 | } releaseLockInfo(id->pLock); releaseOpenCnt(id->pOpen); sqlite3OsLeaveMutex(); id->isOpen = 0; TRACE2("CLOSE %-3d\n", id->h); OpenCounter(-1); sqliteFree(id); *pId = 0; return SQLITE_OK; } /* ** Turn a relative pathname into a full pathname. Return a pointer ** to the full pathname stored in space obtained from sqliteMalloc(). ** The calling function is responsible for freeing this space once it |
︙ | ︙ | |||
1347 1348 1349 1350 1351 1352 1353 | (char*)0); sqliteFree(zBuf); } return zFull; } /* | > > > > > | > > | > > | > > > > > > | 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 | (char*)0); sqliteFree(zBuf); } return zFull; } /* ** Change the value of the fullsync flag in the given file descriptor. */ static void unixSetFullSync(OsFile *id, int v){ id->fullSync = v; } /* ** Return the underlying file handle for an OsFile */ static int unixFileHandle(OsFile *id){ return id->h; } /* ** Return an integer that indices the type of lock currently held ** by this handle. (Used for testing and analysis only.) */ static int unixLockState(OsFile *id){ return id->locktype; } /* ** This is the structure that defines all of the I/O routines. */ struct sqlite3IoVtbl sqlite3Io = { unixDelete, |
︙ | ︙ | |||
1377 1378 1379 1380 1381 1382 1383 | unixSync, unixTruncate, unixFileSize, unixFullPathname, unixLock, unixUnlock, unixCheckReservedLock, | > > | | 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 | unixSync, unixTruncate, unixFileSize, unixFullPathname, unixLock, unixUnlock, unixCheckReservedLock, unixSetFullSync, unixFileHandle, unixLockState, }; #endif /* SQLITE_OMIT_DISKIO */ /*************************************************************************** ** Everything above deals with file I/O. Everything that follows deals ** with other miscellanous aspects of the operating system interface |
︙ | ︙ |
Changes to src/os_win.c.
︙ | ︙ | |||
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 | ** ** This file contains code that is specific to windows. */ #include "sqliteInt.h" #include "os.h" #if OS_WIN /* This file is used for windows only */ #include <winbase.h> #ifdef __CYGWIN__ # include <sys/cygwin.h> #endif /* ** Macros used to determine whether or not to use threads. */ #if defined(THREADSAFE) && THREADSAFE # define SQLITE_W32_THREADS 1 #endif /* ** Include code that is common to all os_*.c files */ #include "os_common.h" /* ** Do not include any of the File I/O interface procedures if the ** SQLITE_OMIT_DISKIO macro is defined (indicating that there database ** will be in-memory only) */ #ifndef SQLITE_OMIT_DISKIO | > > > > > > > > > > > > > > > | 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 | ** ** This file contains code that is specific to windows. */ #include "sqliteInt.h" #include "os.h" #if OS_WIN /* This file is used for windows only */ #include <windows.h> #include <winbase.h> #ifdef __CYGWIN__ # include <sys/cygwin.h> #endif /* ** Macros used to determine whether or not to use threads. */ #if defined(THREADSAFE) && THREADSAFE # define SQLITE_W32_THREADS 1 #endif /* ** Include code that is common to all os_*.c files */ #include "os_common.h" /* ** The OsFile structure is a operating-system independing representation ** of an open file handle. It is defined differently for each architecture. ** ** This is the definition for Win32. */ struct OsFile { HANDLE h; /* Handle for accessing the file */ unsigned char locktype; /* Type of lock currently held on this file */ short sharedLockByte; /* Randomly chosen byte used as a shared lock */ }; /* ** Do not include any of the File I/O interface procedures if the ** SQLITE_OMIT_DISKIO macro is defined (indicating that there database ** will be in-memory only) */ #ifndef SQLITE_OMIT_DISKIO |
︙ | ︙ | |||
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | sqliteFree(zWide); }else{ exists = GetFileAttributesA(zFilename) != 0xffffffff; } return exists; } /* ** Attempt to open a file for both reading and writing. If that ** fails, try opening it read-only. If the file does not exist, ** try to create it. ** ** On success, a handle for the open file is written to *id ** and *pReadonly is set to 0 if the file was opened for reading and ** writing or 1 if the file was opened read-only. The function returns ** SQLITE_OK. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id and *pReadonly unchanged. */ static int winOpenReadWrite( const char *zFilename, | > > > > > > > > > > > > > > > > > | > | | 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | sqliteFree(zWide); }else{ exists = GetFileAttributesA(zFilename) != 0xffffffff; } return exists; } /* ** Allocate memory for an OsFile. Initialize the new OsFile ** to the value given in pInit and return a pointer to the new ** OsFile. If we run out of memory, close the file and return NULL. */ static OsFile *allocateOsFile(OsFile *pInit){ OsFile *pNew; pNew = sqliteMalloc( sizeof(OsFile) ); if( pNew==0 ){ CloseHandle(pInit->h); }else{ *pNew = *pInit; } return pNew; } /* ** Attempt to open a file for both reading and writing. If that ** fails, try opening it read-only. If the file does not exist, ** try to create it. ** ** On success, a handle for the open file is written to *id ** and *pReadonly is set to 0 if the file was opened for reading and ** writing or 1 if the file was opened read-only. The function returns ** SQLITE_OK. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id and *pReadonly unchanged. */ static int winOpenReadWrite( const char *zFilename, OsFile **pId, int *pReadonly ){ OsFile f; HANDLE h; WCHAR *zWide = utf8ToUnicode(zFilename); assert( *pId==0 ); if( zWide ){ h = CreateFileW(zWide, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, |
︙ | ︙ | |||
223 224 225 226 227 228 229 | return SQLITE_CANTOPEN; } *pReadonly = 1; }else{ *pReadonly = 0; } } | | | | > | > > > | < | > | > | | 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 302 303 | return SQLITE_CANTOPEN; } *pReadonly = 1; }else{ *pReadonly = 0; } } f.h = h; f.locktype = NO_LOCK; f.sharedLockByte = 0; TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename); *pId = allocateOsFile(&f); if( *pId==0 ){ return SQLITE_NOMEM; }else{ OpenCounter(+1); return SQLITE_OK; } } /* ** Attempt to open a new file for exclusive access by this process. ** The file will be opened for both reading and writing. To avoid ** a potential security problem, we do not allow the file to have ** previously existed. Nor do we allow the file to be a symbolic ** link. ** ** If delFlag is true, then make arrangements to automatically delete ** the file when it is closed. ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ static int winOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ OsFile f; HANDLE h; int fileflags; WCHAR *zWide = utf8ToUnicode(zFilename); assert( *pId == 0 ); if( delFlag ){ fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_DELETE_ON_CLOSE; }else{ fileflags = FILE_FLAG_RANDOM_ACCESS; } if( zWide ){ |
︙ | ︙ | |||
281 282 283 284 285 286 287 | fileflags, NULL ); } if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } | | | | > | > > > | < | > | > | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 | fileflags, NULL ); } if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } f.h = h; f.locktype = NO_LOCK; f.sharedLockByte = 0; TRACE3("OPEN EX %d \"%s\"\n", h, zFilename); *pId = allocateOsFile(&f); if( *pId==0 ){ return SQLITE_NOMEM; }else{ OpenCounter(+1); return SQLITE_OK; } } /* ** Attempt to open a new file for read-only access. ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ static int winOpenReadOnly(const char *zFilename, OsFile **pId){ OsFile f; HANDLE h; WCHAR *zWide = utf8ToUnicode(zFilename); assert( *pId==0 ); if( zWide ){ h = CreateFileW(zWide, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, |
︙ | ︙ | |||
324 325 326 327 328 329 330 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL ); } if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } | | | | > | > > > | < | > | 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL ); } if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } f.h = h; f.locktype = NO_LOCK; f.sharedLockByte = 0; TRACE3("OPEN RO %d \"%s\"\n", h, zFilename); *pId = allocateOsFile(&f); if( *pId==0 ){ return SQLITE_NOMEM; }else{ OpenCounter(+1); return SQLITE_OK; } } /* ** Attempt to open a file descriptor for the directory that contains a ** file. This file descriptor can be used to fsync() the directory ** in order to make sure the creation of a new file is actually written ** to disk. |
︙ | ︙ | |||
409 410 411 412 413 414 415 | TRACE2("TEMP FILENAME: %s\n", zBuf); return SQLITE_OK; } /* ** Close a file. */ | | | | | > | | | | 456 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 | TRACE2("TEMP FILENAME: %s\n", zBuf); return SQLITE_OK; } /* ** Close a file. */ static int winClose(OsFile **pId){ if( *pId ){ TRACE2("CLOSE %d\n", (*pId)->h); CloseHandle((*pId)->h); OpenCounter(-1); sqliteFree(*pId); *pId = 0; } return SQLITE_OK; } /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ static int winRead(OsFile *id, void *pBuf, int amt){ DWORD got; assert( id!=0 ); SimulateIOError(SQLITE_IOERR); TRACE3("READ %d lock=%d\n", id->h, id->locktype); if( !ReadFile(id->h, pBuf, amt, &got, 0) ){ got = 0; } if( got==(DWORD)amt ){ return SQLITE_OK; }else{ return SQLITE_IOERR; } } /* ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ static int winWrite(OsFile *id, const void *pBuf, int amt){ int rc = 0; DWORD wrote; assert( id!=0 ); SimulateIOError(SQLITE_IOERR); SimulateDiskfullError; TRACE3("WRITE %d lock=%d\n", id->h, id->locktype); assert( amt>0 ); while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; |
︙ | ︙ | |||
475 476 477 478 479 480 481 | /* ** Move the read/write pointer in a file. */ static int winSeek(OsFile *id, i64 offset){ LONG upperBits = offset>>32; LONG lowerBits = offset & 0xffffffff; DWORD rc; | | | | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | /* ** Move the read/write pointer in a file. */ static int winSeek(OsFile *id, i64 offset){ LONG upperBits = offset>>32; LONG lowerBits = offset & 0xffffffff; DWORD rc; assert( id!=0 ); #ifdef SQLITE_TEST if( offset ) SimulateDiskfullError #endif SEEK(offset/1024 + 1); rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN); TRACE3("SEEK %d %lld\n", id->h, offset); if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){ return SQLITE_FULL; } return SQLITE_OK; } /* ** Make sure all writes to a particular file are committed to disk. */ static int winSync(OsFile *id, int dataOnly){ assert( id!=0 ); TRACE3("SYNC %d lock=%d\n", id->h, id->locktype); if( FlushFileBuffers(id->h) ){ return SQLITE_OK; }else{ return SQLITE_IOERR; } } |
︙ | ︙ | |||
515 516 517 518 519 520 521 | } /* ** Truncate an open file to a specified size */ static int winTruncate(OsFile *id, i64 nByte){ LONG upperBits = nByte>>32; | | | | 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 | } /* ** Truncate an open file to a specified size */ static int winTruncate(OsFile *id, i64 nByte){ LONG upperBits = nByte>>32; assert( id!=0 ); TRACE3("TRUNCATE %d %lld\n", id->h, nByte); SimulateIOError(SQLITE_IOERR); SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN); SetEndOfFile(id->h); return SQLITE_OK; } /* ** Determine the current size of a file in bytes */ static int winFileSize(OsFile *id, i64 *pSize){ DWORD upperBits, lowerBits; assert( id!=0 ); SimulateIOError(SQLITE_IOERR); lowerBits = GetFileSize(id->h, &upperBits); *pSize = (((i64)upperBits)<<32) + lowerBits; return SQLITE_OK; } /* |
︙ | ︙ | |||
627 628 629 630 631 632 633 | */ static int winLock(OsFile *id, int locktype){ int rc = SQLITE_OK; /* Return code from subroutines */ int res = 1; /* Result of a windows lock call */ int newLocktype; /* Set id->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ | | | 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | */ static int winLock(OsFile *id, int locktype){ int rc = SQLITE_OK; /* Return code from subroutines */ int res = 1; /* Result of a windows lock call */ int newLocktype; /* Set id->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ assert( id!=0 ); TRACE5("LOCK %d %d was %d(%d)\n", id->h, locktype, id->locktype, id->sharedLockByte); /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ |
︙ | ︙ | |||
733 734 735 736 737 738 739 | /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, return ** non-zero, otherwise zero. */ static int winCheckReservedLock(OsFile *id){ int rc; | | | 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 | /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, return ** non-zero, otherwise zero. */ static int winCheckReservedLock(OsFile *id){ int rc; assert( id!=0 ); if( id->locktype>=RESERVED_LOCK ){ rc = 1; TRACE3("TEST WR-LOCK %d %d (local)\n", id->h, rc); }else{ rc = LockFile(id->h, RESERVED_BYTE, 0, 1, 0); if( rc ){ UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0); |
︙ | ︙ | |||
762 763 764 765 766 767 768 | ** It is not possible for this routine to fail if the second argument ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine ** might return SQLITE_IOERR; */ static int winUnlock(OsFile *id, int locktype){ int type; int rc = SQLITE_OK; | | | 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 | ** It is not possible for this routine to fail if the second argument ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine ** might return SQLITE_IOERR; */ static int winUnlock(OsFile *id, int locktype){ int type; int rc = SQLITE_OK; assert( id!=0 ); assert( locktype<=SHARED_LOCK ); TRACE5("UNLOCK %d to %d was %d(%d)\n", id->h, locktype, id->locktype, id->sharedLockByte); type = id->locktype; if( type>=EXCLUSIVE_LOCK ){ UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( locktype==SHARED_LOCK && !getReadLock(id) ){ |
︙ | ︙ | |||
826 827 828 829 830 831 832 | GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed); } #endif return zFull; } /* | > > > > > | > > | > > | > > > > > > | 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 | GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed); } #endif return zFull; } /* ** The fullSync option is meaningless on windows. This is a no-op. */ static void winSetFullSync(OsFile *id, int v){ return; } /* ** Return the underlying file handle for an OsFile */ static int winFileHandle(OsFile *id){ return (int)id->h; } /* ** Return an integer that indices the type of lock currently held ** by this handle. (Used for testing and analysis only.) */ static int winLockState(OsFile *id){ return id->locktype; } /* ** This is the structure that defines all of the I/O routines. */ struct sqlite3IoVtbl sqlite3Io = { |
︙ | ︙ | |||
857 858 859 860 861 862 863 | winSync, winTruncate, winFileSize, winFullPathname, winLock, winUnlock, winCheckReservedLock, | > | > | 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 | winSync, winTruncate, winFileSize, winFullPathname, winLock, winUnlock, winCheckReservedLock, winSetFullSync, winFileHandle, winLockState, }; #endif /* SQLITE_OMIT_DISKIO */ /*************************************************************************** ** Everything above deals with file I/O. Everything that follows deals ** with other miscellanous aspects of the operating system interface ****************************************************************************/ |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** ** @(#) $Id: pager.c,v 1.221 2005/11/29 03:13:22 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include "os.h" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
48 49 50 51 52 53 54 | ** The following two macros are used within the TRACEX() macros above ** to print out file-descriptors. ** ** PAGERID() takes a pointer to a Pager struct as it's argument. The ** associated file-descriptor is returned. FILEHANDLEID() takes an OsFile ** struct as it's argument. */ | | | | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | ** The following two macros are used within the TRACEX() macros above ** to print out file-descriptors. ** ** PAGERID() takes a pointer to a Pager struct as it's argument. The ** associated file-descriptor is returned. FILEHANDLEID() takes an OsFile ** struct as it's argument. */ #define PAGERID(p) FILEHANDLEID(&(p)->fd) #define FILEHANDLEID(fd) (sqlite3Io.xFileHandle(&fd)) /* ** The page cache as a whole is always in one of the following ** states: ** ** PAGER_UNLOCK The page cache is not currently reading or ** writing the database file. There is no |
︙ | ︙ | |||
258 259 260 261 262 263 264 | int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */ int mxPage; /* Maximum number of pages to hold in cache */ u8 *aInJournal; /* One bit for each page in the database file */ u8 *aInStmt; /* One bit for each page in the database */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ char *zDirectory; /* Directory hold database and journal files */ | | | | 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */ int mxPage; /* Maximum number of pages to hold in cache */ u8 *aInJournal; /* One bit for each page in the database file */ u8 *aInStmt; /* One bit for each page in the database */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ char *zDirectory; /* Directory hold database and journal files */ OsFile *fd, *jfd; /* File descriptors for database and journal */ OsFile *stfd; /* File descriptor for the statement subjournal*/ BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */ PgHdr *pFirst, *pLast; /* List of free pages */ PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */ PgHdr *pAll; /* List of all pages */ PgHdr *pStmt; /* List of pages in the statement subjournal */ i64 journalOff; /* Current byte offset in the journal file */ i64 journalHdr; /* Byte offset to previous journal header */ |
︙ | ︙ | |||
586 587 588 589 590 591 592 | if( c ){ offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager); } assert( offset%JOURNAL_HDR_SZ(pPager)==0 ); assert( offset>=c ); assert( (offset-c)<JOURNAL_HDR_SZ(pPager) ); pPager->journalOff = offset; | | | 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 | if( c ){ offset = ((c-1)/JOURNAL_HDR_SZ(pPager) + 1) * JOURNAL_HDR_SZ(pPager); } assert( offset%JOURNAL_HDR_SZ(pPager)==0 ); assert( offset>=c ); assert( (offset-c)<JOURNAL_HDR_SZ(pPager) ); pPager->journalOff = offset; return sqlite3Io.xSeek(pPager->jfd, pPager->journalOff); } /* ** The journal file must be open when this routine is called. A journal ** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the ** current location. ** |
︙ | ︙ | |||
622 623 624 625 626 627 628 | ** ** Possibly for a pager not in no-sync mode, the journal magic should not ** be written until nRec is filled in as part of next syncJournal(). ** ** Actually maybe the whole journal header should be delayed until that ** point. Think about this. */ | | | | | | | | | 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 | ** ** Possibly for a pager not in no-sync mode, the journal magic should not ** be written until nRec is filled in as part of next syncJournal(). ** ** Actually maybe the whole journal header should be delayed until that ** point. Think about this. */ rc = sqlite3Io.xWrite(pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); if( rc==SQLITE_OK ){ /* The nRec Field. 0xFFFFFFFF for no-sync journals. */ rc = write32bits(pPager->jfd, pPager->noSync ? 0xffffffff : 0); } if( rc==SQLITE_OK ){ /* The random check-hash initialiser */ sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); rc = write32bits(pPager->jfd, pPager->cksumInit); } if( rc==SQLITE_OK ){ /* The initial database size */ rc = write32bits(pPager->jfd, pPager->dbSize); } if( rc==SQLITE_OK ){ /* The assumed sector size for this process */ rc = write32bits(pPager->jfd, pPager->sectorSize); } /* The journal header has been written successfully. Seek the journal ** file descriptor to the end of the journal header sector. */ if( rc==SQLITE_OK ){ rc = sqlite3Io.xSeek(pPager->jfd, pPager->journalOff-1); if( rc==SQLITE_OK ){ rc = sqlite3Io.xWrite(pPager->jfd, "\000", 1); } } return rc; } /* ** The journal file must be open when this is called. A journal header file |
︙ | ︙ | |||
686 687 688 689 690 691 692 | rc = seekJournalHdr(pPager); if( rc ) return rc; if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){ return SQLITE_DONE; } | | | | | | | | 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 | rc = seekJournalHdr(pPager); if( rc ) return rc; if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){ return SQLITE_DONE; } rc = sqlite3Io.xRead(pPager->jfd, aMagic, sizeof(aMagic)); if( rc ) return rc; if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ return SQLITE_DONE; } rc = read32bits(pPager->jfd, pNRec); if( rc ) return rc; rc = read32bits(pPager->jfd, &pPager->cksumInit); if( rc ) return rc; rc = read32bits(pPager->jfd, pDbSize); if( rc ) return rc; /* Update the assumed sector-size to match the value used by ** the process that created this journal. If this journal was ** created by a process other than this one, then this routine ** is being called from within pager_playback(). The local value ** of Pager.sectorSize is restored at the end of that routine. */ rc = read32bits(pPager->jfd, (u32 *)&pPager->sectorSize); if( rc ) return rc; pPager->journalOff += JOURNAL_HDR_SZ(pPager); rc = sqlite3Io.xSeek(pPager->jfd, pPager->journalOff); return rc; } /* ** Write the supplied master journal name into the journal file for pager ** pPager at the current location. The master journal name must be the last |
︙ | ︙ | |||
757 758 759 760 761 762 763 | */ if( pPager->fullSync ){ rc = seekJournalHdr(pPager); if( rc!=SQLITE_OK ) return rc; } pPager->journalOff += (len+20); | | | | | | | 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 | */ if( pPager->fullSync ){ rc = seekJournalHdr(pPager); if( rc!=SQLITE_OK ) return rc; } pPager->journalOff += (len+20); rc = write32bits(pPager->jfd, PAGER_MJ_PGNO(pPager)); if( rc!=SQLITE_OK ) return rc; rc = sqlite3Io.xWrite(pPager->jfd, zMaster, len); if( rc!=SQLITE_OK ) return rc; rc = write32bits(pPager->jfd, len); if( rc!=SQLITE_OK ) return rc; rc = write32bits(pPager->jfd, cksum); if( rc!=SQLITE_OK ) return rc; rc = sqlite3Io.xWrite(pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); pPager->needSync = !pPager->noSync; return rc; } /* ** Add or remove a page from the list of all pages that are in the ** statement journal. |
︙ | ︙ | |||
847 848 849 850 851 852 853 | pPager->pLast = 0; pPager->pAll = 0; memset(pPager->aHash, 0, sizeof(pPager->aHash)); pPager->nPage = 0; if( pPager->state>=PAGER_RESERVED ){ sqlite3pager_rollback(pPager); } | | | 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 | pPager->pLast = 0; pPager->pAll = 0; memset(pPager->aHash, 0, sizeof(pPager->aHash)); pPager->nPage = 0; if( pPager->state>=PAGER_RESERVED ){ sqlite3pager_rollback(pPager); } sqlite3Io.xUnlock(pPager->fd, NO_LOCK); pPager->state = PAGER_UNLOCK; pPager->dbSize = -1; pPager->nRef = 0; assert( pPager->journalOpen==0 ); } /* |
︙ | ︙ | |||
919 920 921 922 923 924 925 | } pPager->dirtyCache = 0; pPager->nRec = 0; }else{ assert( pPager->aInJournal==0 ); assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); } | | | 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 | } pPager->dirtyCache = 0; pPager->nRec = 0; }else{ assert( pPager->aInJournal==0 ); assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); } rc = sqlite3Io.xUnlock(pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; pPager->origDbSize = 0; pPager->setMaster = 0; return rc; } /* |
︙ | ︙ | |||
974 975 976 977 978 979 980 | Pgno pgno; /* The page number of a page in journal */ u32 cksum; /* Checksum used for sanity checking */ u8 aData[SQLITE_MAX_PAGE_SIZE]; /* Temp storage for a page */ /* useCksum should be true for the main journal and false for ** statement journals. Verify that this is always the case */ | | | 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 | Pgno pgno; /* The page number of a page in journal */ u32 cksum; /* Checksum used for sanity checking */ u8 aData[SQLITE_MAX_PAGE_SIZE]; /* Temp storage for a page */ /* useCksum should be true for the main journal and false for ** statement journals. Verify that this is always the case */ assert( jfd == (useCksum ? pPager->jfd : pPager->stfd) ); rc = read32bits(jfd, &pgno); if( rc!=SQLITE_OK ) return rc; rc = sqlite3Io.xRead(jfd, &aData, pPager->pageSize); if( rc!=SQLITE_OK ) return rc; pPager->journalOff += pPager->pageSize + 4; |
︙ | ︙ | |||
1029 1030 1031 1032 1033 1034 1035 | ** page content is in the main journal either because the page is not in ** cache or else it is marked as needSync==0. */ pPg = pager_lookup(pPager, pgno); assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 ); TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno); if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){ | | | | 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 | ** page content is in the main journal either because the page is not in ** cache or else it is marked as needSync==0. */ pPg = pager_lookup(pPager, pgno); assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 ); TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno); if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){ rc = sqlite3Io.xSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize); if( rc==SQLITE_OK ){ rc = sqlite3Io.xWrite(pPager->fd, aData, pPager->pageSize); } if( pPg ) pPg->dirty = 0; } if( pPg ){ /* No page should ever be explicitly rolled back that is in use, except ** for page 1 which is held in use in order to keep the lock on the ** database active. However such a page may be rolled back as a result |
︙ | ︙ | |||
1071 1072 1073 1074 1075 1076 1077 | ** To tell if a master journal can be deleted, check to each of the ** children. If all children are either missing or do not refer to ** a different master journal, then this master journal can be deleted. */ static int pager_delmaster(const char *zMaster){ int rc; int master_open = 0; | | < | | | < | | 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 | ** To tell if a master journal can be deleted, check to each of the ** children. If all children are either missing or do not refer to ** a different master journal, then this master journal can be deleted. */ static int pager_delmaster(const char *zMaster){ int rc; int master_open = 0; OsFile *master = 0; char *zMasterJournal = 0; /* Contents of master journal file */ i64 nMasterJournal; /* Size of master journal file */ /* Open the master journal file exclusively in case some other process ** is running this routine also. Not that it makes too much difference. */ rc = sqlite3Io.xOpenReadOnly(zMaster, &master); if( rc!=SQLITE_OK ) goto delmaster_out; master_open = 1; rc = sqlite3Io.xFileSize(master, &nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; if( nMasterJournal>0 ){ char *zJournal; char *zMasterPtr = 0; /* Load the entire master journal file into space obtained from ** sqliteMalloc() and pointed to by zMasterJournal. */ zMasterJournal = (char *)sqliteMalloc(nMasterJournal); if( !zMasterJournal ){ rc = SQLITE_NOMEM; goto delmaster_out; } rc = sqlite3Io.xRead(master, zMasterJournal, nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; zJournal = zMasterJournal; while( (zJournal-zMasterJournal)<nMasterJournal ){ if( sqlite3Io.xFileExists(zJournal) ){ /* One of the journals pointed to by the master journal exists. ** Open it and check if it points at the master journal. If ** so, return without deleting the master journal file. */ OsFile *journal = 0; int c; rc = sqlite3Io.xOpenReadOnly(zJournal, &journal); if( rc!=SQLITE_OK ){ goto delmaster_out; } rc = readMasterJournal(journal, &zMasterPtr); sqlite3Io.xClose(&journal); if( rc!=SQLITE_OK ){ goto delmaster_out; } c = zMasterPtr!=0 && strcmp(zMasterPtr, zMaster)==0; sqliteFree(zMasterPtr); |
︙ | ︙ | |||
1161 1162 1163 1164 1165 1166 1167 | static int pager_reload_cache(Pager *pPager){ PgHdr *pPg; int rc = SQLITE_OK; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ char zBuf[SQLITE_MAX_PAGE_SIZE]; if( !pPg->dirty ) continue; if( (int)pPg->pgno <= pPager->origDbSize ){ | | | | 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 | static int pager_reload_cache(Pager *pPager){ PgHdr *pPg; int rc = SQLITE_OK; for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ char zBuf[SQLITE_MAX_PAGE_SIZE]; if( !pPg->dirty ) continue; if( (int)pPg->pgno <= pPager->origDbSize ){ rc = sqlite3Io.xSeek(pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1)); if( rc==SQLITE_OK ){ rc = sqlite3Io.xRead(pPager->fd, zBuf, pPager->pageSize); } TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno); if( rc ) break; CODEC(pPager, zBuf, pPg->pgno, 2); }else{ memset(zBuf, 0, pPager->pageSize); } |
︙ | ︙ | |||
1194 1195 1196 1197 1198 1199 1200 | /* ** Truncate the main file of the given pager to the number of pages ** indicated. */ static int pager_truncate(Pager *pPager, int nPage){ assert( pPager->state>=PAGER_EXCLUSIVE ); | | | 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 | /* ** Truncate the main file of the given pager to the number of pages ** indicated. */ static int pager_truncate(Pager *pPager, int nPage){ assert( pPager->state>=PAGER_EXCLUSIVE ); return sqlite3Io.xTruncate(pPager->fd, pPager->pageSize*(i64)nPage); } /* ** Playback the journal and thus restore the database file to ** the state it was in before we started making changes. ** ** The journal file format is as follows: |
︙ | ︙ | |||
1262 1263 1264 1265 1266 1267 1268 | int rc; /* Result code of a subroutine */ char *zMaster = 0; /* Name of master journal file if any */ /* Figure out how many records are in the journal. Abort early if ** the journal is empty. */ assert( pPager->journalOpen ); | | | | | 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 | int rc; /* Result code of a subroutine */ char *zMaster = 0; /* Name of master journal file if any */ /* Figure out how many records are in the journal. Abort early if ** the journal is empty. */ assert( pPager->journalOpen ); rc = sqlite3Io.xFileSize(pPager->jfd, &szJ); if( rc!=SQLITE_OK ){ goto end_playback; } /* Read the master journal name from the journal, if it is present. ** If a master journal file name is specified, but the file is not ** present on disk, then the journal is not hot and does not need to be ** played back. */ rc = readMasterJournal(pPager->jfd, &zMaster); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK || (zMaster && !sqlite3Io.xFileExists(zMaster)) ){ sqliteFree(zMaster); zMaster = 0; if( rc==SQLITE_DONE ) rc = SQLITE_OK; goto end_playback; } sqlite3Io.xSeek(pPager->jfd, 0); pPager->journalOff = 0; /* This loop terminates either when the readJournalHdr() call returns ** SQLITE_DONE or an IO error occurs. */ while( 1 ){ /* Read the next journal header from the journal file. If there are |
︙ | ︙ | |||
1323 1324 1325 1326 1327 1328 1329 | rc = pager_truncate(pPager, mxPg); if( rc!=SQLITE_OK ){ goto end_playback; } pPager->dbSize = mxPg; } | | | | 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 | rc = pager_truncate(pPager, mxPg); if( rc!=SQLITE_OK ){ goto end_playback; } pPager->dbSize = mxPg; } /* rc = sqlite3Io.xSeek(pPager->jfd, JOURNAL_HDR_SZ(pPager)); */ if( rc!=SQLITE_OK ) goto end_playback; /* Copy original pages out of the journal and back into the database file. */ for(i=0; i<nRec; i++){ rc = pager_playback_one_page(pPager, pPager->jfd, 1); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; pPager->journalOff = szJ; break; }else{ goto end_playback; |
︙ | ︙ | |||
1396 1397 1398 1399 1400 1401 1402 | int i; /* Loop counter */ int rc; szJ = pPager->journalOff; #ifndef NDEBUG { i64 os_szJ; | | | 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 | int i; /* Loop counter */ int rc; szJ = pPager->journalOff; #ifndef NDEBUG { i64 os_szJ; rc = sqlite3Io.xFileSize(pPager->jfd, &os_szJ); if( rc!=SQLITE_OK ) return rc; assert( szJ==os_szJ ); } #endif /* Set hdrOff to be the offset to the first journal header written ** this statement transaction, or the end of the file if no journal |
︙ | ︙ | |||
1422 1423 1424 1425 1426 1427 1428 | rc = pager_truncate(pPager, pPager->stmtSize); } pPager->dbSize = pPager->stmtSize; /* Figure out how many records are in the statement journal. */ assert( pPager->stmtInUse && pPager->journalOpen ); | | | | | | | 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 | rc = pager_truncate(pPager, pPager->stmtSize); } pPager->dbSize = pPager->stmtSize; /* Figure out how many records are in the statement journal. */ assert( pPager->stmtInUse && pPager->journalOpen ); sqlite3Io.xSeek(pPager->stfd, 0); nRec = pPager->stmtNRec; /* Copy original pages out of the statement journal and back into the ** database file. Note that the statement journal omits checksums from ** each record since power-failure recovery is not important to statement ** journals. */ for(i=nRec-1; i>=0; i--){ rc = pager_playback_one_page(pPager, pPager->stfd, 0); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } /* Now roll some pages back from the transaction journal. Pager.stmtJSize ** was the size of the journal file when this statement was started, so ** everything after that needs to be rolled back, either into the ** database, the memory cache, or both. ** ** If it is not zero, then Pager.stmtHdrOff is the offset to the start ** of the first journal header written during this statement transaction. */ rc = sqlite3Io.xSeek(pPager->jfd, pPager->stmtJSize); if( rc!=SQLITE_OK ){ goto end_stmt_playback; } pPager->journalOff = pPager->stmtJSize; pPager->cksumInit = pPager->stmtCksum; assert( JOURNAL_HDR_SZ(pPager)<(pPager->pageSize+8) ); while( pPager->journalOff <= (hdrOff-(pPager->pageSize+8)) ){ rc = pager_playback_one_page(pPager, pPager->jfd, 1); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } while( pPager->journalOff < szJ ){ u32 nRec; u32 dummy; rc = readJournalHdr(pPager, szJ, &nRec, &dummy); if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_DONE ); goto end_stmt_playback; } if( nRec==0 ){ nRec = (szJ - pPager->journalOff) / (pPager->pageSize+8); } for(i=nRec-1; i>=0 && pPager->journalOff < szJ; i--){ rc = pager_playback_one_page(pPager, pPager->jfd, 1); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } } pPager->journalOff = szJ; |
︙ | ︙ | |||
1549 1550 1551 1552 1553 1554 1555 | ** (zFile must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write ** the file descriptor into *fd. Return SQLITE_OK on success or some ** other error code if we fail. ** ** The OS will automatically delete the temporary file when it is ** closed. */ | | | | 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 | ** (zFile must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write ** the file descriptor into *fd. Return SQLITE_OK on success or some ** other error code if we fail. ** ** The OS will automatically delete the temporary file when it is ** closed. */ static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){ int cnt = 8; int rc; sqlite3_opentemp_count++; /* Used for testing and analysis only */ do{ cnt--; sqlite3Io.xTempFileName(zFile); rc = sqlite3Io.xOpenExclusive(zFile, pFd, 1); }while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM ); return rc; } /* ** Create a new page cache and put a pointer to the page cache in *ppPager. ** The file to be cached need not exist. The file is not locked until |
︙ | ︙ | |||
1584 1585 1586 1587 1588 1589 1590 | const char *zFilename, /* Name of the database file to open */ int nExtra, /* Extra bytes append to each in-memory page */ int flags /* flags controlling this file */ ){ Pager *pPager; char *zFullPathname = 0; int nameLen; | | | 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 | const char *zFilename, /* Name of the database file to open */ int nExtra, /* Extra bytes append to each in-memory page */ int flags /* flags controlling this file */ ){ Pager *pPager; char *zFullPathname = 0; int nameLen; OsFile *fd; int rc = SQLITE_OK; int i; int tempFile = 0; int memDb = 0; int readOnly = 0; int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; int noReadlock = (flags & PAGER_NO_READLOCK)!=0; |
︙ | ︙ | |||
1648 1649 1650 1651 1652 1653 1654 | strcpy(pPager->zFilename, zFullPathname); strcpy(pPager->zDirectory, zFullPathname); for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){} if( i>0 ) pPager->zDirectory[i-1] = 0; strcpy(pPager->zJournal, zFullPathname); sqliteFree(zFullPathname); strcpy(&pPager->zJournal[nameLen], "-journal"); | | | 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 | strcpy(pPager->zFilename, zFullPathname); strcpy(pPager->zDirectory, zFullPathname); for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){} if( i>0 ) pPager->zDirectory[i-1] = 0; strcpy(pPager->zJournal, zFullPathname); sqliteFree(zFullPathname); strcpy(&pPager->zJournal[nameLen], "-journal"); pPager->fd = fd; pPager->journalOpen = 0; pPager->useJournal = useJournal && !memDb; pPager->noReadlock = noReadlock && readOnly; pPager->stmtOpen = 0; pPager->stmtInUse = 0; pPager->nRef = 0; pPager->dbSize = memDb-1; |
︙ | ︙ | |||
1759 1760 1761 1762 1763 1764 1765 | /* ** Read the first N bytes from the beginning of the file into memory ** that pDest points to. No error checking is done. */ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){ memset(pDest, 0, N); if( MEMDB==0 ){ | | | | | 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 | /* ** Read the first N bytes from the beginning of the file into memory ** that pDest points to. No error checking is done. */ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){ memset(pDest, 0, N); if( MEMDB==0 ){ sqlite3Io.xSeek(pPager->fd, 0); sqlite3Io.xRead(pPager->fd, pDest, N); clear_simulated_io_error(); } } /* ** Return the total number of pages in the disk file associated with ** pPager. ** ** If the PENDING_BYTE lies on the page directly after the end of the ** file, then consider this page part of the file too. For example, if ** PENDING_BYTE is byte 4096 (the first byte of page 5) and the size of the ** file is 4096 bytes, 5 is returned instead of 4. */ int sqlite3pager_pagecount(Pager *pPager){ i64 n; assert( pPager!=0 ); if( pPager->dbSize>=0 ){ n = pPager->dbSize; } else { if( sqlite3Io.xFileSize(pPager->fd, &n)!=SQLITE_OK ){ pPager->errMask |= PAGER_ERR_DISK; return 0; } if( n>0 && n<pPager->pageSize ){ n = 1; }else{ n /= pPager->pageSize; |
︙ | ︙ | |||
1912 1913 1914 1915 1916 1917 1918 | assert( PAGER_SHARED==SHARED_LOCK ); assert( PAGER_RESERVED==RESERVED_LOCK ); assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); if( pPager->state>=locktype ){ rc = SQLITE_OK; }else{ do { | | | 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 | assert( PAGER_SHARED==SHARED_LOCK ); assert( PAGER_RESERVED==RESERVED_LOCK ); assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); if( pPager->state>=locktype ){ rc = SQLITE_OK; }else{ do { rc = sqlite3Io.xLock(pPager->fd, locktype); }while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) ); if( rc==SQLITE_OK ){ pPager->state = locktype; } } return rc; } |
︙ | ︙ | |||
1980 1981 1982 1983 1984 1985 1986 | ** operation. So disable IO error simulation so that testing ** works more easily. */ disable_simulated_io_errors(); sqlite3pager_rollback(pPager); enable_simulated_io_errors(); if( !MEMDB ){ | | | | 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 | ** operation. So disable IO error simulation so that testing ** works more easily. */ disable_simulated_io_errors(); sqlite3pager_rollback(pPager); enable_simulated_io_errors(); if( !MEMDB ){ sqlite3Io.xUnlock(pPager->fd, NO_LOCK); } assert( pPager->errMask || pPager->journalOpen==0 ); break; } case PAGER_SHARED: { if( !MEMDB ){ sqlite3Io.xUnlock(pPager->fd, NO_LOCK); } break; } default: { /* Do nothing */ break; } |
︙ | ︙ | |||
2129 2130 2131 2132 2133 2134 2135 | ** was turned off after the transaction was started. Ticket #615 */ #ifndef NDEBUG { /* Make sure the pPager->nRec counter we are keeping agrees ** with the nRec computed from the size of the journal file. */ i64 jSz; | | | | | | | | 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 | ** was turned off after the transaction was started. Ticket #615 */ #ifndef NDEBUG { /* Make sure the pPager->nRec counter we are keeping agrees ** with the nRec computed from the size of the journal file. */ i64 jSz; rc = sqlite3Io.xFileSize(pPager->jfd, &jSz); if( rc!=0 ) return rc; assert( pPager->journalOff==jSz ); } #endif { /* Write the nRec value into the journal file header. If in ** full-synchronous mode, sync the journal first. This ensures that ** all data has really hit the disk before nRec is updated to mark ** it as a candidate for rollback. */ if( pPager->fullSync ){ TRACE2("SYNC journal of %d\n", PAGERID(pPager)); rc = sqlite3Io.xSync(pPager->jfd, 0); if( rc!=0 ) return rc; } rc = sqlite3Io.xSeek(pPager->jfd, pPager->journalHdr + sizeof(aJournalMagic)); if( rc ) return rc; rc = write32bits(pPager->jfd, pPager->nRec); if( rc ) return rc; rc = sqlite3Io.xSeek(pPager->jfd, pPager->journalOff); if( rc ) return rc; } TRACE2("SYNC journal of %d\n", PAGERID(pPager)); rc = sqlite3Io.xSync(pPager->jfd, pPager->fullSync); if( rc!=0 ) return rc; pPager->journalStarted = 1; } pPager->needSync = 0; /* Erase the needSync flag from every page. */ |
︙ | ︙ | |||
2220 2221 2222 2223 2224 2225 2226 | rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ return rc; } while( pList ){ assert( pList->dirty ); | | | | 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 | rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ return rc; } while( pList ){ assert( pList->dirty ); rc = sqlite3Io.xSeek(pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize); if( rc ) return rc; /* If there are dirty pages in the page cache with page numbers greater ** than Pager.dbSize, this means sqlite3pager_truncate() was called to ** make the file smaller (presumably by auto-vacuum code). Do not write ** any such pages to the file. */ if( pList->pgno<=pPager->dbSize ){ CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6); TRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno); rc = sqlite3Io.xWrite(pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize); CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0); TEST_INCR(pPager->nWrite); } #ifndef NDEBUG else{ TRACE3("NOSTORE %d page %d\n", PAGERID(pPager), pList->pgno); |
︙ | ︙ | |||
2278 2279 2280 2281 2282 2283 2284 | ** If the current size of the database file is 0 but a journal file ** exists, that is probably an old journal left over from a prior ** database with the same name. Just delete the journal. */ static int hasHotJournal(Pager *pPager){ if( !pPager->useJournal ) return 0; if( !sqlite3Io.xFileExists(pPager->zJournal) ) return 0; | | | 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 | ** If the current size of the database file is 0 but a journal file ** exists, that is probably an old journal left over from a prior ** database with the same name. Just delete the journal. */ static int hasHotJournal(Pager *pPager){ if( !pPager->useJournal ) return 0; if( !sqlite3Io.xFileExists(pPager->zJournal) ) return 0; if( sqlite3Io.xCheckReservedLock(pPager->fd) ) return 0; if( sqlite3pager_pagecount(pPager)==0 ){ sqlite3Io.xDelete(pPager->zJournal); return 0; }else{ return 1; } } |
︙ | ︙ | |||
2357 2358 2359 2360 2361 2362 2363 | ** database is safe to read while this process is still rolling it ** back. ** ** Because the intermediate RESERVED lock is not requested, the ** second process will get to this point in the code and fail to ** obtain it's own EXCLUSIVE lock on the database file. */ | | | | | 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 | ** database is safe to read while this process is still rolling it ** back. ** ** Because the intermediate RESERVED lock is not requested, the ** second process will get to this point in the code and fail to ** obtain it's own EXCLUSIVE lock on the database file. */ rc = sqlite3Io.xLock(pPager->fd, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ sqlite3Io.xUnlock(pPager->fd, NO_LOCK); pPager->state = PAGER_UNLOCK; return rc; } pPager->state = PAGER_EXCLUSIVE; /* Open the journal for reading only. Return SQLITE_BUSY if ** we are unable to open the journal file. ** ** The journal file does not need to be locked itself. The ** journal file is never open unless the main database file holds ** a write lock, so there is never any chance of two or more ** processes opening the journal at the same time. */ rc = sqlite3Io.xOpenReadOnly(pPager->zJournal, &pPager->jfd); if( rc!=SQLITE_OK ){ sqlite3Io.xUnlock(pPager->fd, NO_LOCK); pPager->state = PAGER_UNLOCK; return SQLITE_BUSY; } pPager->journalOpen = 1; pPager->journalStarted = 0; pPager->journalOff = 0; pPager->setMaster = 0; |
︙ | ︙ | |||
2532 2533 2534 2535 2536 2537 2538 | return rc; } if( sqlite3pager_pagecount(pPager)<(int)pgno ){ memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); }else{ int rc; assert( MEMDB==0 ); | | | | | 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 | return rc; } if( sqlite3pager_pagecount(pPager)<(int)pgno ){ memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); }else{ int rc; assert( MEMDB==0 ); rc = sqlite3Io.xSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize); if( rc==SQLITE_OK ){ rc = sqlite3Io.xRead(pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize); } TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno); CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3); if( rc!=SQLITE_OK ){ i64 fileSize; if( sqlite3Io.xFileSize(pPager->fd,&fileSize)!=SQLITE_OK || fileSize>=pgno*pPager->pageSize ){ sqlite3pager_unref(PGHDR_TO_DATA(pPg)); return rc; }else{ clear_simulated_io_error(); memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); } |
︙ | ︙ | |||
2671 2672 2673 2674 2675 2676 2677 | pPager->tempFile); pPager->journalOff = 0; pPager->setMaster = 0; pPager->journalHdr = 0; if( rc!=SQLITE_OK ){ goto failed_to_open_journal; } | | | | | 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 | pPager->tempFile); pPager->journalOff = 0; pPager->setMaster = 0; pPager->journalHdr = 0; if( rc!=SQLITE_OK ){ goto failed_to_open_journal; } sqlite3Io.xSetFullSync(pPager->jfd, pPager->fullSync); sqlite3Io.xSetFullSync(pPager->fd, pPager->fullSync); sqlite3Io.xOpenDirectory(pPager->zDirectory, pPager->jfd); pPager->journalOpen = 1; pPager->journalStarted = 0; pPager->needSync = 0; pPager->alwaysRollback = 0; pPager->nRec = 0; if( pPager->errMask!=0 ){ rc = pager_errcode(pPager); |
︙ | ︙ | |||
2701 2702 2703 2704 2705 2706 2707 | } } return rc; failed_to_open_journal: sqliteFree(pPager->aInJournal); pPager->aInJournal = 0; | | | 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 | } } return rc; failed_to_open_journal: sqliteFree(pPager->aInJournal); pPager->aInJournal = 0; sqlite3Io.xUnlock(pPager->fd, NO_LOCK); pPager->state = PAGER_UNLOCK; return rc; } /* ** Acquire a write-lock on the database. The lock is removed when ** the any of the following happen: |
︙ | ︙ | |||
2745 2746 2747 2748 2749 2750 2751 | assert( pPager->state!=PAGER_UNLOCK ); if( pPager->state==PAGER_SHARED ){ assert( pPager->aInJournal==0 ); if( MEMDB ){ pPager->state = PAGER_EXCLUSIVE; pPager->origDbSize = pPager->dbSize; }else{ | | | 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 | assert( pPager->state!=PAGER_UNLOCK ); if( pPager->state==PAGER_SHARED ){ assert( pPager->aInJournal==0 ); if( MEMDB ){ pPager->state = PAGER_EXCLUSIVE; pPager->origDbSize = pPager->dbSize; }else{ rc = sqlite3Io.xLock(pPager->fd, RESERVED_LOCK); if( rc==SQLITE_OK ){ pPager->state = PAGER_RESERVED; if( exFlag ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } } if( rc!=SQLITE_OK ){ |
︙ | ︙ | |||
2856 2857 2858 2859 2860 2861 2862 | assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); CODEC(pPager, pData, pPg->pgno, 7); cksum = pager_cksum(pPager, pPg->pgno, pData); saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager); store32bits(cksum, pPg, pPager->pageSize); szPg = pPager->pageSize+8; store32bits(pPg->pgno, pPg, -4); | | | 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 | assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) ); CODEC(pPager, pData, pPg->pgno, 7); cksum = pager_cksum(pPager, pPg->pgno, pData); saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager); store32bits(cksum, pPg, pPager->pageSize); szPg = pPager->pageSize+8; store32bits(pPg->pgno, pPg, -4); rc = sqlite3Io.xWrite(pPager->jfd, &((char*)pData)[-4], szPg); pPager->journalOff += szPg; TRACE4("JOURNAL %d page %d needSync=%d\n", PAGERID(pPager), pPg->pgno, pPg->needSync); CODEC(pPager, pData, pPg->pgno, 0); *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved; if( rc!=SQLITE_OK ){ sqlite3pager_rollback(pPager); |
︙ | ︙ | |||
2905 2906 2907 2908 2909 2910 2911 | if( pHist->pStmt ){ memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize); } TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); }else{ store32bits(pPg->pgno, pPg, -4); CODEC(pPager, pData, pPg->pgno, 7); | | | 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 | if( pHist->pStmt ){ memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize); } TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); }else{ store32bits(pPg->pgno, pPg, -4); CODEC(pPager, pData, pPg->pgno, 7); rc = sqlite3Io.xWrite(pPager->stfd,((char*)pData)-4, pPager->pageSize+4); TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); CODEC(pPager, pData, pPg->pgno, 0); if( rc!=SQLITE_OK ){ sqlite3pager_rollback(pPager); pPager->errMask |= PAGER_ERR_FULL; return rc; |
︙ | ︙ | |||
3268 3269 3270 3271 3272 3273 3274 | if( !pPager->journalOpen ){ pPager->stmtAutoopen = 1; return SQLITE_OK; } assert( pPager->journalOpen ); pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInStmt==0 ){ | | | | 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 | if( !pPager->journalOpen ){ pPager->stmtAutoopen = 1; return SQLITE_OK; } assert( pPager->journalOpen ); pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInStmt==0 ){ sqlite3Io.xLock(pPager->fd, SHARED_LOCK); return SQLITE_NOMEM; } #ifndef NDEBUG rc = sqlite3Io.xFileSize(pPager->jfd, &pPager->stmtJSize); if( rc ) goto stmt_begin_failed; assert( pPager->stmtJSize == pPager->journalOff ); #endif pPager->stmtJSize = pPager->journalOff; pPager->stmtSize = pPager->dbSize; pPager->stmtHdrOff = 0; pPager->stmtCksum = pPager->cksumInit; |
︙ | ︙ | |||
3305 3306 3307 3308 3309 3310 3311 | ** Commit a statement. */ int sqlite3pager_stmt_commit(Pager *pPager){ if( pPager->stmtInUse ){ PgHdr *pPg, *pNext; TRACE2("STMT-COMMIT %d\n", PAGERID(pPager)); if( !MEMDB ){ | | | | 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 | ** Commit a statement. */ int sqlite3pager_stmt_commit(Pager *pPager){ if( pPager->stmtInUse ){ PgHdr *pPg, *pNext; TRACE2("STMT-COMMIT %d\n", PAGERID(pPager)); if( !MEMDB ){ sqlite3Io.xSeek(pPager->stfd, 0); /* sqlite3Io.xTruncate(pPager->stfd, 0); */ sqliteFree( pPager->aInStmt ); pPager->aInStmt = 0; } for(pPg=pPager->pStmt; pPg; pPg=pNext){ pNext = pPg->pNextStmt; assert( pPg->inStmt ); pPg->inStmt = 0; |
︙ | ︙ | |||
3509 3510 3511 3512 3513 3514 3515 | /* Write all dirty pages to the database file */ pPg = pager_get_all_dirty_pages(pPager); rc = pager_write_pagelist(pPg); if( rc!=SQLITE_OK ) goto sync_exit; /* Sync the database file. */ if( !pPager->noSync ){ | | | 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 | /* Write all dirty pages to the database file */ pPg = pager_get_all_dirty_pages(pPager); rc = pager_write_pagelist(pPg); if( rc!=SQLITE_OK ) goto sync_exit; /* Sync the database file. */ if( !pPager->noSync ){ rc = sqlite3Io.xSync(pPager->fd, 0); } pPager->state = PAGER_SYNCED; } sync_exit: return rc; |
︙ | ︙ | |||
3623 3624 3625 3626 3627 3628 3629 | #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Return the current state of the file lock for the given pager. ** The return value is one of NO_LOCK, SHARED_LOCK, RESERVED_LOCK, ** PENDING_LOCK, or EXCLUSIVE_LOCK. */ int sqlite3pager_lockstate(Pager *pPager){ | < < < | < | 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 | #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) /* ** Return the current state of the file lock for the given pager. ** The return value is one of NO_LOCK, SHARED_LOCK, RESERVED_LOCK, ** PENDING_LOCK, or EXCLUSIVE_LOCK. */ int sqlite3pager_lockstate(Pager *pPager){ return sqlite3Io.xLockState(pPager->fd); } #endif #ifdef SQLITE_DEBUG /* ** Print a listing of all referenced pages and their ref count. */ |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the printf() interface to SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the printf() interface to SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test1.c,v 1.167 2005/11/29 03:13:22 drh Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include "os.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
2425 2426 2427 2428 2429 2430 2431 | */ static int test_sqlite3OsOpenReadWrite( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ | | < | < | | < | 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 | */ static int test_sqlite3OsOpenReadWrite( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ OsFile *pFile; int rc; int dummy; char zBuf[100]; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " filename", 0); return TCL_ERROR; } rc = sqlite3Io.xOpenReadWrite(Tcl_GetString(objv[1]), &pFile, &dummy); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); return TCL_ERROR; } makePointerStr(interp, zBuf, pFile); Tcl_SetResult(interp, zBuf, 0); return TCL_ERROR; } /* ** Usage: sqlite3OsClose <file handle> */ static int test_sqlite3OsClose( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ OsFile *pFile; int rc; if( objc!=2 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " filehandle", 0); return TCL_ERROR; } if( getFilePointer(interp, Tcl_GetString(objv[1]), &pFile) ){ return TCL_ERROR; } rc = sqlite3Io.xClose(&pFile); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC); return TCL_ERROR; } return TCL_OK; } /* ** Usage: sqlite3OsLock <file handle> <locktype> */ static int test_sqlite3OsLock( |
︙ | ︙ |
Changes to src/test2.c.
︙ | ︙ | |||
9 10 11 12 13 14 15 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the pager.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | ** May you share freely, never taking more than you give. ** ************************************************************************* ** Code for testing the pager.c module in SQLite. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** ** $Id: test2.c,v 1.37 2005/11/29 03:13:22 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include "pager.h" #include "tcl.h" #include <stdlib.h> #include <string.h> |
︙ | ︙ | |||
520 521 522 523 524 525 526 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int rc; int n; i64 offset; | | < | | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 | Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ const char **argv /* Text of each argument */ ){ int rc; int n; i64 offset; OsFile *fd = 0; int readOnly = 0; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " N-MEGABYTES FILE\"", 0); return TCL_ERROR; } if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR; rc = sqlite3Io.xOpenReadWrite(argv[2], &fd, &readOnly); if( rc ){ Tcl_AppendResult(interp, "open failed: ", errorName(rc), 0); return TCL_ERROR; } offset = n; offset *= 1024*1024; rc = sqlite3Io.xSeek(fd, offset); if( rc ){ Tcl_AppendResult(interp, "seek failed: ", errorName(rc), 0); return TCL_ERROR; } rc = sqlite3Io.xWrite(fd, "Hello, World!", 14); sqlite3Io.xClose(&fd); if( rc ){ Tcl_AppendResult(interp, "write failed: ", errorName(rc), 0); return TCL_ERROR; } return TCL_OK; } |
︙ | ︙ |
Changes to src/test6.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 21 22 23 24 25 26 27 | ** the effect on the database file of an OS crash or power failure. This ** is used to test the ability of SQLite to recover from those situations. */ #if SQLITE_TEST /* This file is used for the testing only */ #include "sqliteInt.h" #include "os.h" #include "tcl.h" /* ** A copy of the original sqlite3Io structure */ static struct sqlite3IoVtbl origIo; /* | > > | < | | | 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 | ** the effect on the database file of an OS crash or power failure. This ** is used to test the ability of SQLite to recover from those situations. */ #if SQLITE_TEST /* This file is used for the testing only */ #include "sqliteInt.h" #include "os.h" #include "tcl.h" #if 0 /* ** A copy of the original sqlite3Io structure */ static struct sqlite3IoVtbl origIo; /* ** The OsFile structure for the crash-test backend. The pBase field ** points to an OsFile structure for the native backend. */ struct OsFile { u8 **apBlk; /* Array of blocks that have been written to. */ int nBlk; /* Size of apBlock. */ int nMaxWrite; /* Largest offset written to. */ char *zName; /* File name */ OsFile *pBase; /* Base class */ OsFile *pNext; /* Next in a list of them all */ }; /* ** Size of a simulated disk block */ #define BLOCKSIZE 512 #define BLOCK_OFFSET(x) ((x) * BLOCKSIZE) |
︙ | ︙ | |||
98 99 100 101 102 103 104 | ** A list of all open files. */ static OsTestFile *pAllFiles = 0; /* ** Initialise the os_test.c specific fields of pFile. */ | | | < | | | | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | ** A list of all open files. */ static OsTestFile *pAllFiles = 0; /* ** Initialise the os_test.c specific fields of pFile. */ static void initFile(OsFile **pId, char const *zName){ OsFile *pFile = *pId = sqliteMalloc(sizeof(OsFile) + strlen(zName)+1); pFile->nMaxWrite = 0; pFile->nBlk = 0; pFile->apBlk = 0; pFile->zName = (char *)(&pFile[1]); strcpy(pFile->zName, zName); pFile->pBase = id; pFile->pNext = pAllFiles; pAllFiles = pFile; } /* ** Undo the work done by initFile. Delete the OsTestFile structure ** and unlink the structure from the pAllFiles list. */ static void closeFile(OsFile *id){ OsFile *pFile = id; if( pFile==pAllFiles ){ pAllFiles = pFile->pNext; }else{ OsFile *p; for(p=pAllFiles; p->pNext!=pFile; p=p->pNext ){ assert( p ); } p->pNext = pFile->pNext; } sqliteFree(pFile); } /* ** Return the current seek offset from the start of the file. This ** is unix-only code. */ static i64 osTell(OsFile *pFile){ return lseek(pFile->pBase->h, 0, SEEK_CUR); } /* ** Load block 'blk' into the cache of pFile. */ static int cacheBlock(OsFile *pFile, int blk){ if( blk>=pFile->nBlk ){ int n = ((pFile->nBlk * 2) + 100 + blk); /* if( pFile->nBlk==0 ){ printf("DIRTY %s\n", pFile->zName); } */ pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*)); if( !pFile->apBlk ) return SQLITE_NOMEM; memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*)); pFile->nBlk = n; |
︙ | ︙ | |||
180 181 182 183 184 185 186 | return SQLITE_OK; } /* ** Write the cache of pFile to disk. If crash is non-zero, randomly ** skip blocks when writing. The cache is deleted before returning. */ | | | 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | return SQLITE_OK; } /* ** Write the cache of pFile to disk. If crash is non-zero, randomly ** skip blocks when writing. The cache is deleted before returning. */ static int writeCache2(OsFile *pFile, int crash){ int i; int nMax = pFile->nMaxWrite; i64 offset; int rc = SQLITE_OK; offset = osTell(pFile); for(i=0; i<pFile->nBlk; i++){ |
︙ | ︙ | |||
245 246 247 248 249 250 251 | } return rc; } /* ** Write the cache to disk. */ | | | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | } return rc; } /* ** Write the cache to disk. */ static int writeCache(OsFile *pFile){ if( pFile->apBlk ){ int c = crashRequired(pFile->zName); if( c ){ OsTestFile *p; #ifdef TRACE_WRITECACHE printf("\nCrash during sync of %s\n", pFile->zName); #endif |
︙ | ︙ | |||
271 272 273 274 275 276 277 | /* ** Close the file. */ static int crashClose(OsFile *id){ if( id->pAux ) return SQLITE_OK; if( id->isOpen ){ /* printf("CLOSE %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */ | | | | 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | /* ** Close the file. */ static int crashClose(OsFile *id){ if( id->pAux ) return SQLITE_OK; if( id->isOpen ){ /* printf("CLOSE %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */ writeCache(id); origIo.xClose(&id->pBase); } closeFile(id); return SQLITE_OK; } static int crashRead(OsFile *id, void *pBuf, int amt){ i64 offset; /* The current offset from the start of the file */ |
︙ | ︙ | |||
468 469 470 471 472 473 474 | sqlite3Io.xClose = crashClose; sqlite3Io.xSync = crashSync; sqlite3Io.xTruncate = crashTruncate; sqlite3Io.xFileSize = crashFileSize; sqlite3Io.xOpenReadWrite = crashOpenReadWrite; sqlite3Io.xOpenExclusive = crashOpenExclusive; sqlite3Io.xOpenReadOnly = crashOpenReadOnly; | | > > > | 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | sqlite3Io.xClose = crashClose; sqlite3Io.xSync = crashSync; sqlite3Io.xTruncate = crashTruncate; sqlite3Io.xFileSize = crashFileSize; sqlite3Io.xOpenReadWrite = crashOpenReadWrite; sqlite3Io.xOpenExclusive = crashOpenExclusive; sqlite3Io.xOpenReadOnly = crashOpenReadOnly; sqlite3Io.xSet return TCL_OK; } #endif /* ** This procedure registers the TCL procedures defined in this file. */ int Sqlitetest6_Init(Tcl_Interp *interp){ #if 0 Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0); #endif return TCL_OK; } #endif /* SQLITE_TEST */ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
198 199 200 201 202 203 204 | static const u32 masks[5] = { NOPUSH_MASK_0 + (NOPUSH_MASK_1<<16), NOPUSH_MASK_2 + (NOPUSH_MASK_3<<16), NOPUSH_MASK_4 + (NOPUSH_MASK_5<<16), NOPUSH_MASK_6 + (NOPUSH_MASK_7<<16), NOPUSH_MASK_8 + (NOPUSH_MASK_9<<16) }; | | | 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | static const u32 masks[5] = { NOPUSH_MASK_0 + (NOPUSH_MASK_1<<16), NOPUSH_MASK_2 + (NOPUSH_MASK_3<<16), NOPUSH_MASK_4 + (NOPUSH_MASK_5<<16), NOPUSH_MASK_6 + (NOPUSH_MASK_7<<16), NOPUSH_MASK_8 + (NOPUSH_MASK_9<<16) }; assert( op<32*5 ); return (masks[op>>5] & (1<<(op&0x1F))); } #ifndef NDEBUG int sqlite3VdbeOpcodeNoPush(u8 op){ return opcodeNoPush(op); } |
︙ | ︙ | |||
963 964 965 966 967 968 969 | ** committed atomicly. */ #ifndef SQLITE_OMIT_DISKIO else{ int needSync = 0; char *zMaster = 0; /* File-name for the master journal */ char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); | | < | 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 | ** committed atomicly. */ #ifndef SQLITE_OMIT_DISKIO else{ int needSync = 0; char *zMaster = 0; /* File-name for the master journal */ char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt); OsFile *master = 0; /* Select a master journal file name */ do { u32 random; sqliteFree(zMaster); sqlite3Randomness(sizeof(random), &random); zMaster = sqlite3MPrintf("%s-mj%08X", zMainFile, random&0x7fffffff); if( !zMaster ){ return SQLITE_NOMEM; } }while( sqlite3Io.xFileExists(zMaster) ); /* Open the master journal. */ rc = sqlite3Io.xOpenExclusive(zMaster, &master, 0); if( rc!=SQLITE_OK ){ sqliteFree(zMaster); return rc; } /* Write the name of each database file in the transaction into the new |
︙ | ︙ | |||
999 1000 1001 1002 1003 1004 1005 | if( i==1 ) continue; /* Ignore the TEMP database */ if( pBt && sqlite3BtreeIsInTrans(pBt) ){ char const *zFile = sqlite3BtreeGetJournalname(pBt); if( zFile[0]==0 ) continue; /* Ignore :memory: databases */ if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){ needSync = 1; } | | | | | 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 | if( i==1 ) continue; /* Ignore the TEMP database */ if( pBt && sqlite3BtreeIsInTrans(pBt) ){ char const *zFile = sqlite3BtreeGetJournalname(pBt); if( zFile[0]==0 ) continue; /* Ignore :memory: databases */ if( !needSync && !sqlite3BtreeSyncDisabled(pBt) ){ needSync = 1; } rc = sqlite3Io.xWrite(master, zFile, strlen(zFile)+1); if( rc!=SQLITE_OK ){ sqlite3Io.xClose(&master); sqlite3Io.xDelete(zMaster); sqliteFree(zMaster); return rc; } } } /* Sync the master journal file. Before doing this, open the directory ** the master journal file is store in so that it gets synced too. */ zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt); rc = sqlite3Io.xOpenDirectory(zMainFile, master); if( rc!=SQLITE_OK || (needSync && (rc=sqlite3Io.xSync(master,0))!=SQLITE_OK) ){ sqlite3Io.xClose(&master); sqlite3Io.xDelete(zMaster); sqliteFree(zMaster); return rc; } /* Sync all the db files involved in the transaction. The same call |
︙ | ︙ |
Changes to test/attach.test.
︙ | ︙ | |||
8 9 10 11 12 13 14 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # # $Id: attach.test,v 1.41 2005/11/29 03:13:22 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl for {set i 2} {$i<=15} {incr i} { file delete -force test$i.db |
︙ | ︙ | |||
737 738 739 740 741 742 743 744 | } for {set i 2} {$i<=15} {incr i} { catch {db$i close} } db close file delete -force test2.db file delete -force no-such-file | < | 737 738 739 740 741 742 743 744 745 | } for {set i 2} {$i<=15} {incr i} { catch {db$i close} } db close file delete -force test2.db file delete -force no-such-file finish_test |