Fossil SCM
Update the built-in SQLite version to the 3.7.6 release.
Commit
4dde79b9e645d2f4feddecbb124eb7b2f24f8764
Parent
e5609b76cb5fdb3…
2 files changed
+981
-199
+1
-1
+981
-199
| --- src/sqlite3.c | ||
| +++ src/sqlite3.c | ||
| @@ -650,11 +650,11 @@ | ||
| 650 | 650 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 651 | 651 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 652 | 652 | */ |
| 653 | 653 | #define SQLITE_VERSION "3.7.6" |
| 654 | 654 | #define SQLITE_VERSION_NUMBER 3007006 |
| 655 | -#define SQLITE_SOURCE_ID "2011-04-07 15:24:08 bf78acb9dfacde0f08a5b3ceac13480f12a06168" | |
| 655 | +#define SQLITE_SOURCE_ID "2011-04-12 01:58:40 f9d43fa363d54beab6f45db005abac0a7c0c47a7" | |
| 656 | 656 | |
| 657 | 657 | /* |
| 658 | 658 | ** CAPI3REF: Run-Time Library Version Numbers |
| 659 | 659 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 660 | 660 | ** |
| @@ -9808,10 +9808,11 @@ | ||
| 9808 | 9808 | unsigned *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ |
| 9809 | 9809 | Table *pTable; /* The SQL table being indexed */ |
| 9810 | 9810 | int tnum; /* Page containing root of this index in database file */ |
| 9811 | 9811 | u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ |
| 9812 | 9812 | u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ |
| 9813 | + u8 bUnordered; /* Use this index for == or IN queries only */ | |
| 9813 | 9814 | char *zColAff; /* String defining the affinity of each column */ |
| 9814 | 9815 | Index *pNext; /* The next index associated with the same table */ |
| 9815 | 9816 | Schema *pSchema; /* Schema containing this index */ |
| 9816 | 9817 | u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ |
| 9817 | 9818 | char **azColl; /* Array of collation sequence names for index */ |
| @@ -11099,10 +11100,11 @@ | ||
| 11099 | 11100 | SQLITE_PRIVATE void sqlite3PrngSaveState(void); |
| 11100 | 11101 | SQLITE_PRIVATE void sqlite3PrngRestoreState(void); |
| 11101 | 11102 | SQLITE_PRIVATE void sqlite3PrngResetState(void); |
| 11102 | 11103 | SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*); |
| 11103 | 11104 | SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); |
| 11105 | +SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); | |
| 11104 | 11106 | SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); |
| 11105 | 11107 | SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); |
| 11106 | 11108 | SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*); |
| 11107 | 11109 | SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*); |
| 11108 | 11110 | SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); |
| @@ -12078,13 +12080,10 @@ | ||
| 12078 | 12080 | "OMIT_TRIGGER", |
| 12079 | 12081 | #endif |
| 12080 | 12082 | #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION |
| 12081 | 12083 | "OMIT_TRUNCATE_OPTIMIZATION", |
| 12082 | 12084 | #endif |
| 12083 | -#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT | |
| 12084 | - "OMIT_UNIQUE_ENFORCEMENT", | |
| 12085 | -#endif | |
| 12086 | 12085 | #ifdef SQLITE_OMIT_UTF16 |
| 12087 | 12086 | "OMIT_UTF16", |
| 12088 | 12087 | #endif |
| 12089 | 12088 | #ifdef SQLITE_OMIT_VACUUM |
| 12090 | 12089 | "OMIT_VACUUM", |
| @@ -16972,11 +16971,11 @@ | ||
| 16972 | 16971 | #ifdef SQLITE_DEBUG |
| 16973 | 16972 | if( p->trace ) os2MutexTrace(p, "leave"); |
| 16974 | 16973 | #endif |
| 16975 | 16974 | } |
| 16976 | 16975 | |
| 16977 | -SQLITE_PRIVATE SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ | |
| 16976 | +SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ | |
| 16978 | 16977 | static const sqlite3_mutex_methods sMutex = { |
| 16979 | 16978 | os2MutexInit, |
| 16980 | 16979 | os2MutexEnd, |
| 16981 | 16980 | os2MutexAlloc, |
| 16982 | 16981 | os2MutexFree, |
| @@ -20224,12 +20223,12 @@ | ||
| 20224 | 20223 | /* |
| 20225 | 20224 | ** Routine needed to support the testcase() macro. |
| 20226 | 20225 | */ |
| 20227 | 20226 | #ifdef SQLITE_COVERAGE_TEST |
| 20228 | 20227 | SQLITE_PRIVATE void sqlite3Coverage(int x){ |
| 20229 | - static int dummy = 0; | |
| 20230 | - dummy += x; | |
| 20228 | + static unsigned dummy = 0; | |
| 20229 | + dummy += (unsigned)x; | |
| 20231 | 20230 | } |
| 20232 | 20231 | #endif |
| 20233 | 20232 | |
| 20234 | 20233 | #ifndef SQLITE_OMIT_FLOATING_POINT |
| 20235 | 20234 | /* |
| @@ -22045,48 +22044,66 @@ | ||
| 22045 | 22044 | #endif /* !defined(_OS_COMMON_H_) */ |
| 22046 | 22045 | |
| 22047 | 22046 | /************** End of os_common.h *******************************************/ |
| 22048 | 22047 | /************** Continuing where we left off in os_os2.c *********************/ |
| 22049 | 22048 | |
| 22049 | +/* Forward references */ | |
| 22050 | +typedef struct os2File os2File; /* The file structure */ | |
| 22051 | +typedef struct os2ShmNode os2ShmNode; /* A shared descritive memory node */ | |
| 22052 | +typedef struct os2ShmLink os2ShmLink; /* A connection to shared-memory */ | |
| 22053 | + | |
| 22050 | 22054 | /* |
| 22051 | 22055 | ** The os2File structure is subclass of sqlite3_file specific for the OS/2 |
| 22052 | 22056 | ** protability layer. |
| 22053 | 22057 | */ |
| 22054 | -typedef struct os2File os2File; | |
| 22055 | 22058 | struct os2File { |
| 22056 | 22059 | const sqlite3_io_methods *pMethod; /* Always the first entry */ |
| 22057 | 22060 | HFILE h; /* Handle for accessing the file */ |
| 22058 | - char* pathToDel; /* Name of file to delete on close, NULL if not */ | |
| 22059 | - unsigned char locktype; /* Type of lock currently held on this file */ | |
| 22061 | + int flags; /* Flags provided to os2Open() */ | |
| 22062 | + int locktype; /* Type of lock currently held on this file */ | |
| 22063 | + int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ | |
| 22064 | + char *zFullPathCp; /* Full path name of this file */ | |
| 22065 | + os2ShmLink *pShmLink; /* Instance of shared memory on this file */ | |
| 22060 | 22066 | }; |
| 22061 | 22067 | |
| 22062 | 22068 | #define LOCK_TIMEOUT 10L /* the default locking timeout */ |
| 22063 | 22069 | |
| 22070 | +/* | |
| 22071 | +** Missing from some versions of the OS/2 toolkit - | |
| 22072 | +** used to allocate from high memory if possible | |
| 22073 | +*/ | |
| 22074 | +#ifndef OBJ_ANY | |
| 22075 | +# define OBJ_ANY 0x00000400 | |
| 22076 | +#endif | |
| 22077 | + | |
| 22064 | 22078 | /***************************************************************************** |
| 22065 | 22079 | ** The next group of routines implement the I/O methods specified |
| 22066 | 22080 | ** by the sqlite3_io_methods object. |
| 22067 | 22081 | ******************************************************************************/ |
| 22068 | 22082 | |
| 22069 | 22083 | /* |
| 22070 | 22084 | ** Close a file. |
| 22071 | 22085 | */ |
| 22072 | 22086 | static int os2Close( sqlite3_file *id ){ |
| 22073 | - APIRET rc = NO_ERROR; | |
| 22074 | - os2File *pFile; | |
| 22075 | - if( id && (pFile = (os2File*)id) != 0 ){ | |
| 22076 | - OSTRACE(( "CLOSE %d\n", pFile->h )); | |
| 22077 | - rc = DosClose( pFile->h ); | |
| 22078 | - pFile->locktype = NO_LOCK; | |
| 22079 | - if( pFile->pathToDel != NULL ){ | |
| 22080 | - rc = DosForceDelete( (PSZ)pFile->pathToDel ); | |
| 22081 | - free( pFile->pathToDel ); | |
| 22082 | - pFile->pathToDel = NULL; | |
| 22083 | - } | |
| 22084 | - id = 0; | |
| 22085 | - OpenCounter( -1 ); | |
| 22086 | - } | |
| 22087 | - | |
| 22087 | + APIRET rc; | |
| 22088 | + os2File *pFile = (os2File*)id; | |
| 22089 | + | |
| 22090 | + assert( id!=0 ); | |
| 22091 | + OSTRACE(( "CLOSE %d (%s)\n", pFile->h, pFile->zFullPathCp )); | |
| 22092 | + | |
| 22093 | + rc = DosClose( pFile->h ); | |
| 22094 | + | |
| 22095 | + if( pFile->flags & SQLITE_OPEN_DELETEONCLOSE ) | |
| 22096 | + DosForceDelete( (PSZ)pFile->zFullPathCp ); | |
| 22097 | + | |
| 22098 | + free( pFile->zFullPathCp ); | |
| 22099 | + pFile->zFullPathCp = NULL; | |
| 22100 | + pFile->locktype = NO_LOCK; | |
| 22101 | + pFile->h = (HFILE)-1; | |
| 22102 | + pFile->flags = 0; | |
| 22103 | + | |
| 22104 | + OpenCounter( -1 ); | |
| 22088 | 22105 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
| 22089 | 22106 | } |
| 22090 | 22107 | |
| 22091 | 22108 | /* |
| 22092 | 22109 | ** Read data from a file into a buffer. Return SQLITE_OK if all |
| @@ -22155,14 +22172,25 @@ | ||
| 22155 | 22172 | |
| 22156 | 22173 | /* |
| 22157 | 22174 | ** Truncate an open file to a specified size |
| 22158 | 22175 | */ |
| 22159 | 22176 | static int os2Truncate( sqlite3_file *id, i64 nByte ){ |
| 22160 | - APIRET rc = NO_ERROR; | |
| 22177 | + APIRET rc; | |
| 22161 | 22178 | os2File *pFile = (os2File*)id; |
| 22179 | + assert( id!=0 ); | |
| 22162 | 22180 | OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte )); |
| 22163 | 22181 | SimulateIOError( return SQLITE_IOERR_TRUNCATE ); |
| 22182 | + | |
| 22183 | + /* If the user has configured a chunk-size for this file, truncate the | |
| 22184 | + ** file so that it consists of an integer number of chunks (i.e. the | |
| 22185 | + ** actual file size after the operation may be larger than the requested | |
| 22186 | + ** size). | |
| 22187 | + */ | |
| 22188 | + if( pFile->szChunk ){ | |
| 22189 | + nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; | |
| 22190 | + } | |
| 22191 | + | |
| 22164 | 22192 | rc = DosSetFileSize( pFile->h, nByte ); |
| 22165 | 22193 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE; |
| 22166 | 22194 | } |
| 22167 | 22195 | |
| 22168 | 22196 | #ifdef SQLITE_TEST |
| @@ -22522,10 +22550,24 @@ | ||
| 22522 | 22550 | *(int*)pArg = ((os2File*)id)->locktype; |
| 22523 | 22551 | OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n", |
| 22524 | 22552 | ((os2File*)id)->h, ((os2File*)id)->locktype )); |
| 22525 | 22553 | return SQLITE_OK; |
| 22526 | 22554 | } |
| 22555 | + case SQLITE_FCNTL_CHUNK_SIZE: { | |
| 22556 | + ((os2File*)id)->szChunk = *(int*)pArg; | |
| 22557 | + return SQLITE_OK; | |
| 22558 | + } | |
| 22559 | + case SQLITE_FCNTL_SIZE_HINT: { | |
| 22560 | + sqlite3_int64 sz = *(sqlite3_int64*)pArg; | |
| 22561 | + SimulateIOErrorBenign(1); | |
| 22562 | + os2Truncate(id, sz); | |
| 22563 | + SimulateIOErrorBenign(0); | |
| 22564 | + return SQLITE_OK; | |
| 22565 | + } | |
| 22566 | + case SQLITE_FCNTL_SYNC_OMITTED: { | |
| 22567 | + return SQLITE_OK; | |
| 22568 | + } | |
| 22527 | 22569 | } |
| 22528 | 22570 | return SQLITE_NOTFOUND; |
| 22529 | 22571 | } |
| 22530 | 22572 | |
| 22531 | 22573 | /* |
| @@ -22537,18 +22579,20 @@ | ||
| 22537 | 22579 | ** if two files are created in the same file-system directory (i.e. |
| 22538 | 22580 | ** a database and its journal file) that the sector size will be the |
| 22539 | 22581 | ** same for both. |
| 22540 | 22582 | */ |
| 22541 | 22583 | static int os2SectorSize(sqlite3_file *id){ |
| 22584 | + UNUSED_PARAMETER(id); | |
| 22542 | 22585 | return SQLITE_DEFAULT_SECTOR_SIZE; |
| 22543 | 22586 | } |
| 22544 | 22587 | |
| 22545 | 22588 | /* |
| 22546 | 22589 | ** Return a vector of device characteristics. |
| 22547 | 22590 | */ |
| 22548 | 22591 | static int os2DeviceCharacteristics(sqlite3_file *id){ |
| 22549 | - return 0; | |
| 22592 | + UNUSED_PARAMETER(id); | |
| 22593 | + return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; | |
| 22550 | 22594 | } |
| 22551 | 22595 | |
| 22552 | 22596 | |
| 22553 | 22597 | /* |
| 22554 | 22598 | ** Character set conversion objects used by conversion routines. |
| @@ -22630,17 +22674,668 @@ | ||
| 22630 | 22674 | /* determine string for the conversion of UTF-8 which is CP1208 */ |
| 22631 | 22675 | UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH ); |
| 22632 | 22676 | |
| 22633 | 22677 | return out; |
| 22634 | 22678 | } |
| 22679 | + | |
| 22680 | + | |
| 22681 | +#ifndef SQLITE_OMIT_WAL | |
| 22682 | + | |
| 22683 | +/* | |
| 22684 | +** Use main database file for interprocess locking. If un-defined | |
| 22685 | +** a separate file is created for this purpose. The file will be | |
| 22686 | +** used only to set file locks. There will be no data written to it. | |
| 22687 | +*/ | |
| 22688 | +#define SQLITE_OS2_NO_WAL_LOCK_FILE | |
| 22689 | + | |
| 22690 | +#if 0 | |
| 22691 | +static void _ERR_TRACE( const char *fmt, ... ) { | |
| 22692 | + va_list ap; | |
| 22693 | + va_start(ap, fmt); | |
| 22694 | + vfprintf(stderr, fmt, ap); | |
| 22695 | + fflush(stderr); | |
| 22696 | +} | |
| 22697 | +#define ERR_TRACE(rc, msg) \ | |
| 22698 | + if( (rc) != SQLITE_OK ) _ERR_TRACE msg; | |
| 22699 | +#else | |
| 22700 | +#define ERR_TRACE(rc, msg) | |
| 22701 | +#endif | |
| 22702 | + | |
| 22703 | +/* | |
| 22704 | +** Helper functions to obtain and relinquish the global mutex. The | |
| 22705 | +** global mutex is used to protect os2ShmNodeList. | |
| 22706 | +** | |
| 22707 | +** Function os2ShmMutexHeld() is used to assert() that the global mutex | |
| 22708 | +** is held when required. This function is only used as part of assert() | |
| 22709 | +** statements. e.g. | |
| 22710 | +** | |
| 22711 | +** os2ShmEnterMutex() | |
| 22712 | +** assert( os2ShmMutexHeld() ); | |
| 22713 | +** os2ShmLeaveMutex() | |
| 22714 | +*/ | |
| 22715 | +static void os2ShmEnterMutex(void){ | |
| 22716 | + sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); | |
| 22717 | +} | |
| 22718 | +static void os2ShmLeaveMutex(void){ | |
| 22719 | + sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); | |
| 22720 | +} | |
| 22721 | +#ifdef SQLITE_DEBUG | |
| 22722 | +static int os2ShmMutexHeld(void) { | |
| 22723 | + return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); | |
| 22724 | +} | |
| 22725 | +int GetCurrentProcessId(void) { | |
| 22726 | + PPIB pib; | |
| 22727 | + DosGetInfoBlocks(NULL, &pib); | |
| 22728 | + return (int)pib->pib_ulpid; | |
| 22729 | +} | |
| 22730 | +#endif | |
| 22731 | + | |
| 22732 | +/* | |
| 22733 | +** Object used to represent a the shared memory area for a single log file. | |
| 22734 | +** When multiple threads all reference the same log-summary, each thread has | |
| 22735 | +** its own os2File object, but they all point to a single instance of this | |
| 22736 | +** object. In other words, each log-summary is opened only once per process. | |
| 22737 | +** | |
| 22738 | +** os2ShmMutexHeld() must be true when creating or destroying | |
| 22739 | +** this object or while reading or writing the following fields: | |
| 22740 | +** | |
| 22741 | +** nRef | |
| 22742 | +** pNext | |
| 22743 | +** | |
| 22744 | +** The following fields are read-only after the object is created: | |
| 22745 | +** | |
| 22746 | +** szRegion | |
| 22747 | +** hLockFile | |
| 22748 | +** shmBaseName | |
| 22749 | +** | |
| 22750 | +** Either os2ShmNode.mutex must be held or os2ShmNode.nRef==0 and | |
| 22751 | +** os2ShmMutexHeld() is true when reading or writing any other field | |
| 22752 | +** in this structure. | |
| 22753 | +** | |
| 22754 | +*/ | |
| 22755 | +struct os2ShmNode { | |
| 22756 | + sqlite3_mutex *mutex; /* Mutex to access this object */ | |
| 22757 | + os2ShmNode *pNext; /* Next in list of all os2ShmNode objects */ | |
| 22758 | + | |
| 22759 | + int szRegion; /* Size of shared-memory regions */ | |
| 22760 | + | |
| 22761 | + int nRegion; /* Size of array apRegion */ | |
| 22762 | + void **apRegion; /* Array of pointers to shared-memory regions */ | |
| 22763 | + | |
| 22764 | + int nRef; /* Number of os2ShmLink objects pointing to this */ | |
| 22765 | + os2ShmLink *pFirst; /* First os2ShmLink object pointing to this */ | |
| 22766 | + | |
| 22767 | + HFILE hLockFile; /* File used for inter-process memory locking */ | |
| 22768 | + char shmBaseName[1]; /* Name of the memory object !!! must last !!! */ | |
| 22769 | +}; | |
| 22770 | + | |
| 22771 | + | |
| 22772 | +/* | |
| 22773 | +** Structure used internally by this VFS to record the state of an | |
| 22774 | +** open shared memory connection. | |
| 22775 | +** | |
| 22776 | +** The following fields are initialized when this object is created and | |
| 22777 | +** are read-only thereafter: | |
| 22778 | +** | |
| 22779 | +** os2Shm.pShmNode | |
| 22780 | +** os2Shm.id | |
| 22781 | +** | |
| 22782 | +** All other fields are read/write. The os2Shm.pShmNode->mutex must be held | |
| 22783 | +** while accessing any read/write fields. | |
| 22784 | +*/ | |
| 22785 | +struct os2ShmLink { | |
| 22786 | + os2ShmNode *pShmNode; /* The underlying os2ShmNode object */ | |
| 22787 | + os2ShmLink *pNext; /* Next os2Shm with the same os2ShmNode */ | |
| 22788 | + u32 sharedMask; /* Mask of shared locks held */ | |
| 22789 | + u32 exclMask; /* Mask of exclusive locks held */ | |
| 22790 | +#ifdef SQLITE_DEBUG | |
| 22791 | + u8 id; /* Id of this connection with its os2ShmNode */ | |
| 22792 | +#endif | |
| 22793 | +}; | |
| 22794 | + | |
| 22795 | + | |
| 22796 | +/* | |
| 22797 | +** A global list of all os2ShmNode objects. | |
| 22798 | +** | |
| 22799 | +** The os2ShmMutexHeld() must be true while reading or writing this list. | |
| 22800 | +*/ | |
| 22801 | +static os2ShmNode *os2ShmNodeList = NULL; | |
| 22802 | + | |
| 22803 | +/* | |
| 22804 | +** Constants used for locking | |
| 22805 | +*/ | |
| 22806 | +#ifdef SQLITE_OS2_NO_WAL_LOCK_FILE | |
| 22807 | +#define OS2_SHM_BASE (PENDING_BYTE + 0x10000) /* first lock byte */ | |
| 22808 | +#else | |
| 22809 | +#define OS2_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ | |
| 22810 | +#endif | |
| 22811 | + | |
| 22812 | +#define OS2_SHM_DMS (OS2_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ | |
| 22813 | + | |
| 22814 | +/* | |
| 22815 | +** Apply advisory locks for all n bytes beginning at ofst. | |
| 22816 | +*/ | |
| 22817 | +#define _SHM_UNLCK 1 /* no lock */ | |
| 22818 | +#define _SHM_RDLCK 2 /* shared lock, no wait */ | |
| 22819 | +#define _SHM_WRLCK 3 /* exlusive lock, no wait */ | |
| 22820 | +#define _SHM_WRLCK_WAIT 4 /* exclusive lock, wait */ | |
| 22821 | +static int os2ShmSystemLock( | |
| 22822 | + os2ShmNode *pNode, /* Apply locks to this open shared-memory segment */ | |
| 22823 | + int lockType, /* _SHM_UNLCK, _SHM_RDLCK, _SHM_WRLCK or _SHM_WRLCK_WAIT */ | |
| 22824 | + int ofst, /* Offset to first byte to be locked/unlocked */ | |
| 22825 | + int nByte /* Number of bytes to lock or unlock */ | |
| 22826 | +){ | |
| 22827 | + APIRET rc; | |
| 22828 | + FILELOCK area; | |
| 22829 | + ULONG mode, timeout; | |
| 22830 | + | |
| 22831 | + /* Access to the os2ShmNode object is serialized by the caller */ | |
| 22832 | + assert( sqlite3_mutex_held(pNode->mutex) || pNode->nRef==0 ); | |
| 22833 | + | |
| 22834 | + mode = 1; /* shared lock */ | |
| 22835 | + timeout = 0; /* no wait */ | |
| 22836 | + area.lOffset = ofst; | |
| 22837 | + area.lRange = nByte; | |
| 22838 | + | |
| 22839 | + switch( lockType ) { | |
| 22840 | + case _SHM_WRLCK_WAIT: | |
| 22841 | + timeout = (ULONG)-1; /* wait forever */ | |
| 22842 | + case _SHM_WRLCK: | |
| 22843 | + mode = 0; /* exclusive lock */ | |
| 22844 | + case _SHM_RDLCK: | |
| 22845 | + rc = DosSetFileLocks(pNode->hLockFile, | |
| 22846 | + NULL, &area, timeout, mode); | |
| 22847 | + break; | |
| 22848 | + /* case _SHM_UNLCK: */ | |
| 22849 | + default: | |
| 22850 | + rc = DosSetFileLocks(pNode->hLockFile, | |
| 22851 | + &area, NULL, 0, 0); | |
| 22852 | + break; | |
| 22853 | + } | |
| 22854 | + | |
| 22855 | + OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n", | |
| 22856 | + pNode->hLockFile, | |
| 22857 | + rc==SQLITE_OK ? "ok" : "failed", | |
| 22858 | + lockType==_SHM_UNLCK ? "Unlock" : "Lock", | |
| 22859 | + rc)); | |
| 22860 | + | |
| 22861 | + ERR_TRACE(rc, ("os2ShmSystemLock: %d %s\n", rc, pNode->shmBaseName)) | |
| 22862 | + | |
| 22863 | + return ( rc == 0 ) ? SQLITE_OK : SQLITE_BUSY; | |
| 22864 | +} | |
| 22865 | + | |
| 22866 | +/* | |
| 22867 | +** Find an os2ShmNode in global list or allocate a new one, if not found. | |
| 22868 | +** | |
| 22869 | +** This is not a VFS shared-memory method; it is a utility function called | |
| 22870 | +** by VFS shared-memory methods. | |
| 22871 | +*/ | |
| 22872 | +static int os2OpenSharedMemory( os2File *fd, int szRegion ) { | |
| 22873 | + os2ShmLink *pLink; | |
| 22874 | + os2ShmNode *pNode; | |
| 22875 | + int cbShmName, rc = SQLITE_OK; | |
| 22876 | + char shmName[CCHMAXPATH + 30]; | |
| 22877 | +#ifndef SQLITE_OS2_NO_WAL_LOCK_FILE | |
| 22878 | + ULONG action; | |
| 22879 | +#endif | |
| 22880 | + | |
| 22881 | + /* We need some additional space at the end to append the region number */ | |
| 22882 | + cbShmName = sprintf(shmName, "\\SHAREMEM\\%s", fd->zFullPathCp ); | |
| 22883 | + if( cbShmName >= CCHMAXPATH-8 ) | |
| 22884 | + return SQLITE_IOERR_SHMOPEN; | |
| 22885 | + | |
| 22886 | + /* Replace colon in file name to form a valid shared memory name */ | |
| 22887 | + shmName[10+1] = '!'; | |
| 22888 | + | |
| 22889 | + /* Allocate link object (we free it later in case of failure) */ | |
| 22890 | + pLink = sqlite3_malloc( sizeof(*pLink) ); | |
| 22891 | + if( !pLink ) | |
| 22892 | + return SQLITE_NOMEM; | |
| 22893 | + | |
| 22894 | + /* Access node list */ | |
| 22895 | + os2ShmEnterMutex(); | |
| 22896 | + | |
| 22897 | + /* Find node by it's shared memory base name */ | |
| 22898 | + for( pNode = os2ShmNodeList; | |
| 22899 | + pNode && stricmp(shmName, pNode->shmBaseName) != 0; | |
| 22900 | + pNode = pNode->pNext ) ; | |
| 22901 | + | |
| 22902 | + /* Not found: allocate a new node */ | |
| 22903 | + if( !pNode ) { | |
| 22904 | + pNode = sqlite3_malloc( sizeof(*pNode) + cbShmName ); | |
| 22905 | + if( pNode ) { | |
| 22906 | + memset(pNode, 0, sizeof(*pNode) ); | |
| 22907 | + pNode->szRegion = szRegion; | |
| 22908 | + pNode->hLockFile = (HFILE)-1; | |
| 22909 | + strcpy(pNode->shmBaseName, shmName); | |
| 22910 | + | |
| 22911 | +#ifdef SQLITE_OS2_NO_WAL_LOCK_FILE | |
| 22912 | + if( DosDupHandle(fd->h, &pNode->hLockFile) != 0 ) { | |
| 22913 | +#else | |
| 22914 | + sprintf(shmName, "%s-lck", fd->zFullPathCp); | |
| 22915 | + if( DosOpen((PSZ)shmName, &pNode->hLockFile, &action, 0, FILE_NORMAL, | |
| 22916 | + OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW, | |
| 22917 | + OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE | | |
| 22918 | + OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR, | |
| 22919 | + NULL) != 0 ) { | |
| 22920 | +#endif | |
| 22921 | + sqlite3_free(pNode); | |
| 22922 | + rc = SQLITE_IOERR; | |
| 22923 | + } else { | |
| 22924 | + pNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); | |
| 22925 | + if( !pNode->mutex ) { | |
| 22926 | + sqlite3_free(pNode); | |
| 22927 | + rc = SQLITE_NOMEM; | |
| 22928 | + } | |
| 22929 | + } | |
| 22930 | + } else { | |
| 22931 | + rc = SQLITE_NOMEM; | |
| 22932 | + } | |
| 22933 | + | |
| 22934 | + if( rc == SQLITE_OK ) { | |
| 22935 | + pNode->pNext = os2ShmNodeList; | |
| 22936 | + os2ShmNodeList = pNode; | |
| 22937 | + } else { | |
| 22938 | + pNode = NULL; | |
| 22939 | + } | |
| 22940 | + } else if( pNode->szRegion != szRegion ) { | |
| 22941 | + rc = SQLITE_IOERR_SHMSIZE; | |
| 22942 | + pNode = NULL; | |
| 22943 | + } | |
| 22944 | + | |
| 22945 | + if( pNode ) { | |
| 22946 | + sqlite3_mutex_enter(pNode->mutex); | |
| 22947 | + | |
| 22948 | + memset(pLink, 0, sizeof(*pLink)); | |
| 22949 | + | |
| 22950 | + pLink->pShmNode = pNode; | |
| 22951 | + pLink->pNext = pNode->pFirst; | |
| 22952 | + pNode->pFirst = pLink; | |
| 22953 | + pNode->nRef++; | |
| 22954 | + | |
| 22955 | + fd->pShmLink = pLink; | |
| 22956 | + | |
| 22957 | + sqlite3_mutex_leave(pNode->mutex); | |
| 22958 | + | |
| 22959 | + } else { | |
| 22960 | + /* Error occured. Free our link object. */ | |
| 22961 | + sqlite3_free(pLink); | |
| 22962 | + } | |
| 22963 | + | |
| 22964 | + os2ShmLeaveMutex(); | |
| 22965 | + | |
| 22966 | + ERR_TRACE(rc, ("os2OpenSharedMemory: %d %s\n", rc, fd->zFullPathCp)) | |
| 22967 | + | |
| 22968 | + return rc; | |
| 22969 | +} | |
| 22970 | + | |
| 22971 | +/* | |
| 22972 | +** Purge the os2ShmNodeList list of all entries with nRef==0. | |
| 22973 | +** | |
| 22974 | +** This is not a VFS shared-memory method; it is a utility function called | |
| 22975 | +** by VFS shared-memory methods. | |
| 22976 | +*/ | |
| 22977 | +static void os2PurgeShmNodes( int deleteFlag ) { | |
| 22978 | + os2ShmNode *pNode; | |
| 22979 | + os2ShmNode **ppNode; | |
| 22980 | + | |
| 22981 | + os2ShmEnterMutex(); | |
| 22982 | + | |
| 22983 | + ppNode = &os2ShmNodeList; | |
| 22984 | + | |
| 22985 | + while( *ppNode ) { | |
| 22986 | + pNode = *ppNode; | |
| 22987 | + | |
| 22988 | + if( pNode->nRef == 0 ) { | |
| 22989 | + *ppNode = pNode->pNext; | |
| 22990 | + | |
| 22991 | + if( pNode->apRegion ) { | |
| 22992 | + /* Prevent other processes from resizing the shared memory */ | |
| 22993 | + os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1); | |
| 22994 | + | |
| 22995 | + while( pNode->nRegion-- ) { | |
| 22996 | +#ifdef SQLITE_DEBUG | |
| 22997 | + int rc = | |
| 22998 | +#endif | |
| 22999 | + DosFreeMem(pNode->apRegion[pNode->nRegion]); | |
| 23000 | + | |
| 23001 | + OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n", | |
| 23002 | + (int)GetCurrentProcessId(), pNode->nRegion, | |
| 23003 | + rc == 0 ? "ok" : "failed")); | |
| 23004 | + } | |
| 23005 | + | |
| 23006 | + /* Allow other processes to resize the shared memory */ | |
| 23007 | + os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1); | |
| 23008 | + | |
| 23009 | + sqlite3_free(pNode->apRegion); | |
| 23010 | + } | |
| 23011 | + | |
| 23012 | + DosClose(pNode->hLockFile); | |
| 23013 | + | |
| 23014 | +#ifndef SQLITE_OS2_NO_WAL_LOCK_FILE | |
| 23015 | + if( deleteFlag ) { | |
| 23016 | + char fileName[CCHMAXPATH]; | |
| 23017 | + /* Skip "\\SHAREMEM\\" */ | |
| 23018 | + sprintf(fileName, "%s-lck", pNode->shmBaseName + 10); | |
| 23019 | + /* restore colon */ | |
| 23020 | + fileName[1] = ':'; | |
| 23021 | + | |
| 23022 | + DosForceDelete(fileName); | |
| 23023 | + } | |
| 23024 | +#endif | |
| 23025 | + | |
| 23026 | + sqlite3_mutex_free(pNode->mutex); | |
| 23027 | + | |
| 23028 | + sqlite3_free(pNode); | |
| 23029 | + | |
| 23030 | + } else { | |
| 23031 | + ppNode = &pNode->pNext; | |
| 23032 | + } | |
| 23033 | + } | |
| 23034 | + | |
| 23035 | + os2ShmLeaveMutex(); | |
| 23036 | +} | |
| 23037 | + | |
| 23038 | +/* | |
| 23039 | +** This function is called to obtain a pointer to region iRegion of the | |
| 23040 | +** shared-memory associated with the database file id. Shared-memory regions | |
| 23041 | +** are numbered starting from zero. Each shared-memory region is szRegion | |
| 23042 | +** bytes in size. | |
| 23043 | +** | |
| 23044 | +** If an error occurs, an error code is returned and *pp is set to NULL. | |
| 23045 | +** | |
| 23046 | +** Otherwise, if the bExtend parameter is 0 and the requested shared-memory | |
| 23047 | +** region has not been allocated (by any client, including one running in a | |
| 23048 | +** separate process), then *pp is set to NULL and SQLITE_OK returned. If | |
| 23049 | +** bExtend is non-zero and the requested shared-memory region has not yet | |
| 23050 | +** been allocated, it is allocated by this function. | |
| 23051 | +** | |
| 23052 | +** If the shared-memory region has already been allocated or is allocated by | |
| 23053 | +** this call as described above, then it is mapped into this processes | |
| 23054 | +** address space (if it is not already), *pp is set to point to the mapped | |
| 23055 | +** memory and SQLITE_OK returned. | |
| 23056 | +*/ | |
| 23057 | +static int os2ShmMap( | |
| 23058 | + sqlite3_file *id, /* Handle open on database file */ | |
| 23059 | + int iRegion, /* Region to retrieve */ | |
| 23060 | + int szRegion, /* Size of regions */ | |
| 23061 | + int bExtend, /* True to extend block if necessary */ | |
| 23062 | + void volatile **pp /* OUT: Mapped memory */ | |
| 23063 | +){ | |
| 23064 | + PVOID pvTemp; | |
| 23065 | + void **apRegion; | |
| 23066 | + os2ShmNode *pNode; | |
| 23067 | + int n, rc = SQLITE_OK; | |
| 23068 | + char shmName[CCHMAXPATH]; | |
| 23069 | + os2File *pFile = (os2File*)id; | |
| 23070 | + | |
| 23071 | + *pp = NULL; | |
| 23072 | + | |
| 23073 | + if( !pFile->pShmLink ) | |
| 23074 | + rc = os2OpenSharedMemory( pFile, szRegion ); | |
| 23075 | + | |
| 23076 | + if( rc == SQLITE_OK ) { | |
| 23077 | + pNode = pFile->pShmLink->pShmNode ; | |
| 23078 | + | |
| 23079 | + sqlite3_mutex_enter(pNode->mutex); | |
| 23080 | + | |
| 23081 | + assert( szRegion==pNode->szRegion ); | |
| 23082 | + | |
| 23083 | + /* Unmapped region ? */ | |
| 23084 | + if( iRegion >= pNode->nRegion ) { | |
| 23085 | + /* Prevent other processes from resizing the shared memory */ | |
| 23086 | + os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1); | |
| 23087 | + | |
| 23088 | + apRegion = sqlite3_realloc( | |
| 23089 | + pNode->apRegion, (iRegion + 1) * sizeof(apRegion[0])); | |
| 23090 | + | |
| 23091 | + if( apRegion ) { | |
| 23092 | + pNode->apRegion = apRegion; | |
| 23093 | + | |
| 23094 | + while( pNode->nRegion <= iRegion ) { | |
| 23095 | + sprintf(shmName, "%s-%u", | |
| 23096 | + pNode->shmBaseName, pNode->nRegion); | |
| 23097 | + | |
| 23098 | + if( DosGetNamedSharedMem(&pvTemp, (PSZ)shmName, | |
| 23099 | + PAG_READ | PAG_WRITE) != NO_ERROR ) { | |
| 23100 | + if( !bExtend ) | |
| 23101 | + break; | |
| 23102 | + | |
| 23103 | + if( DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion, | |
| 23104 | + PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_ANY) != NO_ERROR && | |
| 23105 | + DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion, | |
| 23106 | + PAG_READ | PAG_WRITE | PAG_COMMIT) != NO_ERROR ) { | |
| 23107 | + rc = SQLITE_NOMEM; | |
| 23108 | + break; | |
| 23109 | + } | |
| 23110 | + } | |
| 23111 | + | |
| 23112 | + apRegion[pNode->nRegion++] = pvTemp; | |
| 23113 | + } | |
| 23114 | + | |
| 23115 | + /* zero out remaining entries */ | |
| 23116 | + for( n = pNode->nRegion; n <= iRegion; n++ ) | |
| 23117 | + pNode->apRegion[n] = NULL; | |
| 23118 | + | |
| 23119 | + /* Return this region (maybe zero) */ | |
| 23120 | + *pp = pNode->apRegion[iRegion]; | |
| 23121 | + } else { | |
| 23122 | + rc = SQLITE_NOMEM; | |
| 23123 | + } | |
| 23124 | + | |
| 23125 | + /* Allow other processes to resize the shared memory */ | |
| 23126 | + os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1); | |
| 23127 | + | |
| 23128 | + } else { | |
| 23129 | + /* Region has been mapped previously */ | |
| 23130 | + *pp = pNode->apRegion[iRegion]; | |
| 23131 | + } | |
| 23132 | + | |
| 23133 | + sqlite3_mutex_leave(pNode->mutex); | |
| 23134 | + } | |
| 23135 | + | |
| 23136 | + ERR_TRACE(rc, ("os2ShmMap: %s iRgn = %d, szRgn = %d, bExt = %d : %d\n", | |
| 23137 | + pFile->zFullPathCp, iRegion, szRegion, bExtend, rc)) | |
| 23138 | + | |
| 23139 | + return rc; | |
| 23140 | +} | |
| 23141 | + | |
| 23142 | +/* | |
| 23143 | +** Close a connection to shared-memory. Delete the underlying | |
| 23144 | +** storage if deleteFlag is true. | |
| 23145 | +** | |
| 23146 | +** If there is no shared memory associated with the connection then this | |
| 23147 | +** routine is a harmless no-op. | |
| 23148 | +*/ | |
| 23149 | +static int os2ShmUnmap( | |
| 23150 | + sqlite3_file *id, /* The underlying database file */ | |
| 23151 | + int deleteFlag /* Delete shared-memory if true */ | |
| 23152 | +){ | |
| 23153 | + os2File *pFile = (os2File*)id; | |
| 23154 | + os2ShmLink *pLink = pFile->pShmLink; | |
| 23155 | + | |
| 23156 | + if( pLink ) { | |
| 23157 | + int nRef = -1; | |
| 23158 | + os2ShmLink **ppLink; | |
| 23159 | + os2ShmNode *pNode = pLink->pShmNode; | |
| 23160 | + | |
| 23161 | + sqlite3_mutex_enter(pNode->mutex); | |
| 23162 | + | |
| 23163 | + for( ppLink = &pNode->pFirst; | |
| 23164 | + *ppLink && *ppLink != pLink; | |
| 23165 | + ppLink = &(*ppLink)->pNext ) ; | |
| 23166 | + | |
| 23167 | + assert(*ppLink); | |
| 23168 | + | |
| 23169 | + if( *ppLink ) { | |
| 23170 | + *ppLink = pLink->pNext; | |
| 23171 | + nRef = --pNode->nRef; | |
| 23172 | + } else { | |
| 23173 | + ERR_TRACE(1, ("os2ShmUnmap: link not found ! %s\n", | |
| 23174 | + pNode->shmBaseName)) | |
| 23175 | + } | |
| 23176 | + | |
| 23177 | + pFile->pShmLink = NULL; | |
| 23178 | + sqlite3_free(pLink); | |
| 23179 | + | |
| 23180 | + sqlite3_mutex_leave(pNode->mutex); | |
| 23181 | + | |
| 23182 | + if( nRef == 0 ) | |
| 23183 | + os2PurgeShmNodes( deleteFlag ); | |
| 23184 | + } | |
| 23185 | + | |
| 23186 | + return SQLITE_OK; | |
| 23187 | +} | |
| 23188 | + | |
| 23189 | +/* | |
| 23190 | +** Change the lock state for a shared-memory segment. | |
| 23191 | +** | |
| 23192 | +** Note that the relationship between SHAREd and EXCLUSIVE locks is a little | |
| 23193 | +** different here than in posix. In xShmLock(), one can go from unlocked | |
| 23194 | +** to shared and back or from unlocked to exclusive and back. But one may | |
| 23195 | +** not go from shared to exclusive or from exclusive to shared. | |
| 23196 | +*/ | |
| 23197 | +static int os2ShmLock( | |
| 23198 | + sqlite3_file *id, /* Database file holding the shared memory */ | |
| 23199 | + int ofst, /* First lock to acquire or release */ | |
| 23200 | + int n, /* Number of locks to acquire or release */ | |
| 23201 | + int flags /* What to do with the lock */ | |
| 23202 | +){ | |
| 23203 | + u32 mask; /* Mask of locks to take or release */ | |
| 23204 | + int rc = SQLITE_OK; /* Result code */ | |
| 23205 | + os2File *pFile = (os2File*)id; | |
| 23206 | + os2ShmLink *p = pFile->pShmLink; /* The shared memory being locked */ | |
| 23207 | + os2ShmLink *pX; /* For looping over all siblings */ | |
| 23208 | + os2ShmNode *pShmNode = p->pShmNode; /* Our node */ | |
| 23209 | + | |
| 23210 | + assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); | |
| 23211 | + assert( n>=1 ); | |
| 23212 | + assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED) | |
| 23213 | + || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE) | |
| 23214 | + || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) | |
| 23215 | + || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); | |
| 23216 | + assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); | |
| 23217 | + | |
| 23218 | + mask = (u32)((1U<<(ofst+n)) - (1U<<ofst)); | |
| 23219 | + assert( n>1 || mask==(1<<ofst) ); | |
| 23220 | + | |
| 23221 | + | |
| 23222 | + sqlite3_mutex_enter(pShmNode->mutex); | |
| 23223 | + | |
| 23224 | + if( flags & SQLITE_SHM_UNLOCK ){ | |
| 23225 | + u32 allMask = 0; /* Mask of locks held by siblings */ | |
| 23226 | + | |
| 23227 | + /* See if any siblings hold this same lock */ | |
| 23228 | + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ | |
| 23229 | + if( pX==p ) continue; | |
| 23230 | + assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); | |
| 23231 | + allMask |= pX->sharedMask; | |
| 23232 | + } | |
| 23233 | + | |
| 23234 | + /* Unlock the system-level locks */ | |
| 23235 | + if( (mask & allMask)==0 ){ | |
| 23236 | + rc = os2ShmSystemLock(pShmNode, _SHM_UNLCK, ofst+OS2_SHM_BASE, n); | |
| 23237 | + }else{ | |
| 23238 | + rc = SQLITE_OK; | |
| 23239 | + } | |
| 23240 | + | |
| 23241 | + /* Undo the local locks */ | |
| 23242 | + if( rc==SQLITE_OK ){ | |
| 23243 | + p->exclMask &= ~mask; | |
| 23244 | + p->sharedMask &= ~mask; | |
| 23245 | + } | |
| 23246 | + }else if( flags & SQLITE_SHM_SHARED ){ | |
| 23247 | + u32 allShared = 0; /* Union of locks held by connections other than "p" */ | |
| 23248 | + | |
| 23249 | + /* Find out which shared locks are already held by sibling connections. | |
| 23250 | + ** If any sibling already holds an exclusive lock, go ahead and return | |
| 23251 | + ** SQLITE_BUSY. | |
| 23252 | + */ | |
| 23253 | + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ | |
| 23254 | + if( (pX->exclMask & mask)!=0 ){ | |
| 23255 | + rc = SQLITE_BUSY; | |
| 23256 | + break; | |
| 23257 | + } | |
| 23258 | + allShared |= pX->sharedMask; | |
| 23259 | + } | |
| 23260 | + | |
| 23261 | + /* Get shared locks at the system level, if necessary */ | |
| 23262 | + if( rc==SQLITE_OK ){ | |
| 23263 | + if( (allShared & mask)==0 ){ | |
| 23264 | + rc = os2ShmSystemLock(pShmNode, _SHM_RDLCK, ofst+OS2_SHM_BASE, n); | |
| 23265 | + }else{ | |
| 23266 | + rc = SQLITE_OK; | |
| 23267 | + } | |
| 23268 | + } | |
| 23269 | + | |
| 23270 | + /* Get the local shared locks */ | |
| 23271 | + if( rc==SQLITE_OK ){ | |
| 23272 | + p->sharedMask |= mask; | |
| 23273 | + } | |
| 23274 | + }else{ | |
| 23275 | + /* Make sure no sibling connections hold locks that will block this | |
| 23276 | + ** lock. If any do, return SQLITE_BUSY right away. | |
| 23277 | + */ | |
| 23278 | + for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ | |
| 23279 | + if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ | |
| 23280 | + rc = SQLITE_BUSY; | |
| 23281 | + break; | |
| 23282 | + } | |
| 23283 | + } | |
| 23284 | + | |
| 23285 | + /* Get the exclusive locks at the system level. Then if successful | |
| 23286 | + ** also mark the local connection as being locked. | |
| 23287 | + */ | |
| 23288 | + if( rc==SQLITE_OK ){ | |
| 23289 | + rc = os2ShmSystemLock(pShmNode, _SHM_WRLCK, ofst+OS2_SHM_BASE, n); | |
| 23290 | + if( rc==SQLITE_OK ){ | |
| 23291 | + assert( (p->sharedMask & mask)==0 ); | |
| 23292 | + p->exclMask |= mask; | |
| 23293 | + } | |
| 23294 | + } | |
| 23295 | + } | |
| 23296 | + | |
| 23297 | + sqlite3_mutex_leave(pShmNode->mutex); | |
| 23298 | + | |
| 23299 | + OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n", | |
| 23300 | + p->id, (int)GetCurrentProcessId(), p->sharedMask, p->exclMask, | |
| 23301 | + rc ? "failed" : "ok")); | |
| 23302 | + | |
| 23303 | + ERR_TRACE(rc, ("os2ShmLock: ofst = %d, n = %d, flags = 0x%x -> %d \n", | |
| 23304 | + ofst, n, flags, rc)) | |
| 23305 | + | |
| 23306 | + return rc; | |
| 23307 | +} | |
| 23308 | + | |
| 23309 | +/* | |
| 23310 | +** Implement a memory barrier or memory fence on shared memory. | |
| 23311 | +** | |
| 23312 | +** All loads and stores begun before the barrier must complete before | |
| 23313 | +** any load or store begun after the barrier. | |
| 23314 | +*/ | |
| 23315 | +static void os2ShmBarrier( | |
| 23316 | + sqlite3_file *id /* Database file holding the shared memory */ | |
| 23317 | +){ | |
| 23318 | + UNUSED_PARAMETER(id); | |
| 23319 | + os2ShmEnterMutex(); | |
| 23320 | + os2ShmLeaveMutex(); | |
| 23321 | +} | |
| 23322 | + | |
| 23323 | +#else | |
| 23324 | +# define os2ShmMap 0 | |
| 23325 | +# define os2ShmLock 0 | |
| 23326 | +# define os2ShmBarrier 0 | |
| 23327 | +# define os2ShmUnmap 0 | |
| 23328 | +#endif /* #ifndef SQLITE_OMIT_WAL */ | |
| 23329 | + | |
| 22635 | 23330 | |
| 22636 | 23331 | /* |
| 22637 | 23332 | ** This vector defines all the methods that can operate on an |
| 22638 | 23333 | ** sqlite3_file for os2. |
| 22639 | 23334 | */ |
| 22640 | 23335 | static const sqlite3_io_methods os2IoMethod = { |
| 22641 | - 1, /* iVersion */ | |
| 23336 | + 2, /* iVersion */ | |
| 22642 | 23337 | os2Close, /* xClose */ |
| 22643 | 23338 | os2Read, /* xRead */ |
| 22644 | 23339 | os2Write, /* xWrite */ |
| 22645 | 23340 | os2Truncate, /* xTruncate */ |
| 22646 | 23341 | os2Sync, /* xSync */ |
| @@ -22649,15 +23344,16 @@ | ||
| 22649 | 23344 | os2Unlock, /* xUnlock */ |
| 22650 | 23345 | os2CheckReservedLock, /* xCheckReservedLock */ |
| 22651 | 23346 | os2FileControl, /* xFileControl */ |
| 22652 | 23347 | os2SectorSize, /* xSectorSize */ |
| 22653 | 23348 | os2DeviceCharacteristics, /* xDeviceCharacteristics */ |
| 22654 | - 0, /* xShmMap */ | |
| 22655 | - 0, /* xShmLock */ | |
| 22656 | - 0, /* xShmBarrier */ | |
| 22657 | - 0 /* xShmUnmap */ | |
| 23349 | + os2ShmMap, /* xShmMap */ | |
| 23350 | + os2ShmLock, /* xShmLock */ | |
| 23351 | + os2ShmBarrier, /* xShmBarrier */ | |
| 23352 | + os2ShmUnmap /* xShmUnmap */ | |
| 22658 | 23353 | }; |
| 23354 | + | |
| 22659 | 23355 | |
| 22660 | 23356 | /*************************************************************************** |
| 22661 | 23357 | ** Here ends the I/O methods that form the sqlite3_io_methods object. |
| 22662 | 23358 | ** |
| 22663 | 23359 | ** The next block of code implements the VFS methods. |
| @@ -22666,54 +23362,61 @@ | ||
| 22666 | 23362 | /* |
| 22667 | 23363 | ** Create a temporary file name in zBuf. zBuf must be big enough to |
| 22668 | 23364 | ** hold at pVfs->mxPathname characters. |
| 22669 | 23365 | */ |
| 22670 | 23366 | static int getTempname(int nBuf, char *zBuf ){ |
| 22671 | - static const unsigned char zChars[] = | |
| 23367 | + static const char zChars[] = | |
| 22672 | 23368 | "abcdefghijklmnopqrstuvwxyz" |
| 22673 | 23369 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 22674 | 23370 | "0123456789"; |
| 22675 | 23371 | int i, j; |
| 22676 | - char zTempPathBuf[3]; | |
| 22677 | - PSZ zTempPath = (PSZ)&zTempPathBuf; | |
| 22678 | - if( sqlite3_temp_directory ){ | |
| 22679 | - zTempPath = sqlite3_temp_directory; | |
| 22680 | - }else{ | |
| 22681 | - if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){ | |
| 22682 | - if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){ | |
| 22683 | - if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){ | |
| 22684 | - ULONG ulDriveNum = 0, ulDriveMap = 0; | |
| 22685 | - DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); | |
| 22686 | - sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) ); | |
| 22687 | - } | |
| 22688 | - } | |
| 22689 | - } | |
| 22690 | - } | |
| 23372 | + PSZ zTempPathCp; | |
| 23373 | + char zTempPath[CCHMAXPATH]; | |
| 23374 | + ULONG ulDriveNum, ulDriveMap; | |
| 23375 | + | |
| 23376 | + /* It's odd to simulate an io-error here, but really this is just | |
| 23377 | + ** using the io-error infrastructure to test that SQLite handles this | |
| 23378 | + ** function failing. | |
| 23379 | + */ | |
| 23380 | + SimulateIOError( return SQLITE_IOERR ); | |
| 23381 | + | |
| 23382 | + if( sqlite3_temp_directory ) { | |
| 23383 | + sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", sqlite3_temp_directory); | |
| 23384 | + } else if( DosScanEnv( (PSZ)"TEMP", &zTempPathCp ) == NO_ERROR || | |
| 23385 | + DosScanEnv( (PSZ)"TMP", &zTempPathCp ) == NO_ERROR || | |
| 23386 | + DosScanEnv( (PSZ)"TMPDIR", &zTempPathCp ) == NO_ERROR ) { | |
| 23387 | + char *zTempPathUTF = convertCpPathToUtf8( (char *)zTempPathCp ); | |
| 23388 | + sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", zTempPathUTF); | |
| 23389 | + free( zTempPathUTF ); | |
| 23390 | + } else if( DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ) == NO_ERROR ) { | |
| 23391 | + zTempPath[0] = (char)('A' + ulDriveNum - 1); | |
| 23392 | + zTempPath[1] = ':'; | |
| 23393 | + zTempPath[2] = '\0'; | |
| 23394 | + } else { | |
| 23395 | + zTempPath[0] = '\0'; | |
| 23396 | + } | |
| 23397 | + | |
| 22691 | 23398 | /* Strip off a trailing slashes or backslashes, otherwise we would get * |
| 22692 | 23399 | * multiple (back)slashes which causes DosOpen() to fail. * |
| 22693 | 23400 | * Trailing spaces are not allowed, either. */ |
| 22694 | 23401 | j = sqlite3Strlen30(zTempPath); |
| 22695 | - while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' | |
| 22696 | - || zTempPath[j-1] == ' ' ) ){ | |
| 23402 | + while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' || | |
| 23403 | + zTempPath[j-1] == ' ' ) ){ | |
| 22697 | 23404 | j--; |
| 22698 | 23405 | } |
| 22699 | 23406 | zTempPath[j] = '\0'; |
| 22700 | - if( !sqlite3_temp_directory ){ | |
| 22701 | - char *zTempPathUTF = convertCpPathToUtf8( zTempPath ); | |
| 22702 | - sqlite3_snprintf( nBuf-30, zBuf, | |
| 22703 | - "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPathUTF ); | |
| 22704 | - free( zTempPathUTF ); | |
| 22705 | - }else{ | |
| 22706 | - sqlite3_snprintf( nBuf-30, zBuf, | |
| 22707 | - "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath ); | |
| 22708 | - } | |
| 22709 | - j = sqlite3Strlen30( zBuf ); | |
| 23407 | + | |
| 23408 | + /* We use 20 bytes to randomize the name */ | |
| 23409 | + sqlite3_snprintf(nBuf-22, zBuf, | |
| 23410 | + "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); | |
| 23411 | + j = sqlite3Strlen30(zBuf); | |
| 22710 | 23412 | sqlite3_randomness( 20, &zBuf[j] ); |
| 22711 | 23413 | for( i = 0; i < 20; i++, j++ ){ |
| 22712 | - zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; | |
| 23414 | + zBuf[j] = zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; | |
| 22713 | 23415 | } |
| 22714 | 23416 | zBuf[j] = 0; |
| 23417 | + | |
| 22715 | 23418 | OSTRACE(( "TEMP FILENAME: %s\n", zBuf )); |
| 22716 | 23419 | return SQLITE_OK; |
| 22717 | 23420 | } |
| 22718 | 23421 | |
| 22719 | 23422 | |
| @@ -22729,12 +23432,12 @@ | ||
| 22729 | 23432 | char *zFull /* Output buffer */ |
| 22730 | 23433 | ){ |
| 22731 | 23434 | char *zRelativeCp = convertUtf8PathToCp( zRelative ); |
| 22732 | 23435 | char zFullCp[CCHMAXPATH] = "\0"; |
| 22733 | 23436 | char *zFullUTF; |
| 22734 | - APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp, | |
| 22735 | - CCHMAXPATH ); | |
| 23437 | + APIRET rc = DosQueryPathInfo( (PSZ)zRelativeCp, FIL_QUERYFULLNAME, | |
| 23438 | + zFullCp, CCHMAXPATH ); | |
| 22736 | 23439 | free( zRelativeCp ); |
| 22737 | 23440 | zFullUTF = convertCpPathToUtf8( zFullCp ); |
| 22738 | 23441 | sqlite3_snprintf( nFull, zFull, zFullUTF ); |
| 22739 | 23442 | free( zFullUTF ); |
| 22740 | 23443 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
| @@ -22760,14 +23463,14 @@ | ||
| 22760 | 23463 | const char *zUtf8Name = zName; |
| 22761 | 23464 | char *zNameCp; |
| 22762 | 23465 | char zTmpname[CCHMAXPATH]; |
| 22763 | 23466 | |
| 22764 | 23467 | int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); |
| 22765 | - int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); | |
| 22766 | 23468 | int isCreate = (flags & SQLITE_OPEN_CREATE); |
| 22767 | 23469 | int isReadWrite = (flags & SQLITE_OPEN_READWRITE); |
| 22768 | 23470 | #ifndef NDEBUG |
| 23471 | + int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); | |
| 22769 | 23472 | int isReadonly = (flags & SQLITE_OPEN_READONLY); |
| 22770 | 23473 | int eType = (flags & 0xFFFFFF00); |
| 22771 | 23474 | int isOpenJournal = (isCreate && ( |
| 22772 | 23475 | eType==SQLITE_OPEN_MASTER_JOURNAL |
| 22773 | 23476 | || eType==SQLITE_OPEN_MAIN_JOURNAL |
| @@ -22803,11 +23506,11 @@ | ||
| 22803 | 23506 | || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL |
| 22804 | 23507 | || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL |
| 22805 | 23508 | ); |
| 22806 | 23509 | |
| 22807 | 23510 | memset( pFile, 0, sizeof(*pFile) ); |
| 22808 | - pFile->pMethod = &os2IoMethod; | |
| 23511 | + pFile->h = (HFILE)-1; | |
| 22809 | 23512 | |
| 22810 | 23513 | /* If the second argument to this function is NULL, generate a |
| 22811 | 23514 | ** temporary file name to use |
| 22812 | 23515 | */ |
| 22813 | 23516 | if( !zUtf8Name ){ |
| @@ -22825,15 +23528,15 @@ | ||
| 22825 | 23528 | ulOpenMode |= OPEN_ACCESS_READONLY; |
| 22826 | 23529 | } |
| 22827 | 23530 | |
| 22828 | 23531 | /* Open in random access mode for possibly better speed. Allow full |
| 22829 | 23532 | ** sharing because file locks will provide exclusive access when needed. |
| 23533 | + ** The handle should not be inherited by child processes and we don't | |
| 23534 | + ** want popups from the critical error handler. | |
| 22830 | 23535 | */ |
| 22831 | - ulOpenMode |= OPEN_FLAGS_RANDOM; | |
| 22832 | - ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR; | |
| 22833 | - ulOpenMode |= OPEN_FLAGS_NOINHERIT; | |
| 22834 | - ulOpenMode |= OPEN_SHARE_DENYNONE; | |
| 23536 | + ulOpenMode |= OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYNONE | | |
| 23537 | + OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR; | |
| 22835 | 23538 | |
| 22836 | 23539 | /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is |
| 22837 | 23540 | ** created. SQLite doesn't use it to indicate "exclusive access" |
| 22838 | 23541 | ** as it is usually understood. |
| 22839 | 23542 | */ |
| @@ -22847,17 +23550,10 @@ | ||
| 22847 | 23550 | }else{ |
| 22848 | 23551 | /* Opens a file, only if it exists. */ |
| 22849 | 23552 | ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; |
| 22850 | 23553 | } |
| 22851 | 23554 | |
| 22852 | - /* For DELETEONCLOSE, save a pointer to the converted filename */ | |
| 22853 | - if( isDelete ){ | |
| 22854 | - char pathUtf8[CCHMAXPATH]; | |
| 22855 | - os2FullPathname( pVfs, zUtf8Name, CCHMAXPATH, pathUtf8 ); | |
| 22856 | - pFile->pathToDel = convertUtf8PathToCp( pathUtf8 ); | |
| 22857 | - } | |
| 22858 | - | |
| 22859 | 23555 | zNameCp = convertUtf8PathToCp( zUtf8Name ); |
| 22860 | 23556 | rc = DosOpen( (PSZ)zNameCp, |
| 22861 | 23557 | &h, |
| 22862 | 23558 | &ulAction, |
| 22863 | 23559 | 0L, |
| @@ -22868,13 +23564,10 @@ | ||
| 22868 | 23564 | free( zNameCp ); |
| 22869 | 23565 | |
| 22870 | 23566 | if( rc != NO_ERROR ){ |
| 22871 | 23567 | OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n", |
| 22872 | 23568 | rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode )); |
| 22873 | - if( pFile->pathToDel ) | |
| 22874 | - free( pFile->pathToDel ); | |
| 22875 | - pFile->pathToDel = NULL; | |
| 22876 | 23569 | |
| 22877 | 23570 | if( isReadWrite ){ |
| 22878 | 23571 | return os2Open( pVfs, zName, id, |
| 22879 | 23572 | ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), |
| 22880 | 23573 | pOutFlags ); |
| @@ -22885,11 +23578,16 @@ | ||
| 22885 | 23578 | |
| 22886 | 23579 | if( pOutFlags ){ |
| 22887 | 23580 | *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY; |
| 22888 | 23581 | } |
| 22889 | 23582 | |
| 23583 | + os2FullPathname( pVfs, zUtf8Name, sizeof( zTmpname ), zTmpname ); | |
| 23584 | + pFile->zFullPathCp = convertUtf8PathToCp( zTmpname ); | |
| 23585 | + pFile->pMethod = &os2IoMethod; | |
| 23586 | + pFile->flags = flags; | |
| 22890 | 23587 | pFile->h = h; |
| 23588 | + | |
| 22891 | 23589 | OpenCounter(+1); |
| 22892 | 23590 | OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags )); |
| 22893 | 23591 | return SQLITE_OK; |
| 22894 | 23592 | } |
| 22895 | 23593 | |
| @@ -22920,34 +23618,46 @@ | ||
| 22920 | 23618 | sqlite3_vfs *pVfs, /* Not used on os2 */ |
| 22921 | 23619 | const char *zFilename, /* Name of file to check */ |
| 22922 | 23620 | int flags, /* Type of test to make on this file */ |
| 22923 | 23621 | int *pOut /* Write results here */ |
| 22924 | 23622 | ){ |
| 23623 | + APIRET rc; | |
| 22925 | 23624 | FILESTATUS3 fsts3ConfigInfo; |
| 22926 | - APIRET rc = NO_ERROR; | |
| 22927 | - char *zFilenameCp = convertUtf8PathToCp( zFilename ); | |
| 23625 | + char *zFilenameCp; | |
| 22928 | 23626 | |
| 22929 | - memset( &fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo) ); | |
| 23627 | + UNUSED_PARAMETER(pVfs); | |
| 23628 | + SimulateIOError( return SQLITE_IOERR_ACCESS; ); | |
| 23629 | + | |
| 23630 | + zFilenameCp = convertUtf8PathToCp( zFilename ); | |
| 22930 | 23631 | rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD, |
| 22931 | 23632 | &fsts3ConfigInfo, sizeof(FILESTATUS3) ); |
| 22932 | 23633 | free( zFilenameCp ); |
| 22933 | 23634 | OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n", |
| 22934 | 23635 | fsts3ConfigInfo.attrFile, flags, rc )); |
| 23636 | + | |
| 22935 | 23637 | switch( flags ){ |
| 22936 | - case SQLITE_ACCESS_READ: | |
| 22937 | 23638 | case SQLITE_ACCESS_EXISTS: |
| 22938 | - rc = (rc == NO_ERROR); | |
| 22939 | - OSTRACE(( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc)); | |
| 23639 | + /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file | |
| 23640 | + ** as if it does not exist. | |
| 23641 | + */ | |
| 23642 | + if( fsts3ConfigInfo.cbFile == 0 ) | |
| 23643 | + rc = ERROR_FILE_NOT_FOUND; | |
| 23644 | + break; | |
| 23645 | + case SQLITE_ACCESS_READ: | |
| 22940 | 23646 | break; |
| 22941 | 23647 | case SQLITE_ACCESS_READWRITE: |
| 22942 | - rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 ); | |
| 22943 | - OSTRACE(( "ACCESS %s access of read/write rc=%d\n", zFilename, rc )); | |
| 23648 | + if( fsts3ConfigInfo.attrFile & FILE_READONLY ) | |
| 23649 | + rc = ERROR_ACCESS_DENIED; | |
| 22944 | 23650 | break; |
| 22945 | 23651 | default: |
| 23652 | + rc = ERROR_FILE_NOT_FOUND; | |
| 22946 | 23653 | assert( !"Invalid flags argument" ); |
| 22947 | 23654 | } |
| 22948 | - *pOut = rc; | |
| 23655 | + | |
| 23656 | + *pOut = (rc == NO_ERROR); | |
| 23657 | + OSTRACE(( "ACCESS %s flags %d: rc=%d\n", zFilename, flags, *pOut )); | |
| 23658 | + | |
| 22949 | 23659 | return SQLITE_OK; |
| 22950 | 23660 | } |
| 22951 | 23661 | |
| 22952 | 23662 | |
| 22953 | 23663 | #ifndef SQLITE_OMIT_LOAD_EXTENSION |
| @@ -22958,15 +23668,14 @@ | ||
| 22958 | 23668 | /* |
| 22959 | 23669 | ** Interfaces for opening a shared library, finding entry points |
| 22960 | 23670 | ** within the shared library, and closing the shared library. |
| 22961 | 23671 | */ |
| 22962 | 23672 | static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){ |
| 22963 | - UCHAR loadErr[256]; | |
| 22964 | 23673 | HMODULE hmod; |
| 22965 | 23674 | APIRET rc; |
| 22966 | 23675 | char *zFilenameCp = convertUtf8PathToCp(zFilename); |
| 22967 | - rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilenameCp, &hmod); | |
| 23676 | + rc = DosLoadModule(NULL, 0, (PSZ)zFilenameCp, &hmod); | |
| 22968 | 23677 | free(zFilenameCp); |
| 22969 | 23678 | return rc != NO_ERROR ? 0 : (void*)hmod; |
| 22970 | 23679 | } |
| 22971 | 23680 | /* |
| 22972 | 23681 | ** A no-op since the error code is returned on the DosLoadModule call. |
| @@ -22976,18 +23685,18 @@ | ||
| 22976 | 23685 | /* no-op */ |
| 22977 | 23686 | } |
| 22978 | 23687 | static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){ |
| 22979 | 23688 | PFN pfn; |
| 22980 | 23689 | APIRET rc; |
| 22981 | - rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn); | |
| 23690 | + rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)zSymbol, &pfn); | |
| 22982 | 23691 | if( rc != NO_ERROR ){ |
| 22983 | 23692 | /* if the symbol itself was not found, search again for the same |
| 22984 | 23693 | * symbol with an extra underscore, that might be needed depending |
| 22985 | 23694 | * on the calling convention */ |
| 22986 | 23695 | char _zSymbol[256] = "_"; |
| 22987 | - strncat(_zSymbol, zSymbol, 255); | |
| 22988 | - rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn); | |
| 23696 | + strncat(_zSymbol, zSymbol, 254); | |
| 23697 | + rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)_zSymbol, &pfn); | |
| 22989 | 23698 | } |
| 22990 | 23699 | return rc != NO_ERROR ? 0 : (void(*)(void))pfn; |
| 22991 | 23700 | } |
| 22992 | 23701 | static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){ |
| 22993 | 23702 | DosFreeModule((HMODULE)pHandle); |
| @@ -23007,58 +23716,43 @@ | ||
| 23007 | 23716 | int n = 0; |
| 23008 | 23717 | #if defined(SQLITE_TEST) |
| 23009 | 23718 | n = nBuf; |
| 23010 | 23719 | memset(zBuf, 0, nBuf); |
| 23011 | 23720 | #else |
| 23012 | - int sizeofULong = sizeof(ULONG); | |
| 23013 | - if( (int)sizeof(DATETIME) <= nBuf - n ){ | |
| 23014 | - DATETIME x; | |
| 23015 | - DosGetDateTime(&x); | |
| 23016 | - memcpy(&zBuf[n], &x, sizeof(x)); | |
| 23017 | - n += sizeof(x); | |
| 23018 | - } | |
| 23019 | - | |
| 23020 | - if( sizeofULong <= nBuf - n ){ | |
| 23021 | - PPIB ppib; | |
| 23022 | - DosGetInfoBlocks(NULL, &ppib); | |
| 23023 | - memcpy(&zBuf[n], &ppib->pib_ulpid, sizeofULong); | |
| 23024 | - n += sizeofULong; | |
| 23025 | - } | |
| 23026 | - | |
| 23027 | - if( sizeofULong <= nBuf - n ){ | |
| 23028 | - PTIB ptib; | |
| 23029 | - DosGetInfoBlocks(&ptib, NULL); | |
| 23030 | - memcpy(&zBuf[n], &ptib->tib_ptib2->tib2_ultid, sizeofULong); | |
| 23031 | - n += sizeofULong; | |
| 23032 | - } | |
| 23033 | - | |
| 23034 | - /* if we still haven't filled the buffer yet the following will */ | |
| 23035 | - /* grab everything once instead of making several calls for a single item */ | |
| 23036 | - if( sizeofULong <= nBuf - n ){ | |
| 23037 | - ULONG ulSysInfo[QSV_MAX]; | |
| 23038 | - DosQuerySysInfo(1L, QSV_MAX, ulSysInfo, sizeofULong * QSV_MAX); | |
| 23039 | - | |
| 23040 | - memcpy(&zBuf[n], &ulSysInfo[QSV_MS_COUNT - 1], sizeofULong); | |
| 23041 | - n += sizeofULong; | |
| 23042 | - | |
| 23043 | - if( sizeofULong <= nBuf - n ){ | |
| 23044 | - memcpy(&zBuf[n], &ulSysInfo[QSV_TIMER_INTERVAL - 1], sizeofULong); | |
| 23045 | - n += sizeofULong; | |
| 23046 | - } | |
| 23047 | - if( sizeofULong <= nBuf - n ){ | |
| 23048 | - memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_LOW - 1], sizeofULong); | |
| 23049 | - n += sizeofULong; | |
| 23050 | - } | |
| 23051 | - if( sizeofULong <= nBuf - n ){ | |
| 23052 | - memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_HIGH - 1], sizeofULong); | |
| 23053 | - n += sizeofULong; | |
| 23054 | - } | |
| 23055 | - if( sizeofULong <= nBuf - n ){ | |
| 23056 | - memcpy(&zBuf[n], &ulSysInfo[QSV_TOTAVAILMEM - 1], sizeofULong); | |
| 23057 | - n += sizeofULong; | |
| 23058 | - } | |
| 23059 | - } | |
| 23721 | + int i; | |
| 23722 | + PPIB ppib; | |
| 23723 | + PTIB ptib; | |
| 23724 | + DATETIME dt; | |
| 23725 | + static unsigned c = 0; | |
| 23726 | + /* Ordered by variation probability */ | |
| 23727 | + static ULONG svIdx[6] = { QSV_MS_COUNT, QSV_TIME_LOW, | |
| 23728 | + QSV_MAXPRMEM, QSV_MAXSHMEM, | |
| 23729 | + QSV_TOTAVAILMEM, QSV_TOTRESMEM }; | |
| 23730 | + | |
| 23731 | + /* 8 bytes; timezone and weekday don't increase the randomness much */ | |
| 23732 | + if( (int)sizeof(dt)-3 <= nBuf - n ){ | |
| 23733 | + c += 0x0100; | |
| 23734 | + DosGetDateTime(&dt); | |
| 23735 | + dt.year = (USHORT)((dt.year - 1900) | c); | |
| 23736 | + memcpy(&zBuf[n], &dt, sizeof(dt)-3); | |
| 23737 | + n += sizeof(dt)-3; | |
| 23738 | + } | |
| 23739 | + | |
| 23740 | + /* 4 bytes; PIDs and TIDs are 16 bit internally, so combine them */ | |
| 23741 | + if( (int)sizeof(ULONG) <= nBuf - n ){ | |
| 23742 | + DosGetInfoBlocks(&ptib, &ppib); | |
| 23743 | + *(PULONG)&zBuf[n] = MAKELONG(ppib->pib_ulpid, | |
| 23744 | + ptib->tib_ptib2->tib2_ultid); | |
| 23745 | + n += sizeof(ULONG); | |
| 23746 | + } | |
| 23747 | + | |
| 23748 | + /* Up to 6 * 4 bytes; variables depend on the system state */ | |
| 23749 | + for( i = 0; i < 6 && (int)sizeof(ULONG) <= nBuf - n; i++ ){ | |
| 23750 | + DosQuerySysInfo(svIdx[i], svIdx[i], | |
| 23751 | + (PULONG)&zBuf[n], sizeof(ULONG)); | |
| 23752 | + n += sizeof(ULONG); | |
| 23753 | + } | |
| 23060 | 23754 | #endif |
| 23061 | 23755 | |
| 23062 | 23756 | return n; |
| 23063 | 23757 | } |
| 23064 | 23758 | |
| @@ -23082,68 +23776,102 @@ | ||
| 23082 | 23776 | #ifdef SQLITE_TEST |
| 23083 | 23777 | SQLITE_API int sqlite3_current_time = 0; |
| 23084 | 23778 | #endif |
| 23085 | 23779 | |
| 23086 | 23780 | /* |
| 23087 | -** Find the current time (in Universal Coordinated Time). Write the | |
| 23088 | -** current time and date as a Julian Day number into *prNow and | |
| 23089 | -** return 0. Return 1 if the time and date cannot be found. | |
| 23781 | +** Find the current time (in Universal Coordinated Time). Write into *piNow | |
| 23782 | +** the current time and date as a Julian Day number times 86_400_000. In | |
| 23783 | +** other words, write into *piNow the number of milliseconds since the Julian | |
| 23784 | +** epoch of noon in Greenwich on November 24, 4714 B.C according to the | |
| 23785 | +** proleptic Gregorian calendar. | |
| 23786 | +** | |
| 23787 | +** On success, return 0. Return 1 if the time and date cannot be found. | |
| 23090 | 23788 | */ |
| 23091 | -int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){ | |
| 23092 | - double now; | |
| 23093 | - SHORT minute; /* needs to be able to cope with negative timezone offset */ | |
| 23094 | - USHORT hundredths, second, hour, | |
| 23095 | - day, month, year; | |
| 23789 | +static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ | |
| 23790 | +#ifdef SQLITE_TEST | |
| 23791 | + static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; | |
| 23792 | +#endif | |
| 23793 | + int year, month, datepart, timepart; | |
| 23794 | + | |
| 23096 | 23795 | DATETIME dt; |
| 23097 | 23796 | DosGetDateTime( &dt ); |
| 23098 | - hundredths = (USHORT)dt.hundredths; | |
| 23099 | - second = (USHORT)dt.seconds; | |
| 23100 | - minute = (SHORT)dt.minutes + dt.timezone; | |
| 23101 | - hour = (USHORT)dt.hours; | |
| 23102 | - day = (USHORT)dt.day; | |
| 23103 | - month = (USHORT)dt.month; | |
| 23104 | - year = (USHORT)dt.year; | |
| 23797 | + | |
| 23798 | + year = dt.year; | |
| 23799 | + month = dt.month; | |
| 23105 | 23800 | |
| 23106 | 23801 | /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html |
| 23107 | - http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */ | |
| 23108 | - /* Calculate the Julian days */ | |
| 23109 | - now = day - 32076 + | |
| 23802 | + ** http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c | |
| 23803 | + ** Calculate the Julian days | |
| 23804 | + */ | |
| 23805 | + datepart = (int)dt.day - 32076 + | |
| 23110 | 23806 | 1461*(year + 4800 + (month - 14)/12)/4 + |
| 23111 | 23807 | 367*(month - 2 - (month - 14)/12*12)/12 - |
| 23112 | 23808 | 3*((year + 4900 + (month - 14)/12)/100)/4; |
| 23113 | 23809 | |
| 23114 | - /* Add the fractional hours, mins and seconds */ | |
| 23115 | - now += (hour + 12.0)/24.0; | |
| 23116 | - now += minute/1440.0; | |
| 23117 | - now += second/86400.0; | |
| 23118 | - now += hundredths/8640000.0; | |
| 23119 | - *prNow = now; | |
| 23810 | + /* Time in milliseconds, hours to noon added */ | |
| 23811 | + timepart = 12*3600*1000 + dt.hundredths*10 + dt.seconds*1000 + | |
| 23812 | + ((int)dt.minutes + dt.timezone)*60*1000 + dt.hours*3600*1000; | |
| 23813 | + | |
| 23814 | + *piNow = (sqlite3_int64)datepart*86400*1000 + timepart; | |
| 23815 | + | |
| 23120 | 23816 | #ifdef SQLITE_TEST |
| 23121 | 23817 | if( sqlite3_current_time ){ |
| 23122 | - *prNow = sqlite3_current_time/86400.0 + 2440587.5; | |
| 23818 | + *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch; | |
| 23123 | 23819 | } |
| 23124 | 23820 | #endif |
| 23821 | + | |
| 23822 | + UNUSED_PARAMETER(pVfs); | |
| 23125 | 23823 | return 0; |
| 23126 | 23824 | } |
| 23127 | 23825 | |
| 23128 | 23826 | /* |
| 23129 | -** Find the current time (in Universal Coordinated Time). Write into *piNow | |
| 23130 | -** the current time and date as a Julian Day number times 86_400_000. In | |
| 23131 | -** other words, write into *piNow the number of milliseconds since the Julian | |
| 23132 | -** epoch of noon in Greenwich on November 24, 4714 B.C according to the | |
| 23133 | -** proleptic Gregorian calendar. | |
| 23134 | -** | |
| 23135 | -** On success, return 0. Return 1 if the time and date cannot be found. | |
| 23136 | -*/ | |
| 23137 | -static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ | |
| 23138 | - double now; | |
| 23139 | - os2CurrentTime(pVfs, &now); | |
| 23140 | - *piNow = now * 86400000; | |
| 23141 | - return 0; | |
| 23142 | -} | |
| 23143 | - | |
| 23827 | +** Find the current time (in Universal Coordinated Time). Write the | |
| 23828 | +** current time and date as a Julian Day number into *prNow and | |
| 23829 | +** return 0. Return 1 if the time and date cannot be found. | |
| 23830 | +*/ | |
| 23831 | +static int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){ | |
| 23832 | + int rc; | |
| 23833 | + sqlite3_int64 i; | |
| 23834 | + rc = os2CurrentTimeInt64(pVfs, &i); | |
| 23835 | + if( !rc ){ | |
| 23836 | + *prNow = i/86400000.0; | |
| 23837 | + } | |
| 23838 | + return rc; | |
| 23839 | +} | |
| 23840 | + | |
| 23841 | +/* | |
| 23842 | +** The idea is that this function works like a combination of | |
| 23843 | +** GetLastError() and FormatMessage() on windows (or errno and | |
| 23844 | +** strerror_r() on unix). After an error is returned by an OS | |
| 23845 | +** function, SQLite calls this function with zBuf pointing to | |
| 23846 | +** a buffer of nBuf bytes. The OS layer should populate the | |
| 23847 | +** buffer with a nul-terminated UTF-8 encoded error message | |
| 23848 | +** describing the last IO error to have occurred within the calling | |
| 23849 | +** thread. | |
| 23850 | +** | |
| 23851 | +** If the error message is too large for the supplied buffer, | |
| 23852 | +** it should be truncated. The return value of xGetLastError | |
| 23853 | +** is zero if the error message fits in the buffer, or non-zero | |
| 23854 | +** otherwise (if the message was truncated). If non-zero is returned, | |
| 23855 | +** then it is not necessary to include the nul-terminator character | |
| 23856 | +** in the output buffer. | |
| 23857 | +** | |
| 23858 | +** Not supplying an error message will have no adverse effect | |
| 23859 | +** on SQLite. It is fine to have an implementation that never | |
| 23860 | +** returns an error message: | |
| 23861 | +** | |
| 23862 | +** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ | |
| 23863 | +** assert(zBuf[0]=='\0'); | |
| 23864 | +** return 0; | |
| 23865 | +** } | |
| 23866 | +** | |
| 23867 | +** However if an error message is supplied, it will be incorporated | |
| 23868 | +** by sqlite into the error message available to the user using | |
| 23869 | +** sqlite3_errmsg(), possibly making IO errors easier to debug. | |
| 23870 | +*/ | |
| 23144 | 23871 | static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
| 23872 | + assert(zBuf[0]=='\0'); | |
| 23145 | 23873 | return 0; |
| 23146 | 23874 | } |
| 23147 | 23875 | |
| 23148 | 23876 | /* |
| 23149 | 23877 | ** Initialize and deinitialize the operating system interface. |
| @@ -23167,17 +23895,18 @@ | ||
| 23167 | 23895 | os2DlClose, /* xDlClose */ |
| 23168 | 23896 | os2Randomness, /* xRandomness */ |
| 23169 | 23897 | os2Sleep, /* xSleep */ |
| 23170 | 23898 | os2CurrentTime, /* xCurrentTime */ |
| 23171 | 23899 | os2GetLastError, /* xGetLastError */ |
| 23172 | - os2CurrentTimeInt64 /* xCurrentTimeInt64 */ | |
| 23900 | + os2CurrentTimeInt64, /* xCurrentTimeInt64 */ | |
| 23173 | 23901 | 0, /* xSetSystemCall */ |
| 23174 | 23902 | 0, /* xGetSystemCall */ |
| 23175 | - 0, /* xNextSystemCall */ | |
| 23903 | + 0 /* xNextSystemCall */ | |
| 23176 | 23904 | }; |
| 23177 | 23905 | sqlite3_vfs_register(&os2Vfs, 1); |
| 23178 | 23906 | initUconvObjects(); |
| 23907 | +/* sqlite3OSTrace = 1; */ | |
| 23179 | 23908 | return SQLITE_OK; |
| 23180 | 23909 | } |
| 23181 | 23910 | SQLITE_API int sqlite3_os_end(void){ |
| 23182 | 23911 | freeUconvObjects(); |
| 23183 | 23912 | return SQLITE_OK; |
| @@ -23752,12 +24481,14 @@ | ||
| 23752 | 24481 | { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, |
| 23753 | 24482 | #endif |
| 23754 | 24483 | #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| 23755 | 24484 | aSyscall[13].pCurrent) |
| 23756 | 24485 | |
| 24486 | +#if SQLITE_ENABLE_LOCKING_STYLE | |
| 23757 | 24487 | { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, |
| 23758 | 24488 | #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) |
| 24489 | +#endif | |
| 23759 | 24490 | |
| 23760 | 24491 | #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE |
| 23761 | 24492 | { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, |
| 23762 | 24493 | #else |
| 23763 | 24494 | { "fallocate", (sqlite3_syscall_ptr)0, 0 }, |
| @@ -54608,10 +55339,14 @@ | ||
| 54608 | 55339 | Pager * const pDestPager = sqlite3BtreePager(p->pDest); |
| 54609 | 55340 | const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); |
| 54610 | 55341 | int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); |
| 54611 | 55342 | const int nCopy = MIN(nSrcPgsz, nDestPgsz); |
| 54612 | 55343 | const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; |
| 55344 | +#ifdef SQLITE_HAS_CODEC | |
| 55345 | + int nSrcReserve = sqlite3BtreeGetReserve(p->pSrc); | |
| 55346 | + int nDestReserve = sqlite3BtreeGetReserve(p->pDest); | |
| 55347 | +#endif | |
| 54613 | 55348 | |
| 54614 | 55349 | int rc = SQLITE_OK; |
| 54615 | 55350 | i64 iOff; |
| 54616 | 55351 | |
| 54617 | 55352 | assert( p->bDestLocked ); |
| @@ -54626,15 +55361,26 @@ | ||
| 54626 | 55361 | rc = SQLITE_READONLY; |
| 54627 | 55362 | } |
| 54628 | 55363 | |
| 54629 | 55364 | #ifdef SQLITE_HAS_CODEC |
| 54630 | 55365 | /* Backup is not possible if the page size of the destination is changing |
| 54631 | - ** a a codec is in use. | |
| 55366 | + ** and a codec is in use. | |
| 54632 | 55367 | */ |
| 54633 | 55368 | if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ |
| 54634 | 55369 | rc = SQLITE_READONLY; |
| 54635 | 55370 | } |
| 55371 | + | |
| 55372 | + /* Backup is not possible if the number of bytes of reserve space differ | |
| 55373 | + ** between source and destination. If there is a difference, try to | |
| 55374 | + ** fix the destination to agree with the source. If that is not possible, | |
| 55375 | + ** then the backup cannot proceed. | |
| 55376 | + */ | |
| 55377 | + if( nSrcReserve!=nDestReserve ){ | |
| 55378 | + u32 newPgsz = nSrcPgsz; | |
| 55379 | + rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); | |
| 55380 | + if( rc==SQLITE_OK && newPgsz!=nSrcPgsz ) rc = SQLITE_READONLY; | |
| 55381 | + } | |
| 54636 | 55382 | #endif |
| 54637 | 55383 | |
| 54638 | 55384 | /* This loop runs once for each destination page spanned by the source |
| 54639 | 55385 | ** page. For each iteration, variable iOff is set to the byte offset |
| 54640 | 55386 | ** of the destination page. |
| @@ -54996,11 +55742,15 @@ | ||
| 54996 | 55742 | if( !isFatalError(p->rc) && iPage<p->iNext ){ |
| 54997 | 55743 | /* The backup process p has already copied page iPage. But now it |
| 54998 | 55744 | ** has been modified by a transaction on the source pager. Copy |
| 54999 | 55745 | ** the new data into the backup. |
| 55000 | 55746 | */ |
| 55001 | - int rc = backupOnePage(p, iPage, aData); | |
| 55747 | + int rc; | |
| 55748 | + assert( p->pDestDb ); | |
| 55749 | + sqlite3_mutex_enter(p->pDestDb->mutex); | |
| 55750 | + rc = backupOnePage(p, iPage, aData); | |
| 55751 | + sqlite3_mutex_leave(p->pDestDb->mutex); | |
| 55002 | 55752 | assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED ); |
| 55003 | 55753 | if( rc!=SQLITE_OK ){ |
| 55004 | 55754 | p->rc = rc; |
| 55005 | 55755 | } |
| 55006 | 55756 | } |
| @@ -74977,10 +75727,14 @@ | ||
| 74977 | 75727 | } |
| 74978 | 75728 | if( i==0 ) pTable->nRowEst = v; |
| 74979 | 75729 | if( pIndex==0 ) break; |
| 74980 | 75730 | pIndex->aiRowEst[i] = v; |
| 74981 | 75731 | if( *z==' ' ) z++; |
| 75732 | + if( memcmp(z, "unordered", 10)==0 ){ | |
| 75733 | + pIndex->bUnordered = 1; | |
| 75734 | + break; | |
| 75735 | + } | |
| 74982 | 75736 | } |
| 74983 | 75737 | return 0; |
| 74984 | 75738 | } |
| 74985 | 75739 | |
| 74986 | 75740 | /* |
| @@ -75322,11 +76076,13 @@ | ||
| 75322 | 76076 | break; |
| 75323 | 76077 | |
| 75324 | 76078 | case SQLITE_NULL: |
| 75325 | 76079 | /* No key specified. Use the key from the main database */ |
| 75326 | 76080 | sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); |
| 75327 | - rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); | |
| 76081 | + if( nKey>0 || sqlite3BtreeGetReserve(db->aDb[0].pBt)>0 ){ | |
| 76082 | + rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); | |
| 76083 | + } | |
| 75328 | 76084 | break; |
| 75329 | 76085 | } |
| 75330 | 76086 | } |
| 75331 | 76087 | #endif |
| 75332 | 76088 | |
| @@ -76753,10 +77509,13 @@ | ||
| 76753 | 77509 | } |
| 76754 | 77510 | pTable = sqlite3FindTable(db, zName, zDb); |
| 76755 | 77511 | if( pTable ){ |
| 76756 | 77512 | if( !noErr ){ |
| 76757 | 77513 | sqlite3ErrorMsg(pParse, "table %T already exists", pName); |
| 77514 | + }else{ | |
| 77515 | + assert( !db->init.busy ); | |
| 77516 | + sqlite3CodeVerifySchema(pParse, iDb); | |
| 76758 | 77517 | } |
| 76759 | 77518 | goto begin_table_error; |
| 76760 | 77519 | } |
| 76761 | 77520 | if( sqlite3FindIndex(db, zName, zDb)!=0 ){ |
| 76762 | 77521 | sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); |
| @@ -77940,10 +78699,11 @@ | ||
| 77940 | 78699 | pTab = sqlite3LocateTable(pParse, isView, |
| 77941 | 78700 | pName->a[0].zName, pName->a[0].zDatabase); |
| 77942 | 78701 | if( noErr ) db->suppressErr--; |
| 77943 | 78702 | |
| 77944 | 78703 | if( pTab==0 ){ |
| 78704 | + if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); | |
| 77945 | 78705 | goto exit_drop_table; |
| 77946 | 78706 | } |
| 77947 | 78707 | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| 77948 | 78708 | assert( iDb>=0 && iDb<db->nDb ); |
| 77949 | 78709 | |
| @@ -78458,10 +79218,13 @@ | ||
| 78458 | 79218 | } |
| 78459 | 79219 | } |
| 78460 | 79220 | if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ |
| 78461 | 79221 | if( !ifNotExist ){ |
| 78462 | 79222 | sqlite3ErrorMsg(pParse, "index %s already exists", zName); |
| 79223 | + }else{ | |
| 79224 | + assert( !db->init.busy ); | |
| 79225 | + sqlite3CodeVerifySchema(pParse, iDb); | |
| 78463 | 79226 | } |
| 78464 | 79227 | goto exit_create_index; |
| 78465 | 79228 | } |
| 78466 | 79229 | }else{ |
| 78467 | 79230 | int n; |
| @@ -78851,10 +79614,12 @@ | ||
| 78851 | 79614 | } |
| 78852 | 79615 | pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); |
| 78853 | 79616 | if( pIndex==0 ){ |
| 78854 | 79617 | if( !ifExists ){ |
| 78855 | 79618 | sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); |
| 79619 | + }else{ | |
| 79620 | + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); | |
| 78856 | 79621 | } |
| 78857 | 79622 | pParse->checkSchema = 1; |
| 78858 | 79623 | goto exit_drop_index; |
| 78859 | 79624 | } |
| 78860 | 79625 | if( pIndex->autoIndex ){ |
| @@ -79439,10 +80204,25 @@ | ||
| 79439 | 80204 | sqlite3OpenTempDatabase(pToplevel); |
| 79440 | 80205 | } |
| 79441 | 80206 | } |
| 79442 | 80207 | } |
| 79443 | 80208 | } |
| 80209 | + | |
| 80210 | +/* | |
| 80211 | +** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each | |
| 80212 | +** attached database. Otherwise, invoke it for the database named zDb only. | |
| 80213 | +*/ | |
| 80214 | +SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){ | |
| 80215 | + sqlite3 *db = pParse->db; | |
| 80216 | + int i; | |
| 80217 | + for(i=0; i<db->nDb; i++){ | |
| 80218 | + Db *pDb = &db->aDb[i]; | |
| 80219 | + if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){ | |
| 80220 | + sqlite3CodeVerifySchema(pParse, i); | |
| 80221 | + } | |
| 80222 | + } | |
| 80223 | +} | |
| 79444 | 80224 | |
| 79445 | 80225 | /* |
| 79446 | 80226 | ** Generate VDBE code that prepares for doing an operation that |
| 79447 | 80227 | ** might change the database. |
| 79448 | 80228 | ** |
| @@ -84872,13 +85652,12 @@ | ||
| 84872 | 85652 | ** index and making sure that duplicate entries do not already exist. |
| 84873 | 85653 | ** Add the new records to the indices as we go. |
| 84874 | 85654 | */ |
| 84875 | 85655 | for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ |
| 84876 | 85656 | int regIdx; |
| 84877 | -#ifndef SQLITE_OMIT_UNIQUE_ENFORCEMENT | |
| 84878 | 85657 | int regR; |
| 84879 | -#endif | |
| 85658 | + | |
| 84880 | 85659 | if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */ |
| 84881 | 85660 | |
| 84882 | 85661 | /* Create a key for accessing the index entry */ |
| 84883 | 85662 | regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1); |
| 84884 | 85663 | for(i=0; i<pIdx->nColumn; i++){ |
| @@ -84892,15 +85671,10 @@ | ||
| 84892 | 85671 | sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); |
| 84893 | 85672 | sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]); |
| 84894 | 85673 | sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT); |
| 84895 | 85674 | sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1); |
| 84896 | 85675 | |
| 84897 | -#ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT | |
| 84898 | - sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); | |
| 84899 | - continue; /* Treat pIdx as if it is not a UNIQUE index */ | |
| 84900 | -#else | |
| 84901 | - | |
| 84902 | 85676 | /* Find out what action to take in case there is an indexing conflict */ |
| 84903 | 85677 | onError = pIdx->onError; |
| 84904 | 85678 | if( onError==OE_None ){ |
| 84905 | 85679 | sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); |
| 84906 | 85680 | continue; /* pIdx is not a UNIQUE index */ |
| @@ -84970,11 +85744,10 @@ | ||
| 84970 | 85744 | break; |
| 84971 | 85745 | } |
| 84972 | 85746 | } |
| 84973 | 85747 | sqlite3VdbeJumpHere(v, j3); |
| 84974 | 85748 | sqlite3ReleaseTempReg(pParse, regR); |
| 84975 | -#endif | |
| 84976 | 85749 | } |
| 84977 | 85750 | |
| 84978 | 85751 | if( pbMayReplace ){ |
| 84979 | 85752 | *pbMayReplace = seenReplace; |
| 84980 | 85753 | } |
| @@ -88180,11 +88953,11 @@ | ||
| 88180 | 88953 | if( zExtra ){ |
| 88181 | 88954 | *pData->pzErrMsg = sqlite3MAppendf(db, *pData->pzErrMsg, |
| 88182 | 88955 | "%s - %s", *pData->pzErrMsg, zExtra); |
| 88183 | 88956 | } |
| 88184 | 88957 | } |
| 88185 | - pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT; | |
| 88958 | + pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT_BKPT; | |
| 88186 | 88959 | } |
| 88187 | 88960 | |
| 88188 | 88961 | /* |
| 88189 | 88962 | ** This is the callback routine for the code that initializes the |
| 88190 | 88963 | ** database. See sqlite3Init() below for additional information. |
| @@ -93841,10 +94614,13 @@ | ||
| 93841 | 94614 | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
| 93842 | 94615 | if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), |
| 93843 | 94616 | zName, sqlite3Strlen30(zName)) ){ |
| 93844 | 94617 | if( !noErr ){ |
| 93845 | 94618 | sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); |
| 94619 | + }else{ | |
| 94620 | + assert( !db->init.busy ); | |
| 94621 | + sqlite3CodeVerifySchema(pParse, iDb); | |
| 93846 | 94622 | } |
| 93847 | 94623 | goto trigger_cleanup; |
| 93848 | 94624 | } |
| 93849 | 94625 | |
| 93850 | 94626 | /* Do not create a trigger on a system table */ |
| @@ -94169,10 +94945,12 @@ | ||
| 94169 | 94945 | if( pTrigger ) break; |
| 94170 | 94946 | } |
| 94171 | 94947 | if( !pTrigger ){ |
| 94172 | 94948 | if( !noErr ){ |
| 94173 | 94949 | sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); |
| 94950 | + }else{ | |
| 94951 | + sqlite3CodeVerifyNamedSchema(pParse, zDb); | |
| 94174 | 94952 | } |
| 94175 | 94953 | pParse->checkSchema = 1; |
| 94176 | 94954 | goto drop_trigger_cleanup; |
| 94177 | 94955 | } |
| 94178 | 94956 | sqlite3DropTriggerPtr(pParse, pTrigger); |
| @@ -98075,11 +98853,14 @@ | ||
| 98075 | 98853 | ** Note that the virtual term must be tagged with TERM_VNULL. This |
| 98076 | 98854 | ** TERM_VNULL tag will suppress the not-null check at the beginning |
| 98077 | 98855 | ** of the loop. Without the TERM_VNULL flag, the not-null check at |
| 98078 | 98856 | ** the start of the loop will prevent any results from being returned. |
| 98079 | 98857 | */ |
| 98080 | - if( pExpr->op==TK_NOTNULL && pExpr->pLeft->iColumn>=0 ){ | |
| 98858 | + if( pExpr->op==TK_NOTNULL | |
| 98859 | + && pExpr->pLeft->op==TK_COLUMN | |
| 98860 | + && pExpr->pLeft->iColumn>=0 | |
| 98861 | + ){ | |
| 98081 | 98862 | Expr *pNewExpr; |
| 98082 | 98863 | Expr *pLeft = pExpr->pLeft; |
| 98083 | 98864 | int idxNew; |
| 98084 | 98865 | WhereTerm *pNewTerm; |
| 98085 | 98866 | |
| @@ -99265,11 +100046,11 @@ | ||
| 99265 | 100046 | ** This routine can fail if it is unable to load a collating sequence |
| 99266 | 100047 | ** required for string comparison, or if unable to allocate memory |
| 99267 | 100048 | ** for a UTF conversion required for comparison. The error is stored |
| 99268 | 100049 | ** in the pParse structure. |
| 99269 | 100050 | */ |
| 99270 | -int whereEqualScanEst( | |
| 100051 | +static int whereEqualScanEst( | |
| 99271 | 100052 | Parse *pParse, /* Parsing & code generating context */ |
| 99272 | 100053 | Index *p, /* The index whose left-most column is pTerm */ |
| 99273 | 100054 | Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */ |
| 99274 | 100055 | double *pnRow /* Write the revised row estimate here */ |
| 99275 | 100056 | ){ |
| @@ -99322,11 +100103,11 @@ | ||
| 99322 | 100103 | ** This routine can fail if it is unable to load a collating sequence |
| 99323 | 100104 | ** required for string comparison, or if unable to allocate memory |
| 99324 | 100105 | ** for a UTF conversion required for comparison. The error is stored |
| 99325 | 100106 | ** in the pParse structure. |
| 99326 | 100107 | */ |
| 99327 | -int whereInScanEst( | |
| 100108 | +static int whereInScanEst( | |
| 99328 | 100109 | Parse *pParse, /* Parsing & code generating context */ |
| 99329 | 100110 | Index *p, /* The index whose left-most column is pTerm */ |
| 99330 | 100111 | ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ |
| 99331 | 100112 | double *pnRow /* Write the revised row estimate here */ |
| 99332 | 100113 | ){ |
| @@ -99593,11 +100374,11 @@ | ||
| 99593 | 100374 | #endif |
| 99594 | 100375 | used |= pTerm->prereqRight; |
| 99595 | 100376 | } |
| 99596 | 100377 | |
| 99597 | 100378 | /* Determine the value of estBound. */ |
| 99598 | - if( nEq<pProbe->nColumn ){ | |
| 100379 | + if( nEq<pProbe->nColumn && pProbe->bUnordered==0 ){ | |
| 99599 | 100380 | int j = pProbe->aiColumn[nEq]; |
| 99600 | 100381 | if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){ |
| 99601 | 100382 | WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx); |
| 99602 | 100383 | WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx); |
| 99603 | 100384 | whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &estBound); |
| @@ -99625,10 +100406,11 @@ | ||
| 99625 | 100406 | ** naturally scan rows in the required order, set the appropriate flags |
| 99626 | 100407 | ** in wsFlags. Otherwise, if there is an ORDER BY clause but the index |
| 99627 | 100408 | ** will scan rows in a different order, set the bSort variable. */ |
| 99628 | 100409 | if( pOrderBy ){ |
| 99629 | 100410 | if( (wsFlags & WHERE_COLUMN_IN)==0 |
| 100411 | + && pProbe->bUnordered==0 | |
| 99630 | 100412 | && isSortingIndex(pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, |
| 99631 | 100413 | nEq, wsFlags, &rev) |
| 99632 | 100414 | ){ |
| 99633 | 100415 | wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY; |
| 99634 | 100416 | wsFlags |= (rev ? WHERE_REVERSE : 0); |
| 99635 | 100417 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -650,11 +650,11 @@ | |
| 650 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 651 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 652 | */ |
| 653 | #define SQLITE_VERSION "3.7.6" |
| 654 | #define SQLITE_VERSION_NUMBER 3007006 |
| 655 | #define SQLITE_SOURCE_ID "2011-04-07 15:24:08 bf78acb9dfacde0f08a5b3ceac13480f12a06168" |
| 656 | |
| 657 | /* |
| 658 | ** CAPI3REF: Run-Time Library Version Numbers |
| 659 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 660 | ** |
| @@ -9808,10 +9808,11 @@ | |
| 9808 | unsigned *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ |
| 9809 | Table *pTable; /* The SQL table being indexed */ |
| 9810 | int tnum; /* Page containing root of this index in database file */ |
| 9811 | u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ |
| 9812 | u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ |
| 9813 | char *zColAff; /* String defining the affinity of each column */ |
| 9814 | Index *pNext; /* The next index associated with the same table */ |
| 9815 | Schema *pSchema; /* Schema containing this index */ |
| 9816 | u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ |
| 9817 | char **azColl; /* Array of collation sequence names for index */ |
| @@ -11099,10 +11100,11 @@ | |
| 11099 | SQLITE_PRIVATE void sqlite3PrngSaveState(void); |
| 11100 | SQLITE_PRIVATE void sqlite3PrngRestoreState(void); |
| 11101 | SQLITE_PRIVATE void sqlite3PrngResetState(void); |
| 11102 | SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*); |
| 11103 | SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); |
| 11104 | SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); |
| 11105 | SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); |
| 11106 | SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*); |
| 11107 | SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*); |
| 11108 | SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); |
| @@ -12078,13 +12080,10 @@ | |
| 12078 | "OMIT_TRIGGER", |
| 12079 | #endif |
| 12080 | #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION |
| 12081 | "OMIT_TRUNCATE_OPTIMIZATION", |
| 12082 | #endif |
| 12083 | #ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT |
| 12084 | "OMIT_UNIQUE_ENFORCEMENT", |
| 12085 | #endif |
| 12086 | #ifdef SQLITE_OMIT_UTF16 |
| 12087 | "OMIT_UTF16", |
| 12088 | #endif |
| 12089 | #ifdef SQLITE_OMIT_VACUUM |
| 12090 | "OMIT_VACUUM", |
| @@ -16972,11 +16971,11 @@ | |
| 16972 | #ifdef SQLITE_DEBUG |
| 16973 | if( p->trace ) os2MutexTrace(p, "leave"); |
| 16974 | #endif |
| 16975 | } |
| 16976 | |
| 16977 | SQLITE_PRIVATE SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ |
| 16978 | static const sqlite3_mutex_methods sMutex = { |
| 16979 | os2MutexInit, |
| 16980 | os2MutexEnd, |
| 16981 | os2MutexAlloc, |
| 16982 | os2MutexFree, |
| @@ -20224,12 +20223,12 @@ | |
| 20224 | /* |
| 20225 | ** Routine needed to support the testcase() macro. |
| 20226 | */ |
| 20227 | #ifdef SQLITE_COVERAGE_TEST |
| 20228 | SQLITE_PRIVATE void sqlite3Coverage(int x){ |
| 20229 | static int dummy = 0; |
| 20230 | dummy += x; |
| 20231 | } |
| 20232 | #endif |
| 20233 | |
| 20234 | #ifndef SQLITE_OMIT_FLOATING_POINT |
| 20235 | /* |
| @@ -22045,48 +22044,66 @@ | |
| 22045 | #endif /* !defined(_OS_COMMON_H_) */ |
| 22046 | |
| 22047 | /************** End of os_common.h *******************************************/ |
| 22048 | /************** Continuing where we left off in os_os2.c *********************/ |
| 22049 | |
| 22050 | /* |
| 22051 | ** The os2File structure is subclass of sqlite3_file specific for the OS/2 |
| 22052 | ** protability layer. |
| 22053 | */ |
| 22054 | typedef struct os2File os2File; |
| 22055 | struct os2File { |
| 22056 | const sqlite3_io_methods *pMethod; /* Always the first entry */ |
| 22057 | HFILE h; /* Handle for accessing the file */ |
| 22058 | char* pathToDel; /* Name of file to delete on close, NULL if not */ |
| 22059 | unsigned char locktype; /* Type of lock currently held on this file */ |
| 22060 | }; |
| 22061 | |
| 22062 | #define LOCK_TIMEOUT 10L /* the default locking timeout */ |
| 22063 | |
| 22064 | /***************************************************************************** |
| 22065 | ** The next group of routines implement the I/O methods specified |
| 22066 | ** by the sqlite3_io_methods object. |
| 22067 | ******************************************************************************/ |
| 22068 | |
| 22069 | /* |
| 22070 | ** Close a file. |
| 22071 | */ |
| 22072 | static int os2Close( sqlite3_file *id ){ |
| 22073 | APIRET rc = NO_ERROR; |
| 22074 | os2File *pFile; |
| 22075 | if( id && (pFile = (os2File*)id) != 0 ){ |
| 22076 | OSTRACE(( "CLOSE %d\n", pFile->h )); |
| 22077 | rc = DosClose( pFile->h ); |
| 22078 | pFile->locktype = NO_LOCK; |
| 22079 | if( pFile->pathToDel != NULL ){ |
| 22080 | rc = DosForceDelete( (PSZ)pFile->pathToDel ); |
| 22081 | free( pFile->pathToDel ); |
| 22082 | pFile->pathToDel = NULL; |
| 22083 | } |
| 22084 | id = 0; |
| 22085 | OpenCounter( -1 ); |
| 22086 | } |
| 22087 | |
| 22088 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
| 22089 | } |
| 22090 | |
| 22091 | /* |
| 22092 | ** Read data from a file into a buffer. Return SQLITE_OK if all |
| @@ -22155,14 +22172,25 @@ | |
| 22155 | |
| 22156 | /* |
| 22157 | ** Truncate an open file to a specified size |
| 22158 | */ |
| 22159 | static int os2Truncate( sqlite3_file *id, i64 nByte ){ |
| 22160 | APIRET rc = NO_ERROR; |
| 22161 | os2File *pFile = (os2File*)id; |
| 22162 | OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte )); |
| 22163 | SimulateIOError( return SQLITE_IOERR_TRUNCATE ); |
| 22164 | rc = DosSetFileSize( pFile->h, nByte ); |
| 22165 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE; |
| 22166 | } |
| 22167 | |
| 22168 | #ifdef SQLITE_TEST |
| @@ -22522,10 +22550,24 @@ | |
| 22522 | *(int*)pArg = ((os2File*)id)->locktype; |
| 22523 | OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n", |
| 22524 | ((os2File*)id)->h, ((os2File*)id)->locktype )); |
| 22525 | return SQLITE_OK; |
| 22526 | } |
| 22527 | } |
| 22528 | return SQLITE_NOTFOUND; |
| 22529 | } |
| 22530 | |
| 22531 | /* |
| @@ -22537,18 +22579,20 @@ | |
| 22537 | ** if two files are created in the same file-system directory (i.e. |
| 22538 | ** a database and its journal file) that the sector size will be the |
| 22539 | ** same for both. |
| 22540 | */ |
| 22541 | static int os2SectorSize(sqlite3_file *id){ |
| 22542 | return SQLITE_DEFAULT_SECTOR_SIZE; |
| 22543 | } |
| 22544 | |
| 22545 | /* |
| 22546 | ** Return a vector of device characteristics. |
| 22547 | */ |
| 22548 | static int os2DeviceCharacteristics(sqlite3_file *id){ |
| 22549 | return 0; |
| 22550 | } |
| 22551 | |
| 22552 | |
| 22553 | /* |
| 22554 | ** Character set conversion objects used by conversion routines. |
| @@ -22630,17 +22674,668 @@ | |
| 22630 | /* determine string for the conversion of UTF-8 which is CP1208 */ |
| 22631 | UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH ); |
| 22632 | |
| 22633 | return out; |
| 22634 | } |
| 22635 | |
| 22636 | /* |
| 22637 | ** This vector defines all the methods that can operate on an |
| 22638 | ** sqlite3_file for os2. |
| 22639 | */ |
| 22640 | static const sqlite3_io_methods os2IoMethod = { |
| 22641 | 1, /* iVersion */ |
| 22642 | os2Close, /* xClose */ |
| 22643 | os2Read, /* xRead */ |
| 22644 | os2Write, /* xWrite */ |
| 22645 | os2Truncate, /* xTruncate */ |
| 22646 | os2Sync, /* xSync */ |
| @@ -22649,15 +23344,16 @@ | |
| 22649 | os2Unlock, /* xUnlock */ |
| 22650 | os2CheckReservedLock, /* xCheckReservedLock */ |
| 22651 | os2FileControl, /* xFileControl */ |
| 22652 | os2SectorSize, /* xSectorSize */ |
| 22653 | os2DeviceCharacteristics, /* xDeviceCharacteristics */ |
| 22654 | 0, /* xShmMap */ |
| 22655 | 0, /* xShmLock */ |
| 22656 | 0, /* xShmBarrier */ |
| 22657 | 0 /* xShmUnmap */ |
| 22658 | }; |
| 22659 | |
| 22660 | /*************************************************************************** |
| 22661 | ** Here ends the I/O methods that form the sqlite3_io_methods object. |
| 22662 | ** |
| 22663 | ** The next block of code implements the VFS methods. |
| @@ -22666,54 +23362,61 @@ | |
| 22666 | /* |
| 22667 | ** Create a temporary file name in zBuf. zBuf must be big enough to |
| 22668 | ** hold at pVfs->mxPathname characters. |
| 22669 | */ |
| 22670 | static int getTempname(int nBuf, char *zBuf ){ |
| 22671 | static const unsigned char zChars[] = |
| 22672 | "abcdefghijklmnopqrstuvwxyz" |
| 22673 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 22674 | "0123456789"; |
| 22675 | int i, j; |
| 22676 | char zTempPathBuf[3]; |
| 22677 | PSZ zTempPath = (PSZ)&zTempPathBuf; |
| 22678 | if( sqlite3_temp_directory ){ |
| 22679 | zTempPath = sqlite3_temp_directory; |
| 22680 | }else{ |
| 22681 | if( DosScanEnv( (PSZ)"TEMP", &zTempPath ) ){ |
| 22682 | if( DosScanEnv( (PSZ)"TMP", &zTempPath ) ){ |
| 22683 | if( DosScanEnv( (PSZ)"TMPDIR", &zTempPath ) ){ |
| 22684 | ULONG ulDriveNum = 0, ulDriveMap = 0; |
| 22685 | DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ); |
| 22686 | sprintf( (char*)zTempPath, "%c:", (char)( 'A' + ulDriveNum - 1 ) ); |
| 22687 | } |
| 22688 | } |
| 22689 | } |
| 22690 | } |
| 22691 | /* Strip off a trailing slashes or backslashes, otherwise we would get * |
| 22692 | * multiple (back)slashes which causes DosOpen() to fail. * |
| 22693 | * Trailing spaces are not allowed, either. */ |
| 22694 | j = sqlite3Strlen30(zTempPath); |
| 22695 | while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' |
| 22696 | || zTempPath[j-1] == ' ' ) ){ |
| 22697 | j--; |
| 22698 | } |
| 22699 | zTempPath[j] = '\0'; |
| 22700 | if( !sqlite3_temp_directory ){ |
| 22701 | char *zTempPathUTF = convertCpPathToUtf8( zTempPath ); |
| 22702 | sqlite3_snprintf( nBuf-30, zBuf, |
| 22703 | "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPathUTF ); |
| 22704 | free( zTempPathUTF ); |
| 22705 | }else{ |
| 22706 | sqlite3_snprintf( nBuf-30, zBuf, |
| 22707 | "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath ); |
| 22708 | } |
| 22709 | j = sqlite3Strlen30( zBuf ); |
| 22710 | sqlite3_randomness( 20, &zBuf[j] ); |
| 22711 | for( i = 0; i < 20; i++, j++ ){ |
| 22712 | zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
| 22713 | } |
| 22714 | zBuf[j] = 0; |
| 22715 | OSTRACE(( "TEMP FILENAME: %s\n", zBuf )); |
| 22716 | return SQLITE_OK; |
| 22717 | } |
| 22718 | |
| 22719 | |
| @@ -22729,12 +23432,12 @@ | |
| 22729 | char *zFull /* Output buffer */ |
| 22730 | ){ |
| 22731 | char *zRelativeCp = convertUtf8PathToCp( zRelative ); |
| 22732 | char zFullCp[CCHMAXPATH] = "\0"; |
| 22733 | char *zFullUTF; |
| 22734 | APIRET rc = DosQueryPathInfo( zRelativeCp, FIL_QUERYFULLNAME, zFullCp, |
| 22735 | CCHMAXPATH ); |
| 22736 | free( zRelativeCp ); |
| 22737 | zFullUTF = convertCpPathToUtf8( zFullCp ); |
| 22738 | sqlite3_snprintf( nFull, zFull, zFullUTF ); |
| 22739 | free( zFullUTF ); |
| 22740 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
| @@ -22760,14 +23463,14 @@ | |
| 22760 | const char *zUtf8Name = zName; |
| 22761 | char *zNameCp; |
| 22762 | char zTmpname[CCHMAXPATH]; |
| 22763 | |
| 22764 | int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); |
| 22765 | int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); |
| 22766 | int isCreate = (flags & SQLITE_OPEN_CREATE); |
| 22767 | int isReadWrite = (flags & SQLITE_OPEN_READWRITE); |
| 22768 | #ifndef NDEBUG |
| 22769 | int isReadonly = (flags & SQLITE_OPEN_READONLY); |
| 22770 | int eType = (flags & 0xFFFFFF00); |
| 22771 | int isOpenJournal = (isCreate && ( |
| 22772 | eType==SQLITE_OPEN_MASTER_JOURNAL |
| 22773 | || eType==SQLITE_OPEN_MAIN_JOURNAL |
| @@ -22803,11 +23506,11 @@ | |
| 22803 | || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL |
| 22804 | || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL |
| 22805 | ); |
| 22806 | |
| 22807 | memset( pFile, 0, sizeof(*pFile) ); |
| 22808 | pFile->pMethod = &os2IoMethod; |
| 22809 | |
| 22810 | /* If the second argument to this function is NULL, generate a |
| 22811 | ** temporary file name to use |
| 22812 | */ |
| 22813 | if( !zUtf8Name ){ |
| @@ -22825,15 +23528,15 @@ | |
| 22825 | ulOpenMode |= OPEN_ACCESS_READONLY; |
| 22826 | } |
| 22827 | |
| 22828 | /* Open in random access mode for possibly better speed. Allow full |
| 22829 | ** sharing because file locks will provide exclusive access when needed. |
| 22830 | */ |
| 22831 | ulOpenMode |= OPEN_FLAGS_RANDOM; |
| 22832 | ulOpenMode |= OPEN_FLAGS_FAIL_ON_ERROR; |
| 22833 | ulOpenMode |= OPEN_FLAGS_NOINHERIT; |
| 22834 | ulOpenMode |= OPEN_SHARE_DENYNONE; |
| 22835 | |
| 22836 | /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is |
| 22837 | ** created. SQLite doesn't use it to indicate "exclusive access" |
| 22838 | ** as it is usually understood. |
| 22839 | */ |
| @@ -22847,17 +23550,10 @@ | |
| 22847 | }else{ |
| 22848 | /* Opens a file, only if it exists. */ |
| 22849 | ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; |
| 22850 | } |
| 22851 | |
| 22852 | /* For DELETEONCLOSE, save a pointer to the converted filename */ |
| 22853 | if( isDelete ){ |
| 22854 | char pathUtf8[CCHMAXPATH]; |
| 22855 | os2FullPathname( pVfs, zUtf8Name, CCHMAXPATH, pathUtf8 ); |
| 22856 | pFile->pathToDel = convertUtf8PathToCp( pathUtf8 ); |
| 22857 | } |
| 22858 | |
| 22859 | zNameCp = convertUtf8PathToCp( zUtf8Name ); |
| 22860 | rc = DosOpen( (PSZ)zNameCp, |
| 22861 | &h, |
| 22862 | &ulAction, |
| 22863 | 0L, |
| @@ -22868,13 +23564,10 @@ | |
| 22868 | free( zNameCp ); |
| 22869 | |
| 22870 | if( rc != NO_ERROR ){ |
| 22871 | OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n", |
| 22872 | rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode )); |
| 22873 | if( pFile->pathToDel ) |
| 22874 | free( pFile->pathToDel ); |
| 22875 | pFile->pathToDel = NULL; |
| 22876 | |
| 22877 | if( isReadWrite ){ |
| 22878 | return os2Open( pVfs, zName, id, |
| 22879 | ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), |
| 22880 | pOutFlags ); |
| @@ -22885,11 +23578,16 @@ | |
| 22885 | |
| 22886 | if( pOutFlags ){ |
| 22887 | *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY; |
| 22888 | } |
| 22889 | |
| 22890 | pFile->h = h; |
| 22891 | OpenCounter(+1); |
| 22892 | OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags )); |
| 22893 | return SQLITE_OK; |
| 22894 | } |
| 22895 | |
| @@ -22920,34 +23618,46 @@ | |
| 22920 | sqlite3_vfs *pVfs, /* Not used on os2 */ |
| 22921 | const char *zFilename, /* Name of file to check */ |
| 22922 | int flags, /* Type of test to make on this file */ |
| 22923 | int *pOut /* Write results here */ |
| 22924 | ){ |
| 22925 | FILESTATUS3 fsts3ConfigInfo; |
| 22926 | APIRET rc = NO_ERROR; |
| 22927 | char *zFilenameCp = convertUtf8PathToCp( zFilename ); |
| 22928 | |
| 22929 | memset( &fsts3ConfigInfo, 0, sizeof(fsts3ConfigInfo) ); |
| 22930 | rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD, |
| 22931 | &fsts3ConfigInfo, sizeof(FILESTATUS3) ); |
| 22932 | free( zFilenameCp ); |
| 22933 | OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n", |
| 22934 | fsts3ConfigInfo.attrFile, flags, rc )); |
| 22935 | switch( flags ){ |
| 22936 | case SQLITE_ACCESS_READ: |
| 22937 | case SQLITE_ACCESS_EXISTS: |
| 22938 | rc = (rc == NO_ERROR); |
| 22939 | OSTRACE(( "ACCESS %s access of read and exists rc=%d\n", zFilename, rc)); |
| 22940 | break; |
| 22941 | case SQLITE_ACCESS_READWRITE: |
| 22942 | rc = (rc == NO_ERROR) && ( (fsts3ConfigInfo.attrFile & FILE_READONLY) == 0 ); |
| 22943 | OSTRACE(( "ACCESS %s access of read/write rc=%d\n", zFilename, rc )); |
| 22944 | break; |
| 22945 | default: |
| 22946 | assert( !"Invalid flags argument" ); |
| 22947 | } |
| 22948 | *pOut = rc; |
| 22949 | return SQLITE_OK; |
| 22950 | } |
| 22951 | |
| 22952 | |
| 22953 | #ifndef SQLITE_OMIT_LOAD_EXTENSION |
| @@ -22958,15 +23668,14 @@ | |
| 22958 | /* |
| 22959 | ** Interfaces for opening a shared library, finding entry points |
| 22960 | ** within the shared library, and closing the shared library. |
| 22961 | */ |
| 22962 | static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){ |
| 22963 | UCHAR loadErr[256]; |
| 22964 | HMODULE hmod; |
| 22965 | APIRET rc; |
| 22966 | char *zFilenameCp = convertUtf8PathToCp(zFilename); |
| 22967 | rc = DosLoadModule((PSZ)loadErr, sizeof(loadErr), zFilenameCp, &hmod); |
| 22968 | free(zFilenameCp); |
| 22969 | return rc != NO_ERROR ? 0 : (void*)hmod; |
| 22970 | } |
| 22971 | /* |
| 22972 | ** A no-op since the error code is returned on the DosLoadModule call. |
| @@ -22976,18 +23685,18 @@ | |
| 22976 | /* no-op */ |
| 22977 | } |
| 22978 | static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){ |
| 22979 | PFN pfn; |
| 22980 | APIRET rc; |
| 22981 | rc = DosQueryProcAddr((HMODULE)pHandle, 0L, zSymbol, &pfn); |
| 22982 | if( rc != NO_ERROR ){ |
| 22983 | /* if the symbol itself was not found, search again for the same |
| 22984 | * symbol with an extra underscore, that might be needed depending |
| 22985 | * on the calling convention */ |
| 22986 | char _zSymbol[256] = "_"; |
| 22987 | strncat(_zSymbol, zSymbol, 255); |
| 22988 | rc = DosQueryProcAddr((HMODULE)pHandle, 0L, _zSymbol, &pfn); |
| 22989 | } |
| 22990 | return rc != NO_ERROR ? 0 : (void(*)(void))pfn; |
| 22991 | } |
| 22992 | static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){ |
| 22993 | DosFreeModule((HMODULE)pHandle); |
| @@ -23007,58 +23716,43 @@ | |
| 23007 | int n = 0; |
| 23008 | #if defined(SQLITE_TEST) |
| 23009 | n = nBuf; |
| 23010 | memset(zBuf, 0, nBuf); |
| 23011 | #else |
| 23012 | int sizeofULong = sizeof(ULONG); |
| 23013 | if( (int)sizeof(DATETIME) <= nBuf - n ){ |
| 23014 | DATETIME x; |
| 23015 | DosGetDateTime(&x); |
| 23016 | memcpy(&zBuf[n], &x, sizeof(x)); |
| 23017 | n += sizeof(x); |
| 23018 | } |
| 23019 | |
| 23020 | if( sizeofULong <= nBuf - n ){ |
| 23021 | PPIB ppib; |
| 23022 | DosGetInfoBlocks(NULL, &ppib); |
| 23023 | memcpy(&zBuf[n], &ppib->pib_ulpid, sizeofULong); |
| 23024 | n += sizeofULong; |
| 23025 | } |
| 23026 | |
| 23027 | if( sizeofULong <= nBuf - n ){ |
| 23028 | PTIB ptib; |
| 23029 | DosGetInfoBlocks(&ptib, NULL); |
| 23030 | memcpy(&zBuf[n], &ptib->tib_ptib2->tib2_ultid, sizeofULong); |
| 23031 | n += sizeofULong; |
| 23032 | } |
| 23033 | |
| 23034 | /* if we still haven't filled the buffer yet the following will */ |
| 23035 | /* grab everything once instead of making several calls for a single item */ |
| 23036 | if( sizeofULong <= nBuf - n ){ |
| 23037 | ULONG ulSysInfo[QSV_MAX]; |
| 23038 | DosQuerySysInfo(1L, QSV_MAX, ulSysInfo, sizeofULong * QSV_MAX); |
| 23039 | |
| 23040 | memcpy(&zBuf[n], &ulSysInfo[QSV_MS_COUNT - 1], sizeofULong); |
| 23041 | n += sizeofULong; |
| 23042 | |
| 23043 | if( sizeofULong <= nBuf - n ){ |
| 23044 | memcpy(&zBuf[n], &ulSysInfo[QSV_TIMER_INTERVAL - 1], sizeofULong); |
| 23045 | n += sizeofULong; |
| 23046 | } |
| 23047 | if( sizeofULong <= nBuf - n ){ |
| 23048 | memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_LOW - 1], sizeofULong); |
| 23049 | n += sizeofULong; |
| 23050 | } |
| 23051 | if( sizeofULong <= nBuf - n ){ |
| 23052 | memcpy(&zBuf[n], &ulSysInfo[QSV_TIME_HIGH - 1], sizeofULong); |
| 23053 | n += sizeofULong; |
| 23054 | } |
| 23055 | if( sizeofULong <= nBuf - n ){ |
| 23056 | memcpy(&zBuf[n], &ulSysInfo[QSV_TOTAVAILMEM - 1], sizeofULong); |
| 23057 | n += sizeofULong; |
| 23058 | } |
| 23059 | } |
| 23060 | #endif |
| 23061 | |
| 23062 | return n; |
| 23063 | } |
| 23064 | |
| @@ -23082,68 +23776,102 @@ | |
| 23082 | #ifdef SQLITE_TEST |
| 23083 | SQLITE_API int sqlite3_current_time = 0; |
| 23084 | #endif |
| 23085 | |
| 23086 | /* |
| 23087 | ** Find the current time (in Universal Coordinated Time). Write the |
| 23088 | ** current time and date as a Julian Day number into *prNow and |
| 23089 | ** return 0. Return 1 if the time and date cannot be found. |
| 23090 | */ |
| 23091 | int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){ |
| 23092 | double now; |
| 23093 | SHORT minute; /* needs to be able to cope with negative timezone offset */ |
| 23094 | USHORT hundredths, second, hour, |
| 23095 | day, month, year; |
| 23096 | DATETIME dt; |
| 23097 | DosGetDateTime( &dt ); |
| 23098 | hundredths = (USHORT)dt.hundredths; |
| 23099 | second = (USHORT)dt.seconds; |
| 23100 | minute = (SHORT)dt.minutes + dt.timezone; |
| 23101 | hour = (USHORT)dt.hours; |
| 23102 | day = (USHORT)dt.day; |
| 23103 | month = (USHORT)dt.month; |
| 23104 | year = (USHORT)dt.year; |
| 23105 | |
| 23106 | /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html |
| 23107 | http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c */ |
| 23108 | /* Calculate the Julian days */ |
| 23109 | now = day - 32076 + |
| 23110 | 1461*(year + 4800 + (month - 14)/12)/4 + |
| 23111 | 367*(month - 2 - (month - 14)/12*12)/12 - |
| 23112 | 3*((year + 4900 + (month - 14)/12)/100)/4; |
| 23113 | |
| 23114 | /* Add the fractional hours, mins and seconds */ |
| 23115 | now += (hour + 12.0)/24.0; |
| 23116 | now += minute/1440.0; |
| 23117 | now += second/86400.0; |
| 23118 | now += hundredths/8640000.0; |
| 23119 | *prNow = now; |
| 23120 | #ifdef SQLITE_TEST |
| 23121 | if( sqlite3_current_time ){ |
| 23122 | *prNow = sqlite3_current_time/86400.0 + 2440587.5; |
| 23123 | } |
| 23124 | #endif |
| 23125 | return 0; |
| 23126 | } |
| 23127 | |
| 23128 | /* |
| 23129 | ** Find the current time (in Universal Coordinated Time). Write into *piNow |
| 23130 | ** the current time and date as a Julian Day number times 86_400_000. In |
| 23131 | ** other words, write into *piNow the number of milliseconds since the Julian |
| 23132 | ** epoch of noon in Greenwich on November 24, 4714 B.C according to the |
| 23133 | ** proleptic Gregorian calendar. |
| 23134 | ** |
| 23135 | ** On success, return 0. Return 1 if the time and date cannot be found. |
| 23136 | */ |
| 23137 | static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ |
| 23138 | double now; |
| 23139 | os2CurrentTime(pVfs, &now); |
| 23140 | *piNow = now * 86400000; |
| 23141 | return 0; |
| 23142 | } |
| 23143 | |
| 23144 | static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
| 23145 | return 0; |
| 23146 | } |
| 23147 | |
| 23148 | /* |
| 23149 | ** Initialize and deinitialize the operating system interface. |
| @@ -23167,17 +23895,18 @@ | |
| 23167 | os2DlClose, /* xDlClose */ |
| 23168 | os2Randomness, /* xRandomness */ |
| 23169 | os2Sleep, /* xSleep */ |
| 23170 | os2CurrentTime, /* xCurrentTime */ |
| 23171 | os2GetLastError, /* xGetLastError */ |
| 23172 | os2CurrentTimeInt64 /* xCurrentTimeInt64 */ |
| 23173 | 0, /* xSetSystemCall */ |
| 23174 | 0, /* xGetSystemCall */ |
| 23175 | 0, /* xNextSystemCall */ |
| 23176 | }; |
| 23177 | sqlite3_vfs_register(&os2Vfs, 1); |
| 23178 | initUconvObjects(); |
| 23179 | return SQLITE_OK; |
| 23180 | } |
| 23181 | SQLITE_API int sqlite3_os_end(void){ |
| 23182 | freeUconvObjects(); |
| 23183 | return SQLITE_OK; |
| @@ -23752,12 +24481,14 @@ | |
| 23752 | { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, |
| 23753 | #endif |
| 23754 | #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| 23755 | aSyscall[13].pCurrent) |
| 23756 | |
| 23757 | { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, |
| 23758 | #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) |
| 23759 | |
| 23760 | #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE |
| 23761 | { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, |
| 23762 | #else |
| 23763 | { "fallocate", (sqlite3_syscall_ptr)0, 0 }, |
| @@ -54608,10 +55339,14 @@ | |
| 54608 | Pager * const pDestPager = sqlite3BtreePager(p->pDest); |
| 54609 | const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); |
| 54610 | int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); |
| 54611 | const int nCopy = MIN(nSrcPgsz, nDestPgsz); |
| 54612 | const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; |
| 54613 | |
| 54614 | int rc = SQLITE_OK; |
| 54615 | i64 iOff; |
| 54616 | |
| 54617 | assert( p->bDestLocked ); |
| @@ -54626,15 +55361,26 @@ | |
| 54626 | rc = SQLITE_READONLY; |
| 54627 | } |
| 54628 | |
| 54629 | #ifdef SQLITE_HAS_CODEC |
| 54630 | /* Backup is not possible if the page size of the destination is changing |
| 54631 | ** a a codec is in use. |
| 54632 | */ |
| 54633 | if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ |
| 54634 | rc = SQLITE_READONLY; |
| 54635 | } |
| 54636 | #endif |
| 54637 | |
| 54638 | /* This loop runs once for each destination page spanned by the source |
| 54639 | ** page. For each iteration, variable iOff is set to the byte offset |
| 54640 | ** of the destination page. |
| @@ -54996,11 +55742,15 @@ | |
| 54996 | if( !isFatalError(p->rc) && iPage<p->iNext ){ |
| 54997 | /* The backup process p has already copied page iPage. But now it |
| 54998 | ** has been modified by a transaction on the source pager. Copy |
| 54999 | ** the new data into the backup. |
| 55000 | */ |
| 55001 | int rc = backupOnePage(p, iPage, aData); |
| 55002 | assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED ); |
| 55003 | if( rc!=SQLITE_OK ){ |
| 55004 | p->rc = rc; |
| 55005 | } |
| 55006 | } |
| @@ -74977,10 +75727,14 @@ | |
| 74977 | } |
| 74978 | if( i==0 ) pTable->nRowEst = v; |
| 74979 | if( pIndex==0 ) break; |
| 74980 | pIndex->aiRowEst[i] = v; |
| 74981 | if( *z==' ' ) z++; |
| 74982 | } |
| 74983 | return 0; |
| 74984 | } |
| 74985 | |
| 74986 | /* |
| @@ -75322,11 +76076,13 @@ | |
| 75322 | break; |
| 75323 | |
| 75324 | case SQLITE_NULL: |
| 75325 | /* No key specified. Use the key from the main database */ |
| 75326 | sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); |
| 75327 | rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); |
| 75328 | break; |
| 75329 | } |
| 75330 | } |
| 75331 | #endif |
| 75332 | |
| @@ -76753,10 +77509,13 @@ | |
| 76753 | } |
| 76754 | pTable = sqlite3FindTable(db, zName, zDb); |
| 76755 | if( pTable ){ |
| 76756 | if( !noErr ){ |
| 76757 | sqlite3ErrorMsg(pParse, "table %T already exists", pName); |
| 76758 | } |
| 76759 | goto begin_table_error; |
| 76760 | } |
| 76761 | if( sqlite3FindIndex(db, zName, zDb)!=0 ){ |
| 76762 | sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); |
| @@ -77940,10 +78699,11 @@ | |
| 77940 | pTab = sqlite3LocateTable(pParse, isView, |
| 77941 | pName->a[0].zName, pName->a[0].zDatabase); |
| 77942 | if( noErr ) db->suppressErr--; |
| 77943 | |
| 77944 | if( pTab==0 ){ |
| 77945 | goto exit_drop_table; |
| 77946 | } |
| 77947 | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| 77948 | assert( iDb>=0 && iDb<db->nDb ); |
| 77949 | |
| @@ -78458,10 +79218,13 @@ | |
| 78458 | } |
| 78459 | } |
| 78460 | if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ |
| 78461 | if( !ifNotExist ){ |
| 78462 | sqlite3ErrorMsg(pParse, "index %s already exists", zName); |
| 78463 | } |
| 78464 | goto exit_create_index; |
| 78465 | } |
| 78466 | }else{ |
| 78467 | int n; |
| @@ -78851,10 +79614,12 @@ | |
| 78851 | } |
| 78852 | pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); |
| 78853 | if( pIndex==0 ){ |
| 78854 | if( !ifExists ){ |
| 78855 | sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); |
| 78856 | } |
| 78857 | pParse->checkSchema = 1; |
| 78858 | goto exit_drop_index; |
| 78859 | } |
| 78860 | if( pIndex->autoIndex ){ |
| @@ -79439,10 +80204,25 @@ | |
| 79439 | sqlite3OpenTempDatabase(pToplevel); |
| 79440 | } |
| 79441 | } |
| 79442 | } |
| 79443 | } |
| 79444 | |
| 79445 | /* |
| 79446 | ** Generate VDBE code that prepares for doing an operation that |
| 79447 | ** might change the database. |
| 79448 | ** |
| @@ -84872,13 +85652,12 @@ | |
| 84872 | ** index and making sure that duplicate entries do not already exist. |
| 84873 | ** Add the new records to the indices as we go. |
| 84874 | */ |
| 84875 | for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ |
| 84876 | int regIdx; |
| 84877 | #ifndef SQLITE_OMIT_UNIQUE_ENFORCEMENT |
| 84878 | int regR; |
| 84879 | #endif |
| 84880 | if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */ |
| 84881 | |
| 84882 | /* Create a key for accessing the index entry */ |
| 84883 | regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1); |
| 84884 | for(i=0; i<pIdx->nColumn; i++){ |
| @@ -84892,15 +85671,10 @@ | |
| 84892 | sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); |
| 84893 | sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]); |
| 84894 | sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT); |
| 84895 | sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1); |
| 84896 | |
| 84897 | #ifdef SQLITE_OMIT_UNIQUE_ENFORCEMENT |
| 84898 | sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); |
| 84899 | continue; /* Treat pIdx as if it is not a UNIQUE index */ |
| 84900 | #else |
| 84901 | |
| 84902 | /* Find out what action to take in case there is an indexing conflict */ |
| 84903 | onError = pIdx->onError; |
| 84904 | if( onError==OE_None ){ |
| 84905 | sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); |
| 84906 | continue; /* pIdx is not a UNIQUE index */ |
| @@ -84970,11 +85744,10 @@ | |
| 84970 | break; |
| 84971 | } |
| 84972 | } |
| 84973 | sqlite3VdbeJumpHere(v, j3); |
| 84974 | sqlite3ReleaseTempReg(pParse, regR); |
| 84975 | #endif |
| 84976 | } |
| 84977 | |
| 84978 | if( pbMayReplace ){ |
| 84979 | *pbMayReplace = seenReplace; |
| 84980 | } |
| @@ -88180,11 +88953,11 @@ | |
| 88180 | if( zExtra ){ |
| 88181 | *pData->pzErrMsg = sqlite3MAppendf(db, *pData->pzErrMsg, |
| 88182 | "%s - %s", *pData->pzErrMsg, zExtra); |
| 88183 | } |
| 88184 | } |
| 88185 | pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT; |
| 88186 | } |
| 88187 | |
| 88188 | /* |
| 88189 | ** This is the callback routine for the code that initializes the |
| 88190 | ** database. See sqlite3Init() below for additional information. |
| @@ -93841,10 +94614,13 @@ | |
| 93841 | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
| 93842 | if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), |
| 93843 | zName, sqlite3Strlen30(zName)) ){ |
| 93844 | if( !noErr ){ |
| 93845 | sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); |
| 93846 | } |
| 93847 | goto trigger_cleanup; |
| 93848 | } |
| 93849 | |
| 93850 | /* Do not create a trigger on a system table */ |
| @@ -94169,10 +94945,12 @@ | |
| 94169 | if( pTrigger ) break; |
| 94170 | } |
| 94171 | if( !pTrigger ){ |
| 94172 | if( !noErr ){ |
| 94173 | sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); |
| 94174 | } |
| 94175 | pParse->checkSchema = 1; |
| 94176 | goto drop_trigger_cleanup; |
| 94177 | } |
| 94178 | sqlite3DropTriggerPtr(pParse, pTrigger); |
| @@ -98075,11 +98853,14 @@ | |
| 98075 | ** Note that the virtual term must be tagged with TERM_VNULL. This |
| 98076 | ** TERM_VNULL tag will suppress the not-null check at the beginning |
| 98077 | ** of the loop. Without the TERM_VNULL flag, the not-null check at |
| 98078 | ** the start of the loop will prevent any results from being returned. |
| 98079 | */ |
| 98080 | if( pExpr->op==TK_NOTNULL && pExpr->pLeft->iColumn>=0 ){ |
| 98081 | Expr *pNewExpr; |
| 98082 | Expr *pLeft = pExpr->pLeft; |
| 98083 | int idxNew; |
| 98084 | WhereTerm *pNewTerm; |
| 98085 | |
| @@ -99265,11 +100046,11 @@ | |
| 99265 | ** This routine can fail if it is unable to load a collating sequence |
| 99266 | ** required for string comparison, or if unable to allocate memory |
| 99267 | ** for a UTF conversion required for comparison. The error is stored |
| 99268 | ** in the pParse structure. |
| 99269 | */ |
| 99270 | int whereEqualScanEst( |
| 99271 | Parse *pParse, /* Parsing & code generating context */ |
| 99272 | Index *p, /* The index whose left-most column is pTerm */ |
| 99273 | Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */ |
| 99274 | double *pnRow /* Write the revised row estimate here */ |
| 99275 | ){ |
| @@ -99322,11 +100103,11 @@ | |
| 99322 | ** This routine can fail if it is unable to load a collating sequence |
| 99323 | ** required for string comparison, or if unable to allocate memory |
| 99324 | ** for a UTF conversion required for comparison. The error is stored |
| 99325 | ** in the pParse structure. |
| 99326 | */ |
| 99327 | int whereInScanEst( |
| 99328 | Parse *pParse, /* Parsing & code generating context */ |
| 99329 | Index *p, /* The index whose left-most column is pTerm */ |
| 99330 | ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ |
| 99331 | double *pnRow /* Write the revised row estimate here */ |
| 99332 | ){ |
| @@ -99593,11 +100374,11 @@ | |
| 99593 | #endif |
| 99594 | used |= pTerm->prereqRight; |
| 99595 | } |
| 99596 | |
| 99597 | /* Determine the value of estBound. */ |
| 99598 | if( nEq<pProbe->nColumn ){ |
| 99599 | int j = pProbe->aiColumn[nEq]; |
| 99600 | if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){ |
| 99601 | WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx); |
| 99602 | WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx); |
| 99603 | whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &estBound); |
| @@ -99625,10 +100406,11 @@ | |
| 99625 | ** naturally scan rows in the required order, set the appropriate flags |
| 99626 | ** in wsFlags. Otherwise, if there is an ORDER BY clause but the index |
| 99627 | ** will scan rows in a different order, set the bSort variable. */ |
| 99628 | if( pOrderBy ){ |
| 99629 | if( (wsFlags & WHERE_COLUMN_IN)==0 |
| 99630 | && isSortingIndex(pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, |
| 99631 | nEq, wsFlags, &rev) |
| 99632 | ){ |
| 99633 | wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY; |
| 99634 | wsFlags |= (rev ? WHERE_REVERSE : 0); |
| 99635 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -650,11 +650,11 @@ | |
| 650 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 651 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 652 | */ |
| 653 | #define SQLITE_VERSION "3.7.6" |
| 654 | #define SQLITE_VERSION_NUMBER 3007006 |
| 655 | #define SQLITE_SOURCE_ID "2011-04-12 01:58:40 f9d43fa363d54beab6f45db005abac0a7c0c47a7" |
| 656 | |
| 657 | /* |
| 658 | ** CAPI3REF: Run-Time Library Version Numbers |
| 659 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 660 | ** |
| @@ -9808,10 +9808,11 @@ | |
| 9808 | unsigned *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ |
| 9809 | Table *pTable; /* The SQL table being indexed */ |
| 9810 | int tnum; /* Page containing root of this index in database file */ |
| 9811 | u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ |
| 9812 | u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ |
| 9813 | u8 bUnordered; /* Use this index for == or IN queries only */ |
| 9814 | char *zColAff; /* String defining the affinity of each column */ |
| 9815 | Index *pNext; /* The next index associated with the same table */ |
| 9816 | Schema *pSchema; /* Schema containing this index */ |
| 9817 | u8 *aSortOrder; /* Array of size Index.nColumn. True==DESC, False==ASC */ |
| 9818 | char **azColl; /* Array of collation sequence names for index */ |
| @@ -11099,10 +11100,11 @@ | |
| 11100 | SQLITE_PRIVATE void sqlite3PrngSaveState(void); |
| 11101 | SQLITE_PRIVATE void sqlite3PrngRestoreState(void); |
| 11102 | SQLITE_PRIVATE void sqlite3PrngResetState(void); |
| 11103 | SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3*); |
| 11104 | SQLITE_PRIVATE void sqlite3CodeVerifySchema(Parse*, int); |
| 11105 | SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse*, const char *zDb); |
| 11106 | SQLITE_PRIVATE void sqlite3BeginTransaction(Parse*, int); |
| 11107 | SQLITE_PRIVATE void sqlite3CommitTransaction(Parse*); |
| 11108 | SQLITE_PRIVATE void sqlite3RollbackTransaction(Parse*); |
| 11109 | SQLITE_PRIVATE void sqlite3Savepoint(Parse*, int, Token*); |
| 11110 | SQLITE_PRIVATE void sqlite3CloseSavepoints(sqlite3 *); |
| @@ -12078,13 +12080,10 @@ | |
| 12080 | "OMIT_TRIGGER", |
| 12081 | #endif |
| 12082 | #ifdef SQLITE_OMIT_TRUNCATE_OPTIMIZATION |
| 12083 | "OMIT_TRUNCATE_OPTIMIZATION", |
| 12084 | #endif |
| 12085 | #ifdef SQLITE_OMIT_UTF16 |
| 12086 | "OMIT_UTF16", |
| 12087 | #endif |
| 12088 | #ifdef SQLITE_OMIT_VACUUM |
| 12089 | "OMIT_VACUUM", |
| @@ -16972,11 +16971,11 @@ | |
| 16971 | #ifdef SQLITE_DEBUG |
| 16972 | if( p->trace ) os2MutexTrace(p, "leave"); |
| 16973 | #endif |
| 16974 | } |
| 16975 | |
| 16976 | SQLITE_PRIVATE sqlite3_mutex_methods const *sqlite3DefaultMutex(void){ |
| 16977 | static const sqlite3_mutex_methods sMutex = { |
| 16978 | os2MutexInit, |
| 16979 | os2MutexEnd, |
| 16980 | os2MutexAlloc, |
| 16981 | os2MutexFree, |
| @@ -20224,12 +20223,12 @@ | |
| 20223 | /* |
| 20224 | ** Routine needed to support the testcase() macro. |
| 20225 | */ |
| 20226 | #ifdef SQLITE_COVERAGE_TEST |
| 20227 | SQLITE_PRIVATE void sqlite3Coverage(int x){ |
| 20228 | static unsigned dummy = 0; |
| 20229 | dummy += (unsigned)x; |
| 20230 | } |
| 20231 | #endif |
| 20232 | |
| 20233 | #ifndef SQLITE_OMIT_FLOATING_POINT |
| 20234 | /* |
| @@ -22045,48 +22044,66 @@ | |
| 22044 | #endif /* !defined(_OS_COMMON_H_) */ |
| 22045 | |
| 22046 | /************** End of os_common.h *******************************************/ |
| 22047 | /************** Continuing where we left off in os_os2.c *********************/ |
| 22048 | |
| 22049 | /* Forward references */ |
| 22050 | typedef struct os2File os2File; /* The file structure */ |
| 22051 | typedef struct os2ShmNode os2ShmNode; /* A shared descritive memory node */ |
| 22052 | typedef struct os2ShmLink os2ShmLink; /* A connection to shared-memory */ |
| 22053 | |
| 22054 | /* |
| 22055 | ** The os2File structure is subclass of sqlite3_file specific for the OS/2 |
| 22056 | ** protability layer. |
| 22057 | */ |
| 22058 | struct os2File { |
| 22059 | const sqlite3_io_methods *pMethod; /* Always the first entry */ |
| 22060 | HFILE h; /* Handle for accessing the file */ |
| 22061 | int flags; /* Flags provided to os2Open() */ |
| 22062 | int locktype; /* Type of lock currently held on this file */ |
| 22063 | int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */ |
| 22064 | char *zFullPathCp; /* Full path name of this file */ |
| 22065 | os2ShmLink *pShmLink; /* Instance of shared memory on this file */ |
| 22066 | }; |
| 22067 | |
| 22068 | #define LOCK_TIMEOUT 10L /* the default locking timeout */ |
| 22069 | |
| 22070 | /* |
| 22071 | ** Missing from some versions of the OS/2 toolkit - |
| 22072 | ** used to allocate from high memory if possible |
| 22073 | */ |
| 22074 | #ifndef OBJ_ANY |
| 22075 | # define OBJ_ANY 0x00000400 |
| 22076 | #endif |
| 22077 | |
| 22078 | /***************************************************************************** |
| 22079 | ** The next group of routines implement the I/O methods specified |
| 22080 | ** by the sqlite3_io_methods object. |
| 22081 | ******************************************************************************/ |
| 22082 | |
| 22083 | /* |
| 22084 | ** Close a file. |
| 22085 | */ |
| 22086 | static int os2Close( sqlite3_file *id ){ |
| 22087 | APIRET rc; |
| 22088 | os2File *pFile = (os2File*)id; |
| 22089 | |
| 22090 | assert( id!=0 ); |
| 22091 | OSTRACE(( "CLOSE %d (%s)\n", pFile->h, pFile->zFullPathCp )); |
| 22092 | |
| 22093 | rc = DosClose( pFile->h ); |
| 22094 | |
| 22095 | if( pFile->flags & SQLITE_OPEN_DELETEONCLOSE ) |
| 22096 | DosForceDelete( (PSZ)pFile->zFullPathCp ); |
| 22097 | |
| 22098 | free( pFile->zFullPathCp ); |
| 22099 | pFile->zFullPathCp = NULL; |
| 22100 | pFile->locktype = NO_LOCK; |
| 22101 | pFile->h = (HFILE)-1; |
| 22102 | pFile->flags = 0; |
| 22103 | |
| 22104 | OpenCounter( -1 ); |
| 22105 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
| 22106 | } |
| 22107 | |
| 22108 | /* |
| 22109 | ** Read data from a file into a buffer. Return SQLITE_OK if all |
| @@ -22155,14 +22172,25 @@ | |
| 22172 | |
| 22173 | /* |
| 22174 | ** Truncate an open file to a specified size |
| 22175 | */ |
| 22176 | static int os2Truncate( sqlite3_file *id, i64 nByte ){ |
| 22177 | APIRET rc; |
| 22178 | os2File *pFile = (os2File*)id; |
| 22179 | assert( id!=0 ); |
| 22180 | OSTRACE(( "TRUNCATE %d %lld\n", pFile->h, nByte )); |
| 22181 | SimulateIOError( return SQLITE_IOERR_TRUNCATE ); |
| 22182 | |
| 22183 | /* If the user has configured a chunk-size for this file, truncate the |
| 22184 | ** file so that it consists of an integer number of chunks (i.e. the |
| 22185 | ** actual file size after the operation may be larger than the requested |
| 22186 | ** size). |
| 22187 | */ |
| 22188 | if( pFile->szChunk ){ |
| 22189 | nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; |
| 22190 | } |
| 22191 | |
| 22192 | rc = DosSetFileSize( pFile->h, nByte ); |
| 22193 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR_TRUNCATE; |
| 22194 | } |
| 22195 | |
| 22196 | #ifdef SQLITE_TEST |
| @@ -22522,10 +22550,24 @@ | |
| 22550 | *(int*)pArg = ((os2File*)id)->locktype; |
| 22551 | OSTRACE(( "FCNTL_LOCKSTATE %d lock=%d\n", |
| 22552 | ((os2File*)id)->h, ((os2File*)id)->locktype )); |
| 22553 | return SQLITE_OK; |
| 22554 | } |
| 22555 | case SQLITE_FCNTL_CHUNK_SIZE: { |
| 22556 | ((os2File*)id)->szChunk = *(int*)pArg; |
| 22557 | return SQLITE_OK; |
| 22558 | } |
| 22559 | case SQLITE_FCNTL_SIZE_HINT: { |
| 22560 | sqlite3_int64 sz = *(sqlite3_int64*)pArg; |
| 22561 | SimulateIOErrorBenign(1); |
| 22562 | os2Truncate(id, sz); |
| 22563 | SimulateIOErrorBenign(0); |
| 22564 | return SQLITE_OK; |
| 22565 | } |
| 22566 | case SQLITE_FCNTL_SYNC_OMITTED: { |
| 22567 | return SQLITE_OK; |
| 22568 | } |
| 22569 | } |
| 22570 | return SQLITE_NOTFOUND; |
| 22571 | } |
| 22572 | |
| 22573 | /* |
| @@ -22537,18 +22579,20 @@ | |
| 22579 | ** if two files are created in the same file-system directory (i.e. |
| 22580 | ** a database and its journal file) that the sector size will be the |
| 22581 | ** same for both. |
| 22582 | */ |
| 22583 | static int os2SectorSize(sqlite3_file *id){ |
| 22584 | UNUSED_PARAMETER(id); |
| 22585 | return SQLITE_DEFAULT_SECTOR_SIZE; |
| 22586 | } |
| 22587 | |
| 22588 | /* |
| 22589 | ** Return a vector of device characteristics. |
| 22590 | */ |
| 22591 | static int os2DeviceCharacteristics(sqlite3_file *id){ |
| 22592 | UNUSED_PARAMETER(id); |
| 22593 | return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; |
| 22594 | } |
| 22595 | |
| 22596 | |
| 22597 | /* |
| 22598 | ** Character set conversion objects used by conversion routines. |
| @@ -22630,17 +22674,668 @@ | |
| 22674 | /* determine string for the conversion of UTF-8 which is CP1208 */ |
| 22675 | UniStrFromUcs( ucUtf8, out, tempPath, CCHMAXPATH ); |
| 22676 | |
| 22677 | return out; |
| 22678 | } |
| 22679 | |
| 22680 | |
| 22681 | #ifndef SQLITE_OMIT_WAL |
| 22682 | |
| 22683 | /* |
| 22684 | ** Use main database file for interprocess locking. If un-defined |
| 22685 | ** a separate file is created for this purpose. The file will be |
| 22686 | ** used only to set file locks. There will be no data written to it. |
| 22687 | */ |
| 22688 | #define SQLITE_OS2_NO_WAL_LOCK_FILE |
| 22689 | |
| 22690 | #if 0 |
| 22691 | static void _ERR_TRACE( const char *fmt, ... ) { |
| 22692 | va_list ap; |
| 22693 | va_start(ap, fmt); |
| 22694 | vfprintf(stderr, fmt, ap); |
| 22695 | fflush(stderr); |
| 22696 | } |
| 22697 | #define ERR_TRACE(rc, msg) \ |
| 22698 | if( (rc) != SQLITE_OK ) _ERR_TRACE msg; |
| 22699 | #else |
| 22700 | #define ERR_TRACE(rc, msg) |
| 22701 | #endif |
| 22702 | |
| 22703 | /* |
| 22704 | ** Helper functions to obtain and relinquish the global mutex. The |
| 22705 | ** global mutex is used to protect os2ShmNodeList. |
| 22706 | ** |
| 22707 | ** Function os2ShmMutexHeld() is used to assert() that the global mutex |
| 22708 | ** is held when required. This function is only used as part of assert() |
| 22709 | ** statements. e.g. |
| 22710 | ** |
| 22711 | ** os2ShmEnterMutex() |
| 22712 | ** assert( os2ShmMutexHeld() ); |
| 22713 | ** os2ShmLeaveMutex() |
| 22714 | */ |
| 22715 | static void os2ShmEnterMutex(void){ |
| 22716 | sqlite3_mutex_enter(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); |
| 22717 | } |
| 22718 | static void os2ShmLeaveMutex(void){ |
| 22719 | sqlite3_mutex_leave(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); |
| 22720 | } |
| 22721 | #ifdef SQLITE_DEBUG |
| 22722 | static int os2ShmMutexHeld(void) { |
| 22723 | return sqlite3_mutex_held(sqlite3MutexAlloc(SQLITE_MUTEX_STATIC_MASTER)); |
| 22724 | } |
| 22725 | int GetCurrentProcessId(void) { |
| 22726 | PPIB pib; |
| 22727 | DosGetInfoBlocks(NULL, &pib); |
| 22728 | return (int)pib->pib_ulpid; |
| 22729 | } |
| 22730 | #endif |
| 22731 | |
| 22732 | /* |
| 22733 | ** Object used to represent a the shared memory area for a single log file. |
| 22734 | ** When multiple threads all reference the same log-summary, each thread has |
| 22735 | ** its own os2File object, but they all point to a single instance of this |
| 22736 | ** object. In other words, each log-summary is opened only once per process. |
| 22737 | ** |
| 22738 | ** os2ShmMutexHeld() must be true when creating or destroying |
| 22739 | ** this object or while reading or writing the following fields: |
| 22740 | ** |
| 22741 | ** nRef |
| 22742 | ** pNext |
| 22743 | ** |
| 22744 | ** The following fields are read-only after the object is created: |
| 22745 | ** |
| 22746 | ** szRegion |
| 22747 | ** hLockFile |
| 22748 | ** shmBaseName |
| 22749 | ** |
| 22750 | ** Either os2ShmNode.mutex must be held or os2ShmNode.nRef==0 and |
| 22751 | ** os2ShmMutexHeld() is true when reading or writing any other field |
| 22752 | ** in this structure. |
| 22753 | ** |
| 22754 | */ |
| 22755 | struct os2ShmNode { |
| 22756 | sqlite3_mutex *mutex; /* Mutex to access this object */ |
| 22757 | os2ShmNode *pNext; /* Next in list of all os2ShmNode objects */ |
| 22758 | |
| 22759 | int szRegion; /* Size of shared-memory regions */ |
| 22760 | |
| 22761 | int nRegion; /* Size of array apRegion */ |
| 22762 | void **apRegion; /* Array of pointers to shared-memory regions */ |
| 22763 | |
| 22764 | int nRef; /* Number of os2ShmLink objects pointing to this */ |
| 22765 | os2ShmLink *pFirst; /* First os2ShmLink object pointing to this */ |
| 22766 | |
| 22767 | HFILE hLockFile; /* File used for inter-process memory locking */ |
| 22768 | char shmBaseName[1]; /* Name of the memory object !!! must last !!! */ |
| 22769 | }; |
| 22770 | |
| 22771 | |
| 22772 | /* |
| 22773 | ** Structure used internally by this VFS to record the state of an |
| 22774 | ** open shared memory connection. |
| 22775 | ** |
| 22776 | ** The following fields are initialized when this object is created and |
| 22777 | ** are read-only thereafter: |
| 22778 | ** |
| 22779 | ** os2Shm.pShmNode |
| 22780 | ** os2Shm.id |
| 22781 | ** |
| 22782 | ** All other fields are read/write. The os2Shm.pShmNode->mutex must be held |
| 22783 | ** while accessing any read/write fields. |
| 22784 | */ |
| 22785 | struct os2ShmLink { |
| 22786 | os2ShmNode *pShmNode; /* The underlying os2ShmNode object */ |
| 22787 | os2ShmLink *pNext; /* Next os2Shm with the same os2ShmNode */ |
| 22788 | u32 sharedMask; /* Mask of shared locks held */ |
| 22789 | u32 exclMask; /* Mask of exclusive locks held */ |
| 22790 | #ifdef SQLITE_DEBUG |
| 22791 | u8 id; /* Id of this connection with its os2ShmNode */ |
| 22792 | #endif |
| 22793 | }; |
| 22794 | |
| 22795 | |
| 22796 | /* |
| 22797 | ** A global list of all os2ShmNode objects. |
| 22798 | ** |
| 22799 | ** The os2ShmMutexHeld() must be true while reading or writing this list. |
| 22800 | */ |
| 22801 | static os2ShmNode *os2ShmNodeList = NULL; |
| 22802 | |
| 22803 | /* |
| 22804 | ** Constants used for locking |
| 22805 | */ |
| 22806 | #ifdef SQLITE_OS2_NO_WAL_LOCK_FILE |
| 22807 | #define OS2_SHM_BASE (PENDING_BYTE + 0x10000) /* first lock byte */ |
| 22808 | #else |
| 22809 | #define OS2_SHM_BASE ((22+SQLITE_SHM_NLOCK)*4) /* first lock byte */ |
| 22810 | #endif |
| 22811 | |
| 22812 | #define OS2_SHM_DMS (OS2_SHM_BASE+SQLITE_SHM_NLOCK) /* deadman switch */ |
| 22813 | |
| 22814 | /* |
| 22815 | ** Apply advisory locks for all n bytes beginning at ofst. |
| 22816 | */ |
| 22817 | #define _SHM_UNLCK 1 /* no lock */ |
| 22818 | #define _SHM_RDLCK 2 /* shared lock, no wait */ |
| 22819 | #define _SHM_WRLCK 3 /* exlusive lock, no wait */ |
| 22820 | #define _SHM_WRLCK_WAIT 4 /* exclusive lock, wait */ |
| 22821 | static int os2ShmSystemLock( |
| 22822 | os2ShmNode *pNode, /* Apply locks to this open shared-memory segment */ |
| 22823 | int lockType, /* _SHM_UNLCK, _SHM_RDLCK, _SHM_WRLCK or _SHM_WRLCK_WAIT */ |
| 22824 | int ofst, /* Offset to first byte to be locked/unlocked */ |
| 22825 | int nByte /* Number of bytes to lock or unlock */ |
| 22826 | ){ |
| 22827 | APIRET rc; |
| 22828 | FILELOCK area; |
| 22829 | ULONG mode, timeout; |
| 22830 | |
| 22831 | /* Access to the os2ShmNode object is serialized by the caller */ |
| 22832 | assert( sqlite3_mutex_held(pNode->mutex) || pNode->nRef==0 ); |
| 22833 | |
| 22834 | mode = 1; /* shared lock */ |
| 22835 | timeout = 0; /* no wait */ |
| 22836 | area.lOffset = ofst; |
| 22837 | area.lRange = nByte; |
| 22838 | |
| 22839 | switch( lockType ) { |
| 22840 | case _SHM_WRLCK_WAIT: |
| 22841 | timeout = (ULONG)-1; /* wait forever */ |
| 22842 | case _SHM_WRLCK: |
| 22843 | mode = 0; /* exclusive lock */ |
| 22844 | case _SHM_RDLCK: |
| 22845 | rc = DosSetFileLocks(pNode->hLockFile, |
| 22846 | NULL, &area, timeout, mode); |
| 22847 | break; |
| 22848 | /* case _SHM_UNLCK: */ |
| 22849 | default: |
| 22850 | rc = DosSetFileLocks(pNode->hLockFile, |
| 22851 | &area, NULL, 0, 0); |
| 22852 | break; |
| 22853 | } |
| 22854 | |
| 22855 | OSTRACE(("SHM-LOCK %d %s %s 0x%08lx\n", |
| 22856 | pNode->hLockFile, |
| 22857 | rc==SQLITE_OK ? "ok" : "failed", |
| 22858 | lockType==_SHM_UNLCK ? "Unlock" : "Lock", |
| 22859 | rc)); |
| 22860 | |
| 22861 | ERR_TRACE(rc, ("os2ShmSystemLock: %d %s\n", rc, pNode->shmBaseName)) |
| 22862 | |
| 22863 | return ( rc == 0 ) ? SQLITE_OK : SQLITE_BUSY; |
| 22864 | } |
| 22865 | |
| 22866 | /* |
| 22867 | ** Find an os2ShmNode in global list or allocate a new one, if not found. |
| 22868 | ** |
| 22869 | ** This is not a VFS shared-memory method; it is a utility function called |
| 22870 | ** by VFS shared-memory methods. |
| 22871 | */ |
| 22872 | static int os2OpenSharedMemory( os2File *fd, int szRegion ) { |
| 22873 | os2ShmLink *pLink; |
| 22874 | os2ShmNode *pNode; |
| 22875 | int cbShmName, rc = SQLITE_OK; |
| 22876 | char shmName[CCHMAXPATH + 30]; |
| 22877 | #ifndef SQLITE_OS2_NO_WAL_LOCK_FILE |
| 22878 | ULONG action; |
| 22879 | #endif |
| 22880 | |
| 22881 | /* We need some additional space at the end to append the region number */ |
| 22882 | cbShmName = sprintf(shmName, "\\SHAREMEM\\%s", fd->zFullPathCp ); |
| 22883 | if( cbShmName >= CCHMAXPATH-8 ) |
| 22884 | return SQLITE_IOERR_SHMOPEN; |
| 22885 | |
| 22886 | /* Replace colon in file name to form a valid shared memory name */ |
| 22887 | shmName[10+1] = '!'; |
| 22888 | |
| 22889 | /* Allocate link object (we free it later in case of failure) */ |
| 22890 | pLink = sqlite3_malloc( sizeof(*pLink) ); |
| 22891 | if( !pLink ) |
| 22892 | return SQLITE_NOMEM; |
| 22893 | |
| 22894 | /* Access node list */ |
| 22895 | os2ShmEnterMutex(); |
| 22896 | |
| 22897 | /* Find node by it's shared memory base name */ |
| 22898 | for( pNode = os2ShmNodeList; |
| 22899 | pNode && stricmp(shmName, pNode->shmBaseName) != 0; |
| 22900 | pNode = pNode->pNext ) ; |
| 22901 | |
| 22902 | /* Not found: allocate a new node */ |
| 22903 | if( !pNode ) { |
| 22904 | pNode = sqlite3_malloc( sizeof(*pNode) + cbShmName ); |
| 22905 | if( pNode ) { |
| 22906 | memset(pNode, 0, sizeof(*pNode) ); |
| 22907 | pNode->szRegion = szRegion; |
| 22908 | pNode->hLockFile = (HFILE)-1; |
| 22909 | strcpy(pNode->shmBaseName, shmName); |
| 22910 | |
| 22911 | #ifdef SQLITE_OS2_NO_WAL_LOCK_FILE |
| 22912 | if( DosDupHandle(fd->h, &pNode->hLockFile) != 0 ) { |
| 22913 | #else |
| 22914 | sprintf(shmName, "%s-lck", fd->zFullPathCp); |
| 22915 | if( DosOpen((PSZ)shmName, &pNode->hLockFile, &action, 0, FILE_NORMAL, |
| 22916 | OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW, |
| 22917 | OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE | |
| 22918 | OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR, |
| 22919 | NULL) != 0 ) { |
| 22920 | #endif |
| 22921 | sqlite3_free(pNode); |
| 22922 | rc = SQLITE_IOERR; |
| 22923 | } else { |
| 22924 | pNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); |
| 22925 | if( !pNode->mutex ) { |
| 22926 | sqlite3_free(pNode); |
| 22927 | rc = SQLITE_NOMEM; |
| 22928 | } |
| 22929 | } |
| 22930 | } else { |
| 22931 | rc = SQLITE_NOMEM; |
| 22932 | } |
| 22933 | |
| 22934 | if( rc == SQLITE_OK ) { |
| 22935 | pNode->pNext = os2ShmNodeList; |
| 22936 | os2ShmNodeList = pNode; |
| 22937 | } else { |
| 22938 | pNode = NULL; |
| 22939 | } |
| 22940 | } else if( pNode->szRegion != szRegion ) { |
| 22941 | rc = SQLITE_IOERR_SHMSIZE; |
| 22942 | pNode = NULL; |
| 22943 | } |
| 22944 | |
| 22945 | if( pNode ) { |
| 22946 | sqlite3_mutex_enter(pNode->mutex); |
| 22947 | |
| 22948 | memset(pLink, 0, sizeof(*pLink)); |
| 22949 | |
| 22950 | pLink->pShmNode = pNode; |
| 22951 | pLink->pNext = pNode->pFirst; |
| 22952 | pNode->pFirst = pLink; |
| 22953 | pNode->nRef++; |
| 22954 | |
| 22955 | fd->pShmLink = pLink; |
| 22956 | |
| 22957 | sqlite3_mutex_leave(pNode->mutex); |
| 22958 | |
| 22959 | } else { |
| 22960 | /* Error occured. Free our link object. */ |
| 22961 | sqlite3_free(pLink); |
| 22962 | } |
| 22963 | |
| 22964 | os2ShmLeaveMutex(); |
| 22965 | |
| 22966 | ERR_TRACE(rc, ("os2OpenSharedMemory: %d %s\n", rc, fd->zFullPathCp)) |
| 22967 | |
| 22968 | return rc; |
| 22969 | } |
| 22970 | |
| 22971 | /* |
| 22972 | ** Purge the os2ShmNodeList list of all entries with nRef==0. |
| 22973 | ** |
| 22974 | ** This is not a VFS shared-memory method; it is a utility function called |
| 22975 | ** by VFS shared-memory methods. |
| 22976 | */ |
| 22977 | static void os2PurgeShmNodes( int deleteFlag ) { |
| 22978 | os2ShmNode *pNode; |
| 22979 | os2ShmNode **ppNode; |
| 22980 | |
| 22981 | os2ShmEnterMutex(); |
| 22982 | |
| 22983 | ppNode = &os2ShmNodeList; |
| 22984 | |
| 22985 | while( *ppNode ) { |
| 22986 | pNode = *ppNode; |
| 22987 | |
| 22988 | if( pNode->nRef == 0 ) { |
| 22989 | *ppNode = pNode->pNext; |
| 22990 | |
| 22991 | if( pNode->apRegion ) { |
| 22992 | /* Prevent other processes from resizing the shared memory */ |
| 22993 | os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1); |
| 22994 | |
| 22995 | while( pNode->nRegion-- ) { |
| 22996 | #ifdef SQLITE_DEBUG |
| 22997 | int rc = |
| 22998 | #endif |
| 22999 | DosFreeMem(pNode->apRegion[pNode->nRegion]); |
| 23000 | |
| 23001 | OSTRACE(("SHM-PURGE pid-%d unmap region=%d %s\n", |
| 23002 | (int)GetCurrentProcessId(), pNode->nRegion, |
| 23003 | rc == 0 ? "ok" : "failed")); |
| 23004 | } |
| 23005 | |
| 23006 | /* Allow other processes to resize the shared memory */ |
| 23007 | os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1); |
| 23008 | |
| 23009 | sqlite3_free(pNode->apRegion); |
| 23010 | } |
| 23011 | |
| 23012 | DosClose(pNode->hLockFile); |
| 23013 | |
| 23014 | #ifndef SQLITE_OS2_NO_WAL_LOCK_FILE |
| 23015 | if( deleteFlag ) { |
| 23016 | char fileName[CCHMAXPATH]; |
| 23017 | /* Skip "\\SHAREMEM\\" */ |
| 23018 | sprintf(fileName, "%s-lck", pNode->shmBaseName + 10); |
| 23019 | /* restore colon */ |
| 23020 | fileName[1] = ':'; |
| 23021 | |
| 23022 | DosForceDelete(fileName); |
| 23023 | } |
| 23024 | #endif |
| 23025 | |
| 23026 | sqlite3_mutex_free(pNode->mutex); |
| 23027 | |
| 23028 | sqlite3_free(pNode); |
| 23029 | |
| 23030 | } else { |
| 23031 | ppNode = &pNode->pNext; |
| 23032 | } |
| 23033 | } |
| 23034 | |
| 23035 | os2ShmLeaveMutex(); |
| 23036 | } |
| 23037 | |
| 23038 | /* |
| 23039 | ** This function is called to obtain a pointer to region iRegion of the |
| 23040 | ** shared-memory associated with the database file id. Shared-memory regions |
| 23041 | ** are numbered starting from zero. Each shared-memory region is szRegion |
| 23042 | ** bytes in size. |
| 23043 | ** |
| 23044 | ** If an error occurs, an error code is returned and *pp is set to NULL. |
| 23045 | ** |
| 23046 | ** Otherwise, if the bExtend parameter is 0 and the requested shared-memory |
| 23047 | ** region has not been allocated (by any client, including one running in a |
| 23048 | ** separate process), then *pp is set to NULL and SQLITE_OK returned. If |
| 23049 | ** bExtend is non-zero and the requested shared-memory region has not yet |
| 23050 | ** been allocated, it is allocated by this function. |
| 23051 | ** |
| 23052 | ** If the shared-memory region has already been allocated or is allocated by |
| 23053 | ** this call as described above, then it is mapped into this processes |
| 23054 | ** address space (if it is not already), *pp is set to point to the mapped |
| 23055 | ** memory and SQLITE_OK returned. |
| 23056 | */ |
| 23057 | static int os2ShmMap( |
| 23058 | sqlite3_file *id, /* Handle open on database file */ |
| 23059 | int iRegion, /* Region to retrieve */ |
| 23060 | int szRegion, /* Size of regions */ |
| 23061 | int bExtend, /* True to extend block if necessary */ |
| 23062 | void volatile **pp /* OUT: Mapped memory */ |
| 23063 | ){ |
| 23064 | PVOID pvTemp; |
| 23065 | void **apRegion; |
| 23066 | os2ShmNode *pNode; |
| 23067 | int n, rc = SQLITE_OK; |
| 23068 | char shmName[CCHMAXPATH]; |
| 23069 | os2File *pFile = (os2File*)id; |
| 23070 | |
| 23071 | *pp = NULL; |
| 23072 | |
| 23073 | if( !pFile->pShmLink ) |
| 23074 | rc = os2OpenSharedMemory( pFile, szRegion ); |
| 23075 | |
| 23076 | if( rc == SQLITE_OK ) { |
| 23077 | pNode = pFile->pShmLink->pShmNode ; |
| 23078 | |
| 23079 | sqlite3_mutex_enter(pNode->mutex); |
| 23080 | |
| 23081 | assert( szRegion==pNode->szRegion ); |
| 23082 | |
| 23083 | /* Unmapped region ? */ |
| 23084 | if( iRegion >= pNode->nRegion ) { |
| 23085 | /* Prevent other processes from resizing the shared memory */ |
| 23086 | os2ShmSystemLock(pNode, _SHM_WRLCK_WAIT, OS2_SHM_DMS, 1); |
| 23087 | |
| 23088 | apRegion = sqlite3_realloc( |
| 23089 | pNode->apRegion, (iRegion + 1) * sizeof(apRegion[0])); |
| 23090 | |
| 23091 | if( apRegion ) { |
| 23092 | pNode->apRegion = apRegion; |
| 23093 | |
| 23094 | while( pNode->nRegion <= iRegion ) { |
| 23095 | sprintf(shmName, "%s-%u", |
| 23096 | pNode->shmBaseName, pNode->nRegion); |
| 23097 | |
| 23098 | if( DosGetNamedSharedMem(&pvTemp, (PSZ)shmName, |
| 23099 | PAG_READ | PAG_WRITE) != NO_ERROR ) { |
| 23100 | if( !bExtend ) |
| 23101 | break; |
| 23102 | |
| 23103 | if( DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion, |
| 23104 | PAG_READ | PAG_WRITE | PAG_COMMIT | OBJ_ANY) != NO_ERROR && |
| 23105 | DosAllocSharedMem(&pvTemp, (PSZ)shmName, szRegion, |
| 23106 | PAG_READ | PAG_WRITE | PAG_COMMIT) != NO_ERROR ) { |
| 23107 | rc = SQLITE_NOMEM; |
| 23108 | break; |
| 23109 | } |
| 23110 | } |
| 23111 | |
| 23112 | apRegion[pNode->nRegion++] = pvTemp; |
| 23113 | } |
| 23114 | |
| 23115 | /* zero out remaining entries */ |
| 23116 | for( n = pNode->nRegion; n <= iRegion; n++ ) |
| 23117 | pNode->apRegion[n] = NULL; |
| 23118 | |
| 23119 | /* Return this region (maybe zero) */ |
| 23120 | *pp = pNode->apRegion[iRegion]; |
| 23121 | } else { |
| 23122 | rc = SQLITE_NOMEM; |
| 23123 | } |
| 23124 | |
| 23125 | /* Allow other processes to resize the shared memory */ |
| 23126 | os2ShmSystemLock(pNode, _SHM_UNLCK, OS2_SHM_DMS, 1); |
| 23127 | |
| 23128 | } else { |
| 23129 | /* Region has been mapped previously */ |
| 23130 | *pp = pNode->apRegion[iRegion]; |
| 23131 | } |
| 23132 | |
| 23133 | sqlite3_mutex_leave(pNode->mutex); |
| 23134 | } |
| 23135 | |
| 23136 | ERR_TRACE(rc, ("os2ShmMap: %s iRgn = %d, szRgn = %d, bExt = %d : %d\n", |
| 23137 | pFile->zFullPathCp, iRegion, szRegion, bExtend, rc)) |
| 23138 | |
| 23139 | return rc; |
| 23140 | } |
| 23141 | |
| 23142 | /* |
| 23143 | ** Close a connection to shared-memory. Delete the underlying |
| 23144 | ** storage if deleteFlag is true. |
| 23145 | ** |
| 23146 | ** If there is no shared memory associated with the connection then this |
| 23147 | ** routine is a harmless no-op. |
| 23148 | */ |
| 23149 | static int os2ShmUnmap( |
| 23150 | sqlite3_file *id, /* The underlying database file */ |
| 23151 | int deleteFlag /* Delete shared-memory if true */ |
| 23152 | ){ |
| 23153 | os2File *pFile = (os2File*)id; |
| 23154 | os2ShmLink *pLink = pFile->pShmLink; |
| 23155 | |
| 23156 | if( pLink ) { |
| 23157 | int nRef = -1; |
| 23158 | os2ShmLink **ppLink; |
| 23159 | os2ShmNode *pNode = pLink->pShmNode; |
| 23160 | |
| 23161 | sqlite3_mutex_enter(pNode->mutex); |
| 23162 | |
| 23163 | for( ppLink = &pNode->pFirst; |
| 23164 | *ppLink && *ppLink != pLink; |
| 23165 | ppLink = &(*ppLink)->pNext ) ; |
| 23166 | |
| 23167 | assert(*ppLink); |
| 23168 | |
| 23169 | if( *ppLink ) { |
| 23170 | *ppLink = pLink->pNext; |
| 23171 | nRef = --pNode->nRef; |
| 23172 | } else { |
| 23173 | ERR_TRACE(1, ("os2ShmUnmap: link not found ! %s\n", |
| 23174 | pNode->shmBaseName)) |
| 23175 | } |
| 23176 | |
| 23177 | pFile->pShmLink = NULL; |
| 23178 | sqlite3_free(pLink); |
| 23179 | |
| 23180 | sqlite3_mutex_leave(pNode->mutex); |
| 23181 | |
| 23182 | if( nRef == 0 ) |
| 23183 | os2PurgeShmNodes( deleteFlag ); |
| 23184 | } |
| 23185 | |
| 23186 | return SQLITE_OK; |
| 23187 | } |
| 23188 | |
| 23189 | /* |
| 23190 | ** Change the lock state for a shared-memory segment. |
| 23191 | ** |
| 23192 | ** Note that the relationship between SHAREd and EXCLUSIVE locks is a little |
| 23193 | ** different here than in posix. In xShmLock(), one can go from unlocked |
| 23194 | ** to shared and back or from unlocked to exclusive and back. But one may |
| 23195 | ** not go from shared to exclusive or from exclusive to shared. |
| 23196 | */ |
| 23197 | static int os2ShmLock( |
| 23198 | sqlite3_file *id, /* Database file holding the shared memory */ |
| 23199 | int ofst, /* First lock to acquire or release */ |
| 23200 | int n, /* Number of locks to acquire or release */ |
| 23201 | int flags /* What to do with the lock */ |
| 23202 | ){ |
| 23203 | u32 mask; /* Mask of locks to take or release */ |
| 23204 | int rc = SQLITE_OK; /* Result code */ |
| 23205 | os2File *pFile = (os2File*)id; |
| 23206 | os2ShmLink *p = pFile->pShmLink; /* The shared memory being locked */ |
| 23207 | os2ShmLink *pX; /* For looping over all siblings */ |
| 23208 | os2ShmNode *pShmNode = p->pShmNode; /* Our node */ |
| 23209 | |
| 23210 | assert( ofst>=0 && ofst+n<=SQLITE_SHM_NLOCK ); |
| 23211 | assert( n>=1 ); |
| 23212 | assert( flags==(SQLITE_SHM_LOCK | SQLITE_SHM_SHARED) |
| 23213 | || flags==(SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE) |
| 23214 | || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) |
| 23215 | || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); |
| 23216 | assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); |
| 23217 | |
| 23218 | mask = (u32)((1U<<(ofst+n)) - (1U<<ofst)); |
| 23219 | assert( n>1 || mask==(1<<ofst) ); |
| 23220 | |
| 23221 | |
| 23222 | sqlite3_mutex_enter(pShmNode->mutex); |
| 23223 | |
| 23224 | if( flags & SQLITE_SHM_UNLOCK ){ |
| 23225 | u32 allMask = 0; /* Mask of locks held by siblings */ |
| 23226 | |
| 23227 | /* See if any siblings hold this same lock */ |
| 23228 | for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ |
| 23229 | if( pX==p ) continue; |
| 23230 | assert( (pX->exclMask & (p->exclMask|p->sharedMask))==0 ); |
| 23231 | allMask |= pX->sharedMask; |
| 23232 | } |
| 23233 | |
| 23234 | /* Unlock the system-level locks */ |
| 23235 | if( (mask & allMask)==0 ){ |
| 23236 | rc = os2ShmSystemLock(pShmNode, _SHM_UNLCK, ofst+OS2_SHM_BASE, n); |
| 23237 | }else{ |
| 23238 | rc = SQLITE_OK; |
| 23239 | } |
| 23240 | |
| 23241 | /* Undo the local locks */ |
| 23242 | if( rc==SQLITE_OK ){ |
| 23243 | p->exclMask &= ~mask; |
| 23244 | p->sharedMask &= ~mask; |
| 23245 | } |
| 23246 | }else if( flags & SQLITE_SHM_SHARED ){ |
| 23247 | u32 allShared = 0; /* Union of locks held by connections other than "p" */ |
| 23248 | |
| 23249 | /* Find out which shared locks are already held by sibling connections. |
| 23250 | ** If any sibling already holds an exclusive lock, go ahead and return |
| 23251 | ** SQLITE_BUSY. |
| 23252 | */ |
| 23253 | for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ |
| 23254 | if( (pX->exclMask & mask)!=0 ){ |
| 23255 | rc = SQLITE_BUSY; |
| 23256 | break; |
| 23257 | } |
| 23258 | allShared |= pX->sharedMask; |
| 23259 | } |
| 23260 | |
| 23261 | /* Get shared locks at the system level, if necessary */ |
| 23262 | if( rc==SQLITE_OK ){ |
| 23263 | if( (allShared & mask)==0 ){ |
| 23264 | rc = os2ShmSystemLock(pShmNode, _SHM_RDLCK, ofst+OS2_SHM_BASE, n); |
| 23265 | }else{ |
| 23266 | rc = SQLITE_OK; |
| 23267 | } |
| 23268 | } |
| 23269 | |
| 23270 | /* Get the local shared locks */ |
| 23271 | if( rc==SQLITE_OK ){ |
| 23272 | p->sharedMask |= mask; |
| 23273 | } |
| 23274 | }else{ |
| 23275 | /* Make sure no sibling connections hold locks that will block this |
| 23276 | ** lock. If any do, return SQLITE_BUSY right away. |
| 23277 | */ |
| 23278 | for(pX=pShmNode->pFirst; pX; pX=pX->pNext){ |
| 23279 | if( (pX->exclMask & mask)!=0 || (pX->sharedMask & mask)!=0 ){ |
| 23280 | rc = SQLITE_BUSY; |
| 23281 | break; |
| 23282 | } |
| 23283 | } |
| 23284 | |
| 23285 | /* Get the exclusive locks at the system level. Then if successful |
| 23286 | ** also mark the local connection as being locked. |
| 23287 | */ |
| 23288 | if( rc==SQLITE_OK ){ |
| 23289 | rc = os2ShmSystemLock(pShmNode, _SHM_WRLCK, ofst+OS2_SHM_BASE, n); |
| 23290 | if( rc==SQLITE_OK ){ |
| 23291 | assert( (p->sharedMask & mask)==0 ); |
| 23292 | p->exclMask |= mask; |
| 23293 | } |
| 23294 | } |
| 23295 | } |
| 23296 | |
| 23297 | sqlite3_mutex_leave(pShmNode->mutex); |
| 23298 | |
| 23299 | OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x %s\n", |
| 23300 | p->id, (int)GetCurrentProcessId(), p->sharedMask, p->exclMask, |
| 23301 | rc ? "failed" : "ok")); |
| 23302 | |
| 23303 | ERR_TRACE(rc, ("os2ShmLock: ofst = %d, n = %d, flags = 0x%x -> %d \n", |
| 23304 | ofst, n, flags, rc)) |
| 23305 | |
| 23306 | return rc; |
| 23307 | } |
| 23308 | |
| 23309 | /* |
| 23310 | ** Implement a memory barrier or memory fence on shared memory. |
| 23311 | ** |
| 23312 | ** All loads and stores begun before the barrier must complete before |
| 23313 | ** any load or store begun after the barrier. |
| 23314 | */ |
| 23315 | static void os2ShmBarrier( |
| 23316 | sqlite3_file *id /* Database file holding the shared memory */ |
| 23317 | ){ |
| 23318 | UNUSED_PARAMETER(id); |
| 23319 | os2ShmEnterMutex(); |
| 23320 | os2ShmLeaveMutex(); |
| 23321 | } |
| 23322 | |
| 23323 | #else |
| 23324 | # define os2ShmMap 0 |
| 23325 | # define os2ShmLock 0 |
| 23326 | # define os2ShmBarrier 0 |
| 23327 | # define os2ShmUnmap 0 |
| 23328 | #endif /* #ifndef SQLITE_OMIT_WAL */ |
| 23329 | |
| 23330 | |
| 23331 | /* |
| 23332 | ** This vector defines all the methods that can operate on an |
| 23333 | ** sqlite3_file for os2. |
| 23334 | */ |
| 23335 | static const sqlite3_io_methods os2IoMethod = { |
| 23336 | 2, /* iVersion */ |
| 23337 | os2Close, /* xClose */ |
| 23338 | os2Read, /* xRead */ |
| 23339 | os2Write, /* xWrite */ |
| 23340 | os2Truncate, /* xTruncate */ |
| 23341 | os2Sync, /* xSync */ |
| @@ -22649,15 +23344,16 @@ | |
| 23344 | os2Unlock, /* xUnlock */ |
| 23345 | os2CheckReservedLock, /* xCheckReservedLock */ |
| 23346 | os2FileControl, /* xFileControl */ |
| 23347 | os2SectorSize, /* xSectorSize */ |
| 23348 | os2DeviceCharacteristics, /* xDeviceCharacteristics */ |
| 23349 | os2ShmMap, /* xShmMap */ |
| 23350 | os2ShmLock, /* xShmLock */ |
| 23351 | os2ShmBarrier, /* xShmBarrier */ |
| 23352 | os2ShmUnmap /* xShmUnmap */ |
| 23353 | }; |
| 23354 | |
| 23355 | |
| 23356 | /*************************************************************************** |
| 23357 | ** Here ends the I/O methods that form the sqlite3_io_methods object. |
| 23358 | ** |
| 23359 | ** The next block of code implements the VFS methods. |
| @@ -22666,54 +23362,61 @@ | |
| 23362 | /* |
| 23363 | ** Create a temporary file name in zBuf. zBuf must be big enough to |
| 23364 | ** hold at pVfs->mxPathname characters. |
| 23365 | */ |
| 23366 | static int getTempname(int nBuf, char *zBuf ){ |
| 23367 | static const char zChars[] = |
| 23368 | "abcdefghijklmnopqrstuvwxyz" |
| 23369 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 23370 | "0123456789"; |
| 23371 | int i, j; |
| 23372 | PSZ zTempPathCp; |
| 23373 | char zTempPath[CCHMAXPATH]; |
| 23374 | ULONG ulDriveNum, ulDriveMap; |
| 23375 | |
| 23376 | /* It's odd to simulate an io-error here, but really this is just |
| 23377 | ** using the io-error infrastructure to test that SQLite handles this |
| 23378 | ** function failing. |
| 23379 | */ |
| 23380 | SimulateIOError( return SQLITE_IOERR ); |
| 23381 | |
| 23382 | if( sqlite3_temp_directory ) { |
| 23383 | sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", sqlite3_temp_directory); |
| 23384 | } else if( DosScanEnv( (PSZ)"TEMP", &zTempPathCp ) == NO_ERROR || |
| 23385 | DosScanEnv( (PSZ)"TMP", &zTempPathCp ) == NO_ERROR || |
| 23386 | DosScanEnv( (PSZ)"TMPDIR", &zTempPathCp ) == NO_ERROR ) { |
| 23387 | char *zTempPathUTF = convertCpPathToUtf8( (char *)zTempPathCp ); |
| 23388 | sqlite3_snprintf(CCHMAXPATH-30, zTempPath, "%s", zTempPathUTF); |
| 23389 | free( zTempPathUTF ); |
| 23390 | } else if( DosQueryCurrentDisk( &ulDriveNum, &ulDriveMap ) == NO_ERROR ) { |
| 23391 | zTempPath[0] = (char)('A' + ulDriveNum - 1); |
| 23392 | zTempPath[1] = ':'; |
| 23393 | zTempPath[2] = '\0'; |
| 23394 | } else { |
| 23395 | zTempPath[0] = '\0'; |
| 23396 | } |
| 23397 | |
| 23398 | /* Strip off a trailing slashes or backslashes, otherwise we would get * |
| 23399 | * multiple (back)slashes which causes DosOpen() to fail. * |
| 23400 | * Trailing spaces are not allowed, either. */ |
| 23401 | j = sqlite3Strlen30(zTempPath); |
| 23402 | while( j > 0 && ( zTempPath[j-1] == '\\' || zTempPath[j-1] == '/' || |
| 23403 | zTempPath[j-1] == ' ' ) ){ |
| 23404 | j--; |
| 23405 | } |
| 23406 | zTempPath[j] = '\0'; |
| 23407 | |
| 23408 | /* We use 20 bytes to randomize the name */ |
| 23409 | sqlite3_snprintf(nBuf-22, zBuf, |
| 23410 | "%s\\"SQLITE_TEMP_FILE_PREFIX, zTempPath); |
| 23411 | j = sqlite3Strlen30(zBuf); |
| 23412 | sqlite3_randomness( 20, &zBuf[j] ); |
| 23413 | for( i = 0; i < 20; i++, j++ ){ |
| 23414 | zBuf[j] = zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
| 23415 | } |
| 23416 | zBuf[j] = 0; |
| 23417 | |
| 23418 | OSTRACE(( "TEMP FILENAME: %s\n", zBuf )); |
| 23419 | return SQLITE_OK; |
| 23420 | } |
| 23421 | |
| 23422 | |
| @@ -22729,12 +23432,12 @@ | |
| 23432 | char *zFull /* Output buffer */ |
| 23433 | ){ |
| 23434 | char *zRelativeCp = convertUtf8PathToCp( zRelative ); |
| 23435 | char zFullCp[CCHMAXPATH] = "\0"; |
| 23436 | char *zFullUTF; |
| 23437 | APIRET rc = DosQueryPathInfo( (PSZ)zRelativeCp, FIL_QUERYFULLNAME, |
| 23438 | zFullCp, CCHMAXPATH ); |
| 23439 | free( zRelativeCp ); |
| 23440 | zFullUTF = convertCpPathToUtf8( zFullCp ); |
| 23441 | sqlite3_snprintf( nFull, zFull, zFullUTF ); |
| 23442 | free( zFullUTF ); |
| 23443 | return rc == NO_ERROR ? SQLITE_OK : SQLITE_IOERR; |
| @@ -22760,14 +23463,14 @@ | |
| 23463 | const char *zUtf8Name = zName; |
| 23464 | char *zNameCp; |
| 23465 | char zTmpname[CCHMAXPATH]; |
| 23466 | |
| 23467 | int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); |
| 23468 | int isCreate = (flags & SQLITE_OPEN_CREATE); |
| 23469 | int isReadWrite = (flags & SQLITE_OPEN_READWRITE); |
| 23470 | #ifndef NDEBUG |
| 23471 | int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); |
| 23472 | int isReadonly = (flags & SQLITE_OPEN_READONLY); |
| 23473 | int eType = (flags & 0xFFFFFF00); |
| 23474 | int isOpenJournal = (isCreate && ( |
| 23475 | eType==SQLITE_OPEN_MASTER_JOURNAL |
| 23476 | || eType==SQLITE_OPEN_MAIN_JOURNAL |
| @@ -22803,11 +23506,11 @@ | |
| 23506 | || eType==SQLITE_OPEN_SUBJOURNAL || eType==SQLITE_OPEN_MASTER_JOURNAL |
| 23507 | || eType==SQLITE_OPEN_TRANSIENT_DB || eType==SQLITE_OPEN_WAL |
| 23508 | ); |
| 23509 | |
| 23510 | memset( pFile, 0, sizeof(*pFile) ); |
| 23511 | pFile->h = (HFILE)-1; |
| 23512 | |
| 23513 | /* If the second argument to this function is NULL, generate a |
| 23514 | ** temporary file name to use |
| 23515 | */ |
| 23516 | if( !zUtf8Name ){ |
| @@ -22825,15 +23528,15 @@ | |
| 23528 | ulOpenMode |= OPEN_ACCESS_READONLY; |
| 23529 | } |
| 23530 | |
| 23531 | /* Open in random access mode for possibly better speed. Allow full |
| 23532 | ** sharing because file locks will provide exclusive access when needed. |
| 23533 | ** The handle should not be inherited by child processes and we don't |
| 23534 | ** want popups from the critical error handler. |
| 23535 | */ |
| 23536 | ulOpenMode |= OPEN_FLAGS_RANDOM | OPEN_SHARE_DENYNONE | |
| 23537 | OPEN_FLAGS_NOINHERIT | OPEN_FLAGS_FAIL_ON_ERROR; |
| 23538 | |
| 23539 | /* SQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is |
| 23540 | ** created. SQLite doesn't use it to indicate "exclusive access" |
| 23541 | ** as it is usually understood. |
| 23542 | */ |
| @@ -22847,17 +23550,10 @@ | |
| 23550 | }else{ |
| 23551 | /* Opens a file, only if it exists. */ |
| 23552 | ulOpenFlags |= OPEN_ACTION_FAIL_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS; |
| 23553 | } |
| 23554 | |
| 23555 | zNameCp = convertUtf8PathToCp( zUtf8Name ); |
| 23556 | rc = DosOpen( (PSZ)zNameCp, |
| 23557 | &h, |
| 23558 | &ulAction, |
| 23559 | 0L, |
| @@ -22868,13 +23564,10 @@ | |
| 23564 | free( zNameCp ); |
| 23565 | |
| 23566 | if( rc != NO_ERROR ){ |
| 23567 | OSTRACE(( "OPEN Invalid handle rc=%d: zName=%s, ulAction=%#lx, ulFlags=%#lx, ulMode=%#lx\n", |
| 23568 | rc, zUtf8Name, ulAction, ulOpenFlags, ulOpenMode )); |
| 23569 | |
| 23570 | if( isReadWrite ){ |
| 23571 | return os2Open( pVfs, zName, id, |
| 23572 | ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), |
| 23573 | pOutFlags ); |
| @@ -22885,11 +23578,16 @@ | |
| 23578 | |
| 23579 | if( pOutFlags ){ |
| 23580 | *pOutFlags = isReadWrite ? SQLITE_OPEN_READWRITE : SQLITE_OPEN_READONLY; |
| 23581 | } |
| 23582 | |
| 23583 | os2FullPathname( pVfs, zUtf8Name, sizeof( zTmpname ), zTmpname ); |
| 23584 | pFile->zFullPathCp = convertUtf8PathToCp( zTmpname ); |
| 23585 | pFile->pMethod = &os2IoMethod; |
| 23586 | pFile->flags = flags; |
| 23587 | pFile->h = h; |
| 23588 | |
| 23589 | OpenCounter(+1); |
| 23590 | OSTRACE(( "OPEN %d pOutFlags=%d\n", pFile->h, pOutFlags )); |
| 23591 | return SQLITE_OK; |
| 23592 | } |
| 23593 | |
| @@ -22920,34 +23618,46 @@ | |
| 23618 | sqlite3_vfs *pVfs, /* Not used on os2 */ |
| 23619 | const char *zFilename, /* Name of file to check */ |
| 23620 | int flags, /* Type of test to make on this file */ |
| 23621 | int *pOut /* Write results here */ |
| 23622 | ){ |
| 23623 | APIRET rc; |
| 23624 | FILESTATUS3 fsts3ConfigInfo; |
| 23625 | char *zFilenameCp; |
| 23626 | |
| 23627 | UNUSED_PARAMETER(pVfs); |
| 23628 | SimulateIOError( return SQLITE_IOERR_ACCESS; ); |
| 23629 | |
| 23630 | zFilenameCp = convertUtf8PathToCp( zFilename ); |
| 23631 | rc = DosQueryPathInfo( (PSZ)zFilenameCp, FIL_STANDARD, |
| 23632 | &fsts3ConfigInfo, sizeof(FILESTATUS3) ); |
| 23633 | free( zFilenameCp ); |
| 23634 | OSTRACE(( "ACCESS fsts3ConfigInfo.attrFile=%d flags=%d rc=%d\n", |
| 23635 | fsts3ConfigInfo.attrFile, flags, rc )); |
| 23636 | |
| 23637 | switch( flags ){ |
| 23638 | case SQLITE_ACCESS_EXISTS: |
| 23639 | /* For an SQLITE_ACCESS_EXISTS query, treat a zero-length file |
| 23640 | ** as if it does not exist. |
| 23641 | */ |
| 23642 | if( fsts3ConfigInfo.cbFile == 0 ) |
| 23643 | rc = ERROR_FILE_NOT_FOUND; |
| 23644 | break; |
| 23645 | case SQLITE_ACCESS_READ: |
| 23646 | break; |
| 23647 | case SQLITE_ACCESS_READWRITE: |
| 23648 | if( fsts3ConfigInfo.attrFile & FILE_READONLY ) |
| 23649 | rc = ERROR_ACCESS_DENIED; |
| 23650 | break; |
| 23651 | default: |
| 23652 | rc = ERROR_FILE_NOT_FOUND; |
| 23653 | assert( !"Invalid flags argument" ); |
| 23654 | } |
| 23655 | |
| 23656 | *pOut = (rc == NO_ERROR); |
| 23657 | OSTRACE(( "ACCESS %s flags %d: rc=%d\n", zFilename, flags, *pOut )); |
| 23658 | |
| 23659 | return SQLITE_OK; |
| 23660 | } |
| 23661 | |
| 23662 | |
| 23663 | #ifndef SQLITE_OMIT_LOAD_EXTENSION |
| @@ -22958,15 +23668,14 @@ | |
| 23668 | /* |
| 23669 | ** Interfaces for opening a shared library, finding entry points |
| 23670 | ** within the shared library, and closing the shared library. |
| 23671 | */ |
| 23672 | static void *os2DlOpen(sqlite3_vfs *pVfs, const char *zFilename){ |
| 23673 | HMODULE hmod; |
| 23674 | APIRET rc; |
| 23675 | char *zFilenameCp = convertUtf8PathToCp(zFilename); |
| 23676 | rc = DosLoadModule(NULL, 0, (PSZ)zFilenameCp, &hmod); |
| 23677 | free(zFilenameCp); |
| 23678 | return rc != NO_ERROR ? 0 : (void*)hmod; |
| 23679 | } |
| 23680 | /* |
| 23681 | ** A no-op since the error code is returned on the DosLoadModule call. |
| @@ -22976,18 +23685,18 @@ | |
| 23685 | /* no-op */ |
| 23686 | } |
| 23687 | static void (*os2DlSym(sqlite3_vfs *pVfs, void *pHandle, const char *zSymbol))(void){ |
| 23688 | PFN pfn; |
| 23689 | APIRET rc; |
| 23690 | rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)zSymbol, &pfn); |
| 23691 | if( rc != NO_ERROR ){ |
| 23692 | /* if the symbol itself was not found, search again for the same |
| 23693 | * symbol with an extra underscore, that might be needed depending |
| 23694 | * on the calling convention */ |
| 23695 | char _zSymbol[256] = "_"; |
| 23696 | strncat(_zSymbol, zSymbol, 254); |
| 23697 | rc = DosQueryProcAddr((HMODULE)pHandle, 0L, (PSZ)_zSymbol, &pfn); |
| 23698 | } |
| 23699 | return rc != NO_ERROR ? 0 : (void(*)(void))pfn; |
| 23700 | } |
| 23701 | static void os2DlClose(sqlite3_vfs *pVfs, void *pHandle){ |
| 23702 | DosFreeModule((HMODULE)pHandle); |
| @@ -23007,58 +23716,43 @@ | |
| 23716 | int n = 0; |
| 23717 | #if defined(SQLITE_TEST) |
| 23718 | n = nBuf; |
| 23719 | memset(zBuf, 0, nBuf); |
| 23720 | #else |
| 23721 | int i; |
| 23722 | PPIB ppib; |
| 23723 | PTIB ptib; |
| 23724 | DATETIME dt; |
| 23725 | static unsigned c = 0; |
| 23726 | /* Ordered by variation probability */ |
| 23727 | static ULONG svIdx[6] = { QSV_MS_COUNT, QSV_TIME_LOW, |
| 23728 | QSV_MAXPRMEM, QSV_MAXSHMEM, |
| 23729 | QSV_TOTAVAILMEM, QSV_TOTRESMEM }; |
| 23730 | |
| 23731 | /* 8 bytes; timezone and weekday don't increase the randomness much */ |
| 23732 | if( (int)sizeof(dt)-3 <= nBuf - n ){ |
| 23733 | c += 0x0100; |
| 23734 | DosGetDateTime(&dt); |
| 23735 | dt.year = (USHORT)((dt.year - 1900) | c); |
| 23736 | memcpy(&zBuf[n], &dt, sizeof(dt)-3); |
| 23737 | n += sizeof(dt)-3; |
| 23738 | } |
| 23739 | |
| 23740 | /* 4 bytes; PIDs and TIDs are 16 bit internally, so combine them */ |
| 23741 | if( (int)sizeof(ULONG) <= nBuf - n ){ |
| 23742 | DosGetInfoBlocks(&ptib, &ppib); |
| 23743 | *(PULONG)&zBuf[n] = MAKELONG(ppib->pib_ulpid, |
| 23744 | ptib->tib_ptib2->tib2_ultid); |
| 23745 | n += sizeof(ULONG); |
| 23746 | } |
| 23747 | |
| 23748 | /* Up to 6 * 4 bytes; variables depend on the system state */ |
| 23749 | for( i = 0; i < 6 && (int)sizeof(ULONG) <= nBuf - n; i++ ){ |
| 23750 | DosQuerySysInfo(svIdx[i], svIdx[i], |
| 23751 | (PULONG)&zBuf[n], sizeof(ULONG)); |
| 23752 | n += sizeof(ULONG); |
| 23753 | } |
| 23754 | #endif |
| 23755 | |
| 23756 | return n; |
| 23757 | } |
| 23758 | |
| @@ -23082,68 +23776,102 @@ | |
| 23776 | #ifdef SQLITE_TEST |
| 23777 | SQLITE_API int sqlite3_current_time = 0; |
| 23778 | #endif |
| 23779 | |
| 23780 | /* |
| 23781 | ** Find the current time (in Universal Coordinated Time). Write into *piNow |
| 23782 | ** the current time and date as a Julian Day number times 86_400_000. In |
| 23783 | ** other words, write into *piNow the number of milliseconds since the Julian |
| 23784 | ** epoch of noon in Greenwich on November 24, 4714 B.C according to the |
| 23785 | ** proleptic Gregorian calendar. |
| 23786 | ** |
| 23787 | ** On success, return 0. Return 1 if the time and date cannot be found. |
| 23788 | */ |
| 23789 | static int os2CurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow){ |
| 23790 | #ifdef SQLITE_TEST |
| 23791 | static const sqlite3_int64 unixEpoch = 24405875*(sqlite3_int64)8640000; |
| 23792 | #endif |
| 23793 | int year, month, datepart, timepart; |
| 23794 | |
| 23795 | DATETIME dt; |
| 23796 | DosGetDateTime( &dt ); |
| 23797 | |
| 23798 | year = dt.year; |
| 23799 | month = dt.month; |
| 23800 | |
| 23801 | /* Calculations from http://www.astro.keele.ac.uk/~rno/Astronomy/hjd.html |
| 23802 | ** http://www.astro.keele.ac.uk/~rno/Astronomy/hjd-0.1.c |
| 23803 | ** Calculate the Julian days |
| 23804 | */ |
| 23805 | datepart = (int)dt.day - 32076 + |
| 23806 | 1461*(year + 4800 + (month - 14)/12)/4 + |
| 23807 | 367*(month - 2 - (month - 14)/12*12)/12 - |
| 23808 | 3*((year + 4900 + (month - 14)/12)/100)/4; |
| 23809 | |
| 23810 | /* Time in milliseconds, hours to noon added */ |
| 23811 | timepart = 12*3600*1000 + dt.hundredths*10 + dt.seconds*1000 + |
| 23812 | ((int)dt.minutes + dt.timezone)*60*1000 + dt.hours*3600*1000; |
| 23813 | |
| 23814 | *piNow = (sqlite3_int64)datepart*86400*1000 + timepart; |
| 23815 | |
| 23816 | #ifdef SQLITE_TEST |
| 23817 | if( sqlite3_current_time ){ |
| 23818 | *piNow = 1000*(sqlite3_int64)sqlite3_current_time + unixEpoch; |
| 23819 | } |
| 23820 | #endif |
| 23821 | |
| 23822 | UNUSED_PARAMETER(pVfs); |
| 23823 | return 0; |
| 23824 | } |
| 23825 | |
| 23826 | /* |
| 23827 | ** Find the current time (in Universal Coordinated Time). Write the |
| 23828 | ** current time and date as a Julian Day number into *prNow and |
| 23829 | ** return 0. Return 1 if the time and date cannot be found. |
| 23830 | */ |
| 23831 | static int os2CurrentTime( sqlite3_vfs *pVfs, double *prNow ){ |
| 23832 | int rc; |
| 23833 | sqlite3_int64 i; |
| 23834 | rc = os2CurrentTimeInt64(pVfs, &i); |
| 23835 | if( !rc ){ |
| 23836 | *prNow = i/86400000.0; |
| 23837 | } |
| 23838 | return rc; |
| 23839 | } |
| 23840 | |
| 23841 | /* |
| 23842 | ** The idea is that this function works like a combination of |
| 23843 | ** GetLastError() and FormatMessage() on windows (or errno and |
| 23844 | ** strerror_r() on unix). After an error is returned by an OS |
| 23845 | ** function, SQLite calls this function with zBuf pointing to |
| 23846 | ** a buffer of nBuf bytes. The OS layer should populate the |
| 23847 | ** buffer with a nul-terminated UTF-8 encoded error message |
| 23848 | ** describing the last IO error to have occurred within the calling |
| 23849 | ** thread. |
| 23850 | ** |
| 23851 | ** If the error message is too large for the supplied buffer, |
| 23852 | ** it should be truncated. The return value of xGetLastError |
| 23853 | ** is zero if the error message fits in the buffer, or non-zero |
| 23854 | ** otherwise (if the message was truncated). If non-zero is returned, |
| 23855 | ** then it is not necessary to include the nul-terminator character |
| 23856 | ** in the output buffer. |
| 23857 | ** |
| 23858 | ** Not supplying an error message will have no adverse effect |
| 23859 | ** on SQLite. It is fine to have an implementation that never |
| 23860 | ** returns an error message: |
| 23861 | ** |
| 23862 | ** int xGetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
| 23863 | ** assert(zBuf[0]=='\0'); |
| 23864 | ** return 0; |
| 23865 | ** } |
| 23866 | ** |
| 23867 | ** However if an error message is supplied, it will be incorporated |
| 23868 | ** by sqlite into the error message available to the user using |
| 23869 | ** sqlite3_errmsg(), possibly making IO errors easier to debug. |
| 23870 | */ |
| 23871 | static int os2GetLastError(sqlite3_vfs *pVfs, int nBuf, char *zBuf){ |
| 23872 | assert(zBuf[0]=='\0'); |
| 23873 | return 0; |
| 23874 | } |
| 23875 | |
| 23876 | /* |
| 23877 | ** Initialize and deinitialize the operating system interface. |
| @@ -23167,17 +23895,18 @@ | |
| 23895 | os2DlClose, /* xDlClose */ |
| 23896 | os2Randomness, /* xRandomness */ |
| 23897 | os2Sleep, /* xSleep */ |
| 23898 | os2CurrentTime, /* xCurrentTime */ |
| 23899 | os2GetLastError, /* xGetLastError */ |
| 23900 | os2CurrentTimeInt64, /* xCurrentTimeInt64 */ |
| 23901 | 0, /* xSetSystemCall */ |
| 23902 | 0, /* xGetSystemCall */ |
| 23903 | 0 /* xNextSystemCall */ |
| 23904 | }; |
| 23905 | sqlite3_vfs_register(&os2Vfs, 1); |
| 23906 | initUconvObjects(); |
| 23907 | /* sqlite3OSTrace = 1; */ |
| 23908 | return SQLITE_OK; |
| 23909 | } |
| 23910 | SQLITE_API int sqlite3_os_end(void){ |
| 23911 | freeUconvObjects(); |
| 23912 | return SQLITE_OK; |
| @@ -23752,12 +24481,14 @@ | |
| 24481 | { "pwrite64", (sqlite3_syscall_ptr)0, 0 }, |
| 24482 | #endif |
| 24483 | #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| 24484 | aSyscall[13].pCurrent) |
| 24485 | |
| 24486 | #if SQLITE_ENABLE_LOCKING_STYLE |
| 24487 | { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, |
| 24488 | #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) |
| 24489 | #endif |
| 24490 | |
| 24491 | #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE |
| 24492 | { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, |
| 24493 | #else |
| 24494 | { "fallocate", (sqlite3_syscall_ptr)0, 0 }, |
| @@ -54608,10 +55339,14 @@ | |
| 55339 | Pager * const pDestPager = sqlite3BtreePager(p->pDest); |
| 55340 | const int nSrcPgsz = sqlite3BtreeGetPageSize(p->pSrc); |
| 55341 | int nDestPgsz = sqlite3BtreeGetPageSize(p->pDest); |
| 55342 | const int nCopy = MIN(nSrcPgsz, nDestPgsz); |
| 55343 | const i64 iEnd = (i64)iSrcPg*(i64)nSrcPgsz; |
| 55344 | #ifdef SQLITE_HAS_CODEC |
| 55345 | int nSrcReserve = sqlite3BtreeGetReserve(p->pSrc); |
| 55346 | int nDestReserve = sqlite3BtreeGetReserve(p->pDest); |
| 55347 | #endif |
| 55348 | |
| 55349 | int rc = SQLITE_OK; |
| 55350 | i64 iOff; |
| 55351 | |
| 55352 | assert( p->bDestLocked ); |
| @@ -54626,15 +55361,26 @@ | |
| 55361 | rc = SQLITE_READONLY; |
| 55362 | } |
| 55363 | |
| 55364 | #ifdef SQLITE_HAS_CODEC |
| 55365 | /* Backup is not possible if the page size of the destination is changing |
| 55366 | ** and a codec is in use. |
| 55367 | */ |
| 55368 | if( nSrcPgsz!=nDestPgsz && sqlite3PagerGetCodec(pDestPager)!=0 ){ |
| 55369 | rc = SQLITE_READONLY; |
| 55370 | } |
| 55371 | |
| 55372 | /* Backup is not possible if the number of bytes of reserve space differ |
| 55373 | ** between source and destination. If there is a difference, try to |
| 55374 | ** fix the destination to agree with the source. If that is not possible, |
| 55375 | ** then the backup cannot proceed. |
| 55376 | */ |
| 55377 | if( nSrcReserve!=nDestReserve ){ |
| 55378 | u32 newPgsz = nSrcPgsz; |
| 55379 | rc = sqlite3PagerSetPagesize(pDestPager, &newPgsz, nSrcReserve); |
| 55380 | if( rc==SQLITE_OK && newPgsz!=nSrcPgsz ) rc = SQLITE_READONLY; |
| 55381 | } |
| 55382 | #endif |
| 55383 | |
| 55384 | /* This loop runs once for each destination page spanned by the source |
| 55385 | ** page. For each iteration, variable iOff is set to the byte offset |
| 55386 | ** of the destination page. |
| @@ -54996,11 +55742,15 @@ | |
| 55742 | if( !isFatalError(p->rc) && iPage<p->iNext ){ |
| 55743 | /* The backup process p has already copied page iPage. But now it |
| 55744 | ** has been modified by a transaction on the source pager. Copy |
| 55745 | ** the new data into the backup. |
| 55746 | */ |
| 55747 | int rc; |
| 55748 | assert( p->pDestDb ); |
| 55749 | sqlite3_mutex_enter(p->pDestDb->mutex); |
| 55750 | rc = backupOnePage(p, iPage, aData); |
| 55751 | sqlite3_mutex_leave(p->pDestDb->mutex); |
| 55752 | assert( rc!=SQLITE_BUSY && rc!=SQLITE_LOCKED ); |
| 55753 | if( rc!=SQLITE_OK ){ |
| 55754 | p->rc = rc; |
| 55755 | } |
| 55756 | } |
| @@ -74977,10 +75727,14 @@ | |
| 75727 | } |
| 75728 | if( i==0 ) pTable->nRowEst = v; |
| 75729 | if( pIndex==0 ) break; |
| 75730 | pIndex->aiRowEst[i] = v; |
| 75731 | if( *z==' ' ) z++; |
| 75732 | if( memcmp(z, "unordered", 10)==0 ){ |
| 75733 | pIndex->bUnordered = 1; |
| 75734 | break; |
| 75735 | } |
| 75736 | } |
| 75737 | return 0; |
| 75738 | } |
| 75739 | |
| 75740 | /* |
| @@ -75322,11 +76076,13 @@ | |
| 76076 | break; |
| 76077 | |
| 76078 | case SQLITE_NULL: |
| 76079 | /* No key specified. Use the key from the main database */ |
| 76080 | sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); |
| 76081 | if( nKey>0 || sqlite3BtreeGetReserve(db->aDb[0].pBt)>0 ){ |
| 76082 | rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); |
| 76083 | } |
| 76084 | break; |
| 76085 | } |
| 76086 | } |
| 76087 | #endif |
| 76088 | |
| @@ -76753,10 +77509,13 @@ | |
| 77509 | } |
| 77510 | pTable = sqlite3FindTable(db, zName, zDb); |
| 77511 | if( pTable ){ |
| 77512 | if( !noErr ){ |
| 77513 | sqlite3ErrorMsg(pParse, "table %T already exists", pName); |
| 77514 | }else{ |
| 77515 | assert( !db->init.busy ); |
| 77516 | sqlite3CodeVerifySchema(pParse, iDb); |
| 77517 | } |
| 77518 | goto begin_table_error; |
| 77519 | } |
| 77520 | if( sqlite3FindIndex(db, zName, zDb)!=0 ){ |
| 77521 | sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); |
| @@ -77940,10 +78699,11 @@ | |
| 78699 | pTab = sqlite3LocateTable(pParse, isView, |
| 78700 | pName->a[0].zName, pName->a[0].zDatabase); |
| 78701 | if( noErr ) db->suppressErr--; |
| 78702 | |
| 78703 | if( pTab==0 ){ |
| 78704 | if( noErr ) sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); |
| 78705 | goto exit_drop_table; |
| 78706 | } |
| 78707 | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| 78708 | assert( iDb>=0 && iDb<db->nDb ); |
| 78709 | |
| @@ -78458,10 +79218,13 @@ | |
| 79218 | } |
| 79219 | } |
| 79220 | if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ |
| 79221 | if( !ifNotExist ){ |
| 79222 | sqlite3ErrorMsg(pParse, "index %s already exists", zName); |
| 79223 | }else{ |
| 79224 | assert( !db->init.busy ); |
| 79225 | sqlite3CodeVerifySchema(pParse, iDb); |
| 79226 | } |
| 79227 | goto exit_create_index; |
| 79228 | } |
| 79229 | }else{ |
| 79230 | int n; |
| @@ -78851,10 +79614,12 @@ | |
| 79614 | } |
| 79615 | pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); |
| 79616 | if( pIndex==0 ){ |
| 79617 | if( !ifExists ){ |
| 79618 | sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); |
| 79619 | }else{ |
| 79620 | sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); |
| 79621 | } |
| 79622 | pParse->checkSchema = 1; |
| 79623 | goto exit_drop_index; |
| 79624 | } |
| 79625 | if( pIndex->autoIndex ){ |
| @@ -79439,10 +80204,25 @@ | |
| 80204 | sqlite3OpenTempDatabase(pToplevel); |
| 80205 | } |
| 80206 | } |
| 80207 | } |
| 80208 | } |
| 80209 | |
| 80210 | /* |
| 80211 | ** If argument zDb is NULL, then call sqlite3CodeVerifySchema() for each |
| 80212 | ** attached database. Otherwise, invoke it for the database named zDb only. |
| 80213 | */ |
| 80214 | SQLITE_PRIVATE void sqlite3CodeVerifyNamedSchema(Parse *pParse, const char *zDb){ |
| 80215 | sqlite3 *db = pParse->db; |
| 80216 | int i; |
| 80217 | for(i=0; i<db->nDb; i++){ |
| 80218 | Db *pDb = &db->aDb[i]; |
| 80219 | if( pDb->pBt && (!zDb || 0==sqlite3StrICmp(zDb, pDb->zName)) ){ |
| 80220 | sqlite3CodeVerifySchema(pParse, i); |
| 80221 | } |
| 80222 | } |
| 80223 | } |
| 80224 | |
| 80225 | /* |
| 80226 | ** Generate VDBE code that prepares for doing an operation that |
| 80227 | ** might change the database. |
| 80228 | ** |
| @@ -84872,13 +85652,12 @@ | |
| 85652 | ** index and making sure that duplicate entries do not already exist. |
| 85653 | ** Add the new records to the indices as we go. |
| 85654 | */ |
| 85655 | for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ |
| 85656 | int regIdx; |
| 85657 | int regR; |
| 85658 | |
| 85659 | if( aRegIdx[iCur]==0 ) continue; /* Skip unused indices */ |
| 85660 | |
| 85661 | /* Create a key for accessing the index entry */ |
| 85662 | regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1); |
| 85663 | for(i=0; i<pIdx->nColumn; i++){ |
| @@ -84892,15 +85671,10 @@ | |
| 85671 | sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); |
| 85672 | sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]); |
| 85673 | sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT); |
| 85674 | sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn+1); |
| 85675 | |
| 85676 | /* Find out what action to take in case there is an indexing conflict */ |
| 85677 | onError = pIdx->onError; |
| 85678 | if( onError==OE_None ){ |
| 85679 | sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); |
| 85680 | continue; /* pIdx is not a UNIQUE index */ |
| @@ -84970,11 +85744,10 @@ | |
| 85744 | break; |
| 85745 | } |
| 85746 | } |
| 85747 | sqlite3VdbeJumpHere(v, j3); |
| 85748 | sqlite3ReleaseTempReg(pParse, regR); |
| 85749 | } |
| 85750 | |
| 85751 | if( pbMayReplace ){ |
| 85752 | *pbMayReplace = seenReplace; |
| 85753 | } |
| @@ -88180,11 +88953,11 @@ | |
| 88953 | if( zExtra ){ |
| 88954 | *pData->pzErrMsg = sqlite3MAppendf(db, *pData->pzErrMsg, |
| 88955 | "%s - %s", *pData->pzErrMsg, zExtra); |
| 88956 | } |
| 88957 | } |
| 88958 | pData->rc = db->mallocFailed ? SQLITE_NOMEM : SQLITE_CORRUPT_BKPT; |
| 88959 | } |
| 88960 | |
| 88961 | /* |
| 88962 | ** This is the callback routine for the code that initializes the |
| 88963 | ** database. See sqlite3Init() below for additional information. |
| @@ -93841,10 +94614,13 @@ | |
| 94614 | assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); |
| 94615 | if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), |
| 94616 | zName, sqlite3Strlen30(zName)) ){ |
| 94617 | if( !noErr ){ |
| 94618 | sqlite3ErrorMsg(pParse, "trigger %T already exists", pName); |
| 94619 | }else{ |
| 94620 | assert( !db->init.busy ); |
| 94621 | sqlite3CodeVerifySchema(pParse, iDb); |
| 94622 | } |
| 94623 | goto trigger_cleanup; |
| 94624 | } |
| 94625 | |
| 94626 | /* Do not create a trigger on a system table */ |
| @@ -94169,10 +94945,12 @@ | |
| 94945 | if( pTrigger ) break; |
| 94946 | } |
| 94947 | if( !pTrigger ){ |
| 94948 | if( !noErr ){ |
| 94949 | sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0); |
| 94950 | }else{ |
| 94951 | sqlite3CodeVerifyNamedSchema(pParse, zDb); |
| 94952 | } |
| 94953 | pParse->checkSchema = 1; |
| 94954 | goto drop_trigger_cleanup; |
| 94955 | } |
| 94956 | sqlite3DropTriggerPtr(pParse, pTrigger); |
| @@ -98075,11 +98853,14 @@ | |
| 98853 | ** Note that the virtual term must be tagged with TERM_VNULL. This |
| 98854 | ** TERM_VNULL tag will suppress the not-null check at the beginning |
| 98855 | ** of the loop. Without the TERM_VNULL flag, the not-null check at |
| 98856 | ** the start of the loop will prevent any results from being returned. |
| 98857 | */ |
| 98858 | if( pExpr->op==TK_NOTNULL |
| 98859 | && pExpr->pLeft->op==TK_COLUMN |
| 98860 | && pExpr->pLeft->iColumn>=0 |
| 98861 | ){ |
| 98862 | Expr *pNewExpr; |
| 98863 | Expr *pLeft = pExpr->pLeft; |
| 98864 | int idxNew; |
| 98865 | WhereTerm *pNewTerm; |
| 98866 | |
| @@ -99265,11 +100046,11 @@ | |
| 100046 | ** This routine can fail if it is unable to load a collating sequence |
| 100047 | ** required for string comparison, or if unable to allocate memory |
| 100048 | ** for a UTF conversion required for comparison. The error is stored |
| 100049 | ** in the pParse structure. |
| 100050 | */ |
| 100051 | static int whereEqualScanEst( |
| 100052 | Parse *pParse, /* Parsing & code generating context */ |
| 100053 | Index *p, /* The index whose left-most column is pTerm */ |
| 100054 | Expr *pExpr, /* Expression for VALUE in the x=VALUE constraint */ |
| 100055 | double *pnRow /* Write the revised row estimate here */ |
| 100056 | ){ |
| @@ -99322,11 +100103,11 @@ | |
| 100103 | ** This routine can fail if it is unable to load a collating sequence |
| 100104 | ** required for string comparison, or if unable to allocate memory |
| 100105 | ** for a UTF conversion required for comparison. The error is stored |
| 100106 | ** in the pParse structure. |
| 100107 | */ |
| 100108 | static int whereInScanEst( |
| 100109 | Parse *pParse, /* Parsing & code generating context */ |
| 100110 | Index *p, /* The index whose left-most column is pTerm */ |
| 100111 | ExprList *pList, /* The value list on the RHS of "x IN (v1,v2,v3,...)" */ |
| 100112 | double *pnRow /* Write the revised row estimate here */ |
| 100113 | ){ |
| @@ -99593,11 +100374,11 @@ | |
| 100374 | #endif |
| 100375 | used |= pTerm->prereqRight; |
| 100376 | } |
| 100377 | |
| 100378 | /* Determine the value of estBound. */ |
| 100379 | if( nEq<pProbe->nColumn && pProbe->bUnordered==0 ){ |
| 100380 | int j = pProbe->aiColumn[nEq]; |
| 100381 | if( findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE|WO_GT|WO_GE, pIdx) ){ |
| 100382 | WhereTerm *pTop = findTerm(pWC, iCur, j, notReady, WO_LT|WO_LE, pIdx); |
| 100383 | WhereTerm *pBtm = findTerm(pWC, iCur, j, notReady, WO_GT|WO_GE, pIdx); |
| 100384 | whereRangeScanEst(pParse, pProbe, nEq, pBtm, pTop, &estBound); |
| @@ -99625,10 +100406,11 @@ | |
| 100406 | ** naturally scan rows in the required order, set the appropriate flags |
| 100407 | ** in wsFlags. Otherwise, if there is an ORDER BY clause but the index |
| 100408 | ** will scan rows in a different order, set the bSort variable. */ |
| 100409 | if( pOrderBy ){ |
| 100410 | if( (wsFlags & WHERE_COLUMN_IN)==0 |
| 100411 | && pProbe->bUnordered==0 |
| 100412 | && isSortingIndex(pParse, pWC->pMaskSet, pProbe, iCur, pOrderBy, |
| 100413 | nEq, wsFlags, &rev) |
| 100414 | ){ |
| 100415 | wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE|WHERE_ORDERBY; |
| 100416 | wsFlags |= (rev ? WHERE_REVERSE : 0); |
| 100417 |
+1
-1
| --- src/sqlite3.h | ||
| +++ src/sqlite3.h | ||
| @@ -107,11 +107,11 @@ | ||
| 107 | 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | 109 | */ |
| 110 | 110 | #define SQLITE_VERSION "3.7.6" |
| 111 | 111 | #define SQLITE_VERSION_NUMBER 3007006 |
| 112 | -#define SQLITE_SOURCE_ID "2011-04-07 15:24:08 bf78acb9dfacde0f08a5b3ceac13480f12a06168" | |
| 112 | +#define SQLITE_SOURCE_ID "2011-04-12 01:58:40 f9d43fa363d54beab6f45db005abac0a7c0c47a7" | |
| 113 | 113 | |
| 114 | 114 | /* |
| 115 | 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | 117 | ** |
| 118 | 118 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -107,11 +107,11 @@ | |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.7.6" |
| 111 | #define SQLITE_VERSION_NUMBER 3007006 |
| 112 | #define SQLITE_SOURCE_ID "2011-04-07 15:24:08 bf78acb9dfacde0f08a5b3ceac13480f12a06168" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| 118 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -107,11 +107,11 @@ | |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.7.6" |
| 111 | #define SQLITE_VERSION_NUMBER 3007006 |
| 112 | #define SQLITE_SOURCE_ID "2011-04-12 01:58:40 f9d43fa363d54beab6f45db005abac0a7c0c47a7" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| 118 |