Index: SQLite.Interop/SQLite.Interop.vcproj ================================================================== --- SQLite.Interop/SQLite.Interop.vcproj +++ SQLite.Interop/SQLite.Interop.vcproj @@ -34,11 +34,11 @@ WholeProgramOptimization="1" > @@ -114,11 +116,11 @@ WholeProgramOptimization="0" > @@ -134,11 +136,11 @@ @@ -199,11 +202,11 @@ WholeProgramOptimization="1" > @@ -281,11 +286,11 @@ WholeProgramOptimization="1" > @@ -427,22 +434,82 @@ > + + - - + + + + + + + + + + + + + + + + + + + + + + + + @@ -463,10 +530,42 @@ > + + + + + + + + + + + + @@ -523,21 +622,28 @@ Name="Header Files" Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > - - + + + + + + ADDED SQLite.Interop/crypt.c Index: SQLite.Interop/crypt.c ================================================================== --- /dev/null +++ SQLite.Interop/crypt.c @@ -0,0 +1,372 @@ +#include "src/pager.c" + +#ifndef SQLITE_OMIT_DISKIO +#ifdef SQLITE_HAS_CODEC + +#include +#include + +HCRYPTPROV g_hProvider = 0; // Global instance of the cryptographic provider + +#define SQLITECRYPTERROR_PROVIDER "Cryptographic provider not available" + +typedef struct _CRYPTBLOCK +{ + HCRYPTKEY hReadKey; // Key used to read from the database and write to the journal + HCRYPTKEY hWriteKey; // Key used to write to the database + DWORD dwPageSize; // Size of pages + LPVOID pvCrypt; // A buffer for encrypting/decrypting (if necessary) + DWORD dwCryptSize; // Equal to or greater than dwPageSize. If larger, pvCrypt is valid and this is its size +} CRYPTBLOCK, *LPCRYPTBLOCK; + +// Needed for re-keying +static void * sqlite3pager_get_codecarg(Pager *pPager) +{ + return (pPager->xCodec) ? pPager->pCodecArg: NULL; +} + +// Create a cryptographic context. Use the enhanced provider because it is available on +// most platforms +static BOOL InitializeProvider() +{ + if (g_hProvider) return TRUE; + + if (!CryptAcquireContext(&g_hProvider, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0)) + { + if(!CryptAcquireContext(&g_hProvider, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) + { + return FALSE; + } + } + return TRUE; +} + +// Create or update a cryptographic context for a pager. +// This function will automatically determine if the encryption algorithm requires +// extra padding, and if it does, will create a temp buffer big enough to provide +// space to hold it. +static LPCRYPTBLOCK CreateCryptBlock(HCRYPTKEY hKey, Pager *pager, LPCRYPTBLOCK pExisting) +{ + LPCRYPTBLOCK pBlock; + + if (!pExisting) // Creating a new cryptblock + { + pBlock = malloc(sizeof(CRYPTBLOCK)); + ZeroMemory(pBlock, sizeof(CRYPTBLOCK)); + pBlock->hReadKey = hKey; + pBlock->hWriteKey = hKey; + } + else // Updating an existing cryptblock + { + pBlock = pExisting; + } + + pBlock->dwPageSize = (DWORD)pager->pageSize; + pBlock->dwCryptSize = pBlock->dwPageSize; + + // Existing cryptblocks may have a buffer, if so, delete it + if (pBlock->pvCrypt) + { + free(pBlock->pvCrypt); + pBlock->pvCrypt = NULL; + } + + // Figure out if this cryptographic key requires extra buffer space, and if so, allocate + // enough room for it + if (CryptEncrypt(hKey, 0, TRUE, 0, NULL, &pBlock->dwCryptSize, pBlock->dwCryptSize * 2)) + { + if (pBlock->dwCryptSize > pBlock->dwPageSize) + { + pBlock->pvCrypt = malloc(pBlock->dwCryptSize); + } + } + return pBlock; +} + +// Destroy a cryptographic context and any buffers and keys allocated therein +static void DestroyCryptBlock(LPCRYPTBLOCK pBlock) +{ + // Destroy the read key if there is one + if (pBlock->hReadKey) + { + CryptDestroyKey(pBlock->hReadKey); + } + + // If there's a writekey and its not equal to the readkey, destroy it + if (pBlock->hWriteKey && pBlock->hWriteKey != pBlock->hReadKey) + { + CryptDestroyKey(pBlock->hWriteKey); + } + + // If there's extra buffer space allocated, free it as well + if (pBlock->pvCrypt) + { + free(pBlock->pvCrypt); + } + + // All done with this cryptblock + free(pBlock); +} + +// Encrypt/Decrypt functionality, called by pager.c +void sqlite3Codec(void *pArg, void *data, Pgno nPageNum, int nMode) +{ + LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)pArg; + DWORD dwPageSize; + LPVOID pvTemp; + PgHdr *pageHeader; + + if (!pBlock) return; + + // Make sure the page size for the pager is still the same as the page size + // for the cryptblock. If the user changed it, we need to adjust! + pageHeader = DATA_TO_PGHDR(data); + if (pageHeader->pPager->pageSize != pBlock->dwPageSize) + { + // Update the cryptblock to reflect the new page size + CreateCryptBlock(0, pageHeader->pPager, pBlock); + } + + /* Block ciphers often need to write extra padding beyond the + data block. We don't have that luxury for a given page of data so + we must copy the page data to a buffer that IS large enough to hold + the padding. We then encrypt the block and write the buffer back to + the page without the unnecessary padding. + We only use the special block of memory if its absolutely necessary. */ + if (pBlock->pvCrypt) + { + CopyMemory(pBlock->pvCrypt, data, pBlock->dwPageSize); + pvTemp = data; + data = pBlock->pvCrypt; + } + + switch(nMode) + { + case 0: // Undo a "case 7" journal file encryption + case 2: // Reload a page + case 3: // Load a page + if (!pBlock->hReadKey) break; + dwPageSize = pBlock->dwCryptSize; + CryptDecrypt(pBlock->hReadKey, 0, TRUE, 0, (LPBYTE)data, &dwPageSize); + break; + case 6: // Encrypt a page for the main database file + if (!pBlock->hWriteKey) break; + dwPageSize = pBlock->dwPageSize; + CryptEncrypt(pBlock->hWriteKey, 0, TRUE, 0, (LPBYTE)data, &dwPageSize, pBlock->dwCryptSize); + break; + case 7: // Encrypt a page for the journal file + /* Under normal circumstances, the readkey is the same as the writekey. However, + when the database is being rekeyed, the readkey is not the same as the writekey. + The rollback journal must be written using the original key for the + database file because it is, by nature, a rollback journal. + Therefore, for case 7, when the rollback is being written, always encrypt using + the database's readkey, which is guaranteed to be the same key that was used to + read the original data. + */ + if (!pBlock->hReadKey) break; + dwPageSize = pBlock->dwPageSize; + CryptEncrypt(pBlock->hReadKey, 0, TRUE, 0, (LPBYTE)data, &dwPageSize, pBlock->dwCryptSize); + break; + } + + // If the encryption algorithm required extra padding and we were forced to encrypt or + // decrypt a copy of the page data to a temp buffer, then write the contents of the temp + // buffer back to the page data minus any padding applied. + if (pBlock->pvCrypt) + { + CopyMemory(pvTemp, data, pBlock->dwPageSize); + } +} + +// Derive an encryption key from a user-supplied buffer +static HCRYPTKEY DeriveKey(const void *pKey, int nKeyLen) +{ + HCRYPTHASH hHash = 0; + HCRYPTKEY hKey; + + if (!pKey || !nKeyLen) return 0; + + if (!InitializeProvider()) + { + return MAXDWORD; + } + + if (CryptCreateHash(g_hProvider, CALG_SHA1, 0, 0, &hHash)) + { + if (CryptHashData(hHash, (LPBYTE)pKey, nKeyLen, 0)) + { + CryptDeriveKey(g_hProvider, CALG_RC4, hHash, 0, &hKey); + } + CryptDestroyHash(hHash); + } + return hKey; +} + +// Called by sqlite and sqlite3_key_interop to attach a key to a database. +int sqlite3CodecAttach(sqlite3 *db, int nDb, const void *pKey, int nKeyLen) +{ + int rc = SQLITE_ERROR; + HCRYPTKEY hKey = 0; + + // No key specified, could mean either use the main db's encryption or no encryption + if (!pKey || !nKeyLen) + { + if (!nDb) + { + return SQLITE_OK; // Main database, no key specified so not encrypted + } + else // Attached database, use the main database's key + { + // Get the encryption block for the main database and attempt to duplicate the key + // for use by the attached database + LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)sqlite3pager_get_codecarg(sqlite3BtreePager(db->aDb[0].pBt)); + + if (!pBlock) return SQLITE_OK; // Main database is not encrypted so neither will be any attached database + if (!pBlock->hReadKey) return SQLITE_OK; // Not encrypted + + if (!CryptDuplicateKey(pBlock->hReadKey, NULL, 0, &hKey)) + return rc; // Unable to duplicate the key + } + } + else // User-supplied passphrase, so create a cryptographic key out of it + { + hKey = DeriveKey(pKey, nKeyLen); + if (hKey == MAXDWORD) + { + sqlite3Error(db, rc, SQLITECRYPTERROR_PROVIDER); + return rc; + } + } + + // Create a new encryption block and assign the codec to the new attached database + if (hKey) + { + LPCRYPTBLOCK pBlock = CreateCryptBlock(hKey, sqlite3BtreePager(db->aDb[nDb].pBt), NULL); + sqlite3pager_set_codec(sqlite3BtreePager(db->aDb[nDb].pBt), sqlite3Codec, pBlock); + rc = SQLITE_OK; + } + return rc; +} + +// Once a password has been supplied and a key created, we don't keep the +// original password for security purposes. Therefore return NULL. +void sqlite3CodecGetKey(sqlite3 *db, int nDb, void **ppKey, int *pnKeyLen) +{ + *ppKey = NULL; + *pnKeyLen = 0; +} + +// We do not attach this key to the temp store, only the main database. +__declspec(dllexport) int __stdcall sqlite3_key_interop(sqlite3 *db, const void *pKey, int nKeySize) +{ + return sqlite3CodecAttach(db, 0, pKey, nKeySize); +} + +// Changes the encryption key for an existing database. +__declspec(dllexport) int __stdcall sqlite3_rekey_interop(sqlite3 *db, const void *pKey, int nKeySize) +{ + Btree *pbt = db->aDb[0].pBt; + Pager *p = sqlite3BtreePager(pbt); + LPCRYPTBLOCK pBlock = (LPCRYPTBLOCK)sqlite3pager_get_codecarg(p); + HCRYPTKEY hKey = DeriveKey(pKey, nKeySize); + int rc = SQLITE_ERROR; + + if (hKey == MAXDWORD) + { + sqlite3Error(db, rc, SQLITECRYPTERROR_PROVIDER); + return rc; + } + + if (!pBlock && !hKey) return SQLITE_OK; // Wasn't encrypted to begin with + + // To rekey a database, we change the writekey for the pager. The readkey remains + // the same + if (!pBlock) // Encrypt an unencrypted database + { + pBlock = CreateCryptBlock(hKey, p, NULL); + pBlock->hReadKey = 0; // Original database is not encrypted + sqlite3pager_set_codec(sqlite3BtreePager(pbt), sqlite3Codec, pBlock); + } + else // Change the writekey for an already-encrypted database + { + pBlock->hWriteKey = hKey; + } + + // Start a transaction + rc = sqlite3BtreeBeginTrans(pbt, 1); + + if (!rc) + { + // Rewrite all the pages in the database using the new encryption key + int nPage = sqlite3pager_pagecount(p); + void *pPage; + int n; + + for(n = 1; rc == SQLITE_OK && n <= nPage; n ++) + { + rc = sqlite3pager_get(p, n, &pPage); + if(!rc) + { + rc = sqlite3pager_write(pPage); + sqlite3pager_unref(pPage); + } + } + } + + // If we succeeded, try and commit the transaction + if (!rc) + { + rc = sqlite3BtreeCommit(pbt); + } + + // If we failed, rollback + if (rc) + { + sqlite3BtreeRollback(pbt); + } + + // If we succeeded, destroy any previous read key this database used + // and make the readkey equal to the writekey + if (!rc) + { + if (pBlock->hReadKey) + { + CryptDestroyKey(pBlock->hReadKey); + } + pBlock->hReadKey = pBlock->hWriteKey; + } + // We failed. Destroy the new writekey (if there was one) and revert it back to + // the original readkey + else + { + if (pBlock->hWriteKey) + { + CryptDestroyKey(pBlock->hWriteKey); + } + pBlock->hWriteKey = pBlock->hReadKey; + } + + // If the readkey and writekey are both empty, there's no need for a codec on this + // pager anymore. Destroy the crypt block and remove the codec from the pager. + if (!pBlock->hReadKey && !pBlock->hWriteKey) + { + sqlite3pager_set_codec(p, NULL, NULL); + DestroyCryptBlock(pBlock); + } + + return rc; +} + +int sqlite3_key(sqlite3 *db, const void *pKey, int nKey) +{ + return sqlite3_key_interop(db, pKey, nKey); +} + +int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey) +{ + return sqlite3_rekey_interop(db, pKey, nKey); +} + +#endif // SQLITE_HAS_CODEC + +#endif // SQLITE_OMIT_DISKIO ADDED SQLite.Interop/fixsource.vbs Index: SQLite.Interop/fixsource.vbs ================================================================== --- /dev/null +++ SQLite.Interop/fixsource.vbs @@ -0,0 +1,44 @@ +' VBScript source code +Main + +Sub Main() + Dim WshShell + Set WshShell = WScript.CreateObject("WScript.Shell") + + Dim fso + Set fso = WScript.CreateObject("Scripting.FileSystemObject") + + Dim srcFile + Dim srcFileContents + dim newFileContents + + Set srcFile = fso.OpenTextFile("src\select.c", 1) + + srcFileContents = srcFile.ReadAll() + srcFile.Close() + + newFileContents = Replace(srcFileContents, "static void generateColumnNames(", "static void _generateColumnNames(") + + If (newFileContents <> srcFileContents) Then + WScript.StdOut.WriteLine "Updating select.c" + Set srcFile = fso.CreateTextFile("src\select.c", true) + srcFile.Write(newFileContents) + srcFile.Close() + End If + + Set srcFile = fso.OpenTextFile("src\tokenize.c", 1) + + srcFileContents = srcFile.ReadAll() + srcFile.Close() + + newFileContents = Replace(srcFileContents, " case ':': {", " case '@': case ':': {") + + If (newFileContents <> srcFileContents) Then + WScript.StdOut.WriteLine "Updating tokenize.c" + Set srcFile = fso.CreateTextFile("src\tokenize.c", true) + srcFile.Write(newFileContents) + srcFile.Close() + End If + +End Sub + ADDED SQLite.Interop/interop.c Index: SQLite.Interop/interop.c ================================================================== --- /dev/null +++ SQLite.Interop/interop.c @@ -0,0 +1,764 @@ +/* + This interop file must be included at or near the top of the select.c file of the SQLite3 source distribution. + + generateColumnNames() in the select.c must be renamed to _generateColumnNames + +*/ + +#include "src/sqliteint.h" +#include "src\os.h" + +// Forward declare this function, we're implementing it later +static void generateColumnNames( + Parse *pParse, /* Parser context */ + SrcList *pTabList, /* List of tables */ + ExprList *pEList /* Expressions defining the result set */ +); + +#include "src\select.c" + +/* +** Generate code that will tell the VDBE the names of columns +** in the result set. This information is used to provide the +** azCol[] values in the callback. +*/ +static void generateColumnNames( + Parse *pParse, /* Parser context */ + SrcList *pTabList, /* List of tables */ + ExprList *pEList /* Expressions defining the result set */ +){ + Vdbe *v = pParse->pVdbe; + int i, j; + sqlite3 *db = pParse->db; + int fullNames, shortNames; + int realNames; /*** ADDED - SQLite.Interop ***/ + + realNames = (db->flags & 0x01000000)!=0; /*** ADDED - SQLite.Interop ***/ + if (!realNames) // Default to normal Sqlite3 /*** ADDED - SQLite.Interop ***/ + { /*** ADDED - SQLite.Interop ***/ + _generateColumnNames(pParse, pTabList, pEList); /*** ADDED - SQLite.Interop ***/ + return; /*** ADDED - SQLite.Interop ***/ + } /*** ADDED - SQLite.Interop ***/ + +#ifndef SQLITE_OMIT_EXPLAIN + /* If this is an EXPLAIN, skip this step */ + if( pParse->explain ){ + return; + } +#endif + + assert( v!=0 ); + if( pParse->colNamesSet || v==0 || sqlite3ThreadData()->mallocFailed ) return; + pParse->colNamesSet = 1; + fullNames = (db->flags & SQLITE_FullColNames)!=0; + shortNames = (db->flags & SQLITE_ShortColNames)!=0; + if (realNames) fullNames = 1; /*** ADDED - SQLite.Interop ***/ + + sqlite3VdbeSetNumCols(v, pEList->nExpr); + for(i=0; inExpr; i++){ + Expr *p; + p = pEList->a[i].pExpr; + if( p==0 ) continue; + if( pEList->a[i].zName && (realNames == 0 || p->op != TK_COLUMN)){ /*** CHANGED - SQLite.Interop ***/ + char *zName = pEList->a[i].zName; + sqlite3VdbeSetColName(v, i, zName, strlen(zName)); + continue; + } + if( p->op==TK_COLUMN && pTabList ){ + Table *pTab; + char *zCol; + int iCol = p->iColumn; + for(j=0; jnSrc && pTabList->a[j].iCursor!=p->iTable; j++){} + assert( jnSrc ); + pTab = pTabList->a[j].pTab; + if( iCol<0 ) iCol = pTab->iPKey; + assert( iCol==-1 || (iCol>=0 && iColnCol) ); + if( iCol<0 ){ + zCol = "rowid"; + }else{ + zCol = pTab->aCol[iCol].zName; + } + if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){ + sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n); + }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){ + char *zName = 0; + char *zTab; + char *zDb = 0; /*** ADDED - SQLite.Interop ***/ + int iDb; + + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + + zTab = pTabList->a[j].zAlias; + if( fullNames || zTab==0 ){ + if (iDb > 1) zDb = db->aDb[iDb].zName; /*** ADDED - SQLite.Interop ***/ + zTab = pTab->zName; + } + if (!zDb || !realNames) sqlite3SetString(&zName, zTab, "\x01", zCol, 0); /*** CHANGED - SQLite.Interop ***/ + else sqlite3SetString(&zName, zDb, "\x01", zTab, "\x01", zCol, 0); /*** ADDED - SQLite.Interop ***/ + sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC); + }else{ + sqlite3VdbeSetColName(v, i, zCol, strlen(zCol)); + } + }else if( p->span.z && p->span.z[0] ){ + sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n); + /* sqlite3VdbeCompressSpace(v, addr); */ + }else{ + char zName[30]; + assert( p->op!=TK_COLUMN || pTabList==0 ); + sprintf(zName, "column%d", i+1); + sqlite3VdbeSetColName(v, i, zName, 0); + } + } + generateColumnTypes(pParse, pTabList, pEList); +} + +#ifdef OS_WIN + +#include + +typedef void (__stdcall *SQLITEUSERFUNC)(void *, int, void **); +typedef int (__stdcall *SQLITECOLLATION)(int, const void *, int, const void*); + +typedef int (__stdcall *ENCRYPTFILEW)(const wchar_t *); +typedef int (__stdcall *ENCRYPTEDSTATUSW)(const wchar_t *, unsigned long *); +typedef int (__stdcall *DECRYPTFILEW)(const wchar_t *, unsigned long); + +typedef HANDLE (__stdcall *CREATEFILEW)( + LPCWSTR, + DWORD, + DWORD, + LPSECURITY_ATTRIBUTES, + DWORD, + DWORD, + HANDLE); + +// Callback wrappers +int sqlite3_interop_collationfunc(void *pv, int len1, const void *pv1, int len2, const void *pv2) +{ + SQLITECOLLATION *p = (SQLITECOLLATION *)pv; + return p[0](len1, pv1, len2, pv2); +} + +void sqlite3_interop_func(sqlite3_context *pctx, int n, sqlite3_value **pv) +{ + SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); + pf[0](pctx, n, (void **)pv); +} + +void sqlite3_interop_step(sqlite3_context *pctx, int n, sqlite3_value **pv) +{ + SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); + pf[1](pctx, n, (void **)pv); +} + +void sqlite3_interop_final(sqlite3_context *pctx) +{ + SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); + pf[2](pctx, 0, 0); +} + +__declspec(dllexport) void __stdcall sqlite3_sleep_interop(int milliseconds) +{ + Sleep(milliseconds); +} + +__declspec(dllexport) int sqlite3_encryptfile(const wchar_t *pwszFilename) +{ + HMODULE hMod = LoadLibrary(_T("ADVAPI32")); + ENCRYPTFILEW pfunc; + int n; + + if (hMod == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + pfunc = (ENCRYPTFILEW)GetProcAddress(hMod, _T("EncryptFileW")); + if (pfunc == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + n = pfunc(pwszFilename); + + FreeLibrary(hMod); + + return n; +} + +__declspec(dllexport) int sqlite3_decryptfile(const wchar_t *pwszFilename) +{ + HMODULE hMod = LoadLibrary(_T("ADVAPI32")); + DECRYPTFILEW pfunc; + int n; + + if (hMod == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + pfunc = (DECRYPTFILEW)GetProcAddress(hMod, _T("DecryptFileW")); + if (pfunc == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + n = pfunc(pwszFilename, 0); + + FreeLibrary(hMod); + + return n; +} + +__declspec(dllexport) unsigned long sqlite3_encryptedstatus(const wchar_t *pwszFilename, unsigned long *pdwStatus) +{ + HMODULE hMod = LoadLibrary(_T("ADVAPI32")); + ENCRYPTEDSTATUSW pfunc; + int n; + + if (hMod == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + pfunc = (ENCRYPTEDSTATUSW)GetProcAddress(hMod, _T("FileEncryptionStatusW")); + if (pfunc == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + n = pfunc(pwszFilename, pdwStatus); + + FreeLibrary(hMod); + + return n; +} + +int SetCompression(const wchar_t *pwszFilename, unsigned short ufLevel) +{ +#ifdef FSCTL_SET_COMPRESSION + HMODULE hMod = GetModuleHandle(_T("KERNEL32")); + CREATEFILEW pfunc; + HANDLE hFile; + unsigned long dw = 0; + int n; + + if (hMod == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + pfunc = (CREATEFILEW)GetProcAddress(hMod, _T("CreateFileW")); + if (pfunc == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + hFile = pfunc(pwszFilename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == NULL) + return 0; + + n = DeviceIoControl(hFile, FSCTL_SET_COMPRESSION, &ufLevel, sizeof(ufLevel), NULL, 0, &dw, NULL); + + CloseHandle(hFile); + + return n; +#else + SetLastError(ERROR_NOT_SUPPORTED); + return 0; +#endif +} + +__declspec(dllexport) int __stdcall sqlite3_compressfile(const wchar_t *pwszFilename) +{ + return SetCompression(pwszFilename, COMPRESSION_FORMAT_DEFAULT); +} + +__declspec(dllexport) int __stdcall sqlite3_decompressfile(const wchar_t *pwszFilename) +{ + return SetCompression(pwszFilename, COMPRESSION_FORMAT_NONE); +} + +__declspec(dllexport) void __stdcall sqlite3_function_free_callbackcookie(void *pCookie) +{ + if (pCookie) + free(pCookie); +} + +// sqlite3 wrappers +__declspec(dllexport) const char * __stdcall sqlite3_libversion_interop(int *plen) +{ + const char *val = sqlite3_libversion(); + *plen = (val != 0) ? strlen(val) : 0; + + return val; +} + +__declspec(dllexport) int __stdcall sqlite3_libversion_number_interop(void) +{ + return sqlite3_libversion_number(); +} + +__declspec(dllexport) int __stdcall sqlite3_close_interop(sqlite3 *db) +{ + return sqlite3_close(db); +} + +__declspec(dllexport) int __stdcall sqlite3_exec_interop(sqlite3 *db, const char *sql, sqlite3_callback cb, void *pv, char **errmsg, int *plen) +{ + int n = sqlite3_exec(db, sql, cb, pv, errmsg); + *plen = (*errmsg != 0) ? strlen(*errmsg) : 0; + return n; +} + +__declspec(dllexport) sqlite_int64 __stdcall sqlite3_last_insert_rowid_interop(sqlite3 *db) +{ + return sqlite3_last_insert_rowid(db); +} + +__declspec(dllexport) int __stdcall sqlite3_changes_interop(sqlite3 *db) +{ + return sqlite3_changes(db); +} + +__declspec(dllexport) int __stdcall sqlite3_total_changes_interop(sqlite3 *db) +{ + return sqlite3_total_changes(db); +} + +__declspec(dllexport) void __stdcall sqlite3_interrupt_interop(sqlite3 *db) +{ + sqlite3_interrupt(db); +} + +__declspec(dllexport) int __stdcall sqlite3_complete_interop(const char *sql) +{ + return sqlite3_complete(sql); +} + +__declspec(dllexport) int __stdcall sqlite3_complete16_interop(const void *sql) +{ + return sqlite3_complete16(sql); +} + +__declspec(dllexport) int __stdcall sqlite3_busy_handler_interop(sqlite3 *db, int(*cb)(void *, int), void *pv) +{ + return sqlite3_busy_handler(db, cb, pv); +} + +__declspec(dllexport) int __stdcall sqlite3_busy_timeout_interop(sqlite3 *db, int ms) +{ + return sqlite3_busy_timeout(db, ms); +} + +__declspec(dllexport) int __stdcall sqlite3_get_table_interop(sqlite3 *db, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg, int *plen) +{ + int n = sqlite3_get_table(db, sql, resultp, nrow, ncolumn, errmsg); + *plen = (*errmsg != 0) ? strlen((char *)*errmsg) : 0; + return n; +} + +__declspec(dllexport) void __stdcall sqlite3_free_table_interop(char **result) +{ + sqlite3_free_table(result); +} + +__declspec(dllexport) void __stdcall sqlite3_free_interop(char *z) +{ + sqlite3_free(z); +} + +__declspec(dllexport) int __stdcall sqlite3_open_interop(const char*filename, sqlite3 **ppdb) +{ + return sqlite3_open(filename, ppdb); +} + +__declspec(dllexport) int __stdcall sqlite3_open16_interop(const void *filename, sqlite3 **ppdb) +{ + return sqlite3_open16(filename, ppdb); +} + +__declspec(dllexport) int __stdcall sqlite3_errcode_interop(sqlite3 *db) +{ + return sqlite3_errcode(db); +} + +__declspec(dllexport) const char * __stdcall sqlite3_errmsg_interop(sqlite3 *db, int *plen) +{ + const char *pval = sqlite3_errmsg(db); + *plen = (pval != 0) ? strlen(pval) : 0; + return pval; +} + +__declspec(dllexport) const void * __stdcall sqlite3_errmsg16_interop(sqlite3 *db, int *plen) +{ + const void *pval = sqlite3_errmsg16(db); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t): 0; + return pval; +} + +__declspec(dllexport) int __stdcall sqlite3_prepare_interop(sqlite3 *db, const char *sql, int nbytes, sqlite3_stmt **ppstmt, const char **pztail, int *plen) +{ + int n = sqlite3_prepare(db, sql, nbytes, ppstmt, pztail); + *plen = (*pztail != 0) ? strlen(*pztail) : 0; + return n; +} + +__declspec(dllexport) int __stdcall sqlite3_prepare16_interop(sqlite3 *db, const void *sql, int nbytes, sqlite3_stmt **ppstmt, const void **pztail, int *plen) +{ + int n = sqlite3_prepare16(db, sql, nbytes, ppstmt, pztail); + *plen = (*pztail != 0) ? wcslen((wchar_t *)*pztail) * sizeof(wchar_t) : 0; + return n; +} + +__declspec(dllexport) int __stdcall sqlite3_bind_blob_interop(sqlite3_stmt *stmt, int iCol, const void *pv, int n, void(*cb)(void*)) +{ + return sqlite3_bind_blob(stmt, iCol, pv, n, cb); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_double_interop(sqlite3_stmt *stmt, int iCol, double *val) +{ + return sqlite3_bind_double(stmt,iCol,*val); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_int_interop(sqlite3_stmt *stmt, int iCol, int val) +{ + return sqlite3_bind_int(stmt, iCol, val); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_int64_interop(sqlite3_stmt *stmt, int iCol, sqlite_int64 *val) +{ + return sqlite3_bind_int64(stmt,iCol,*val); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_null_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_bind_null(stmt, iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_text_interop(sqlite3_stmt *stmt, int iCol, const char *val, int n, void(*cb)(void *)) +{ + return sqlite3_bind_text(stmt, iCol, val, n, cb); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_text16_interop(sqlite3_stmt *stmt, int iCol, const void *val, int n, void(*cb)(void *)) +{ + return sqlite3_bind_text16(stmt, iCol, val, n, cb); +} + +__declspec(dllexport) int __stdcall sqlite3_bind_parameter_count_interop(sqlite3_stmt *stmt) +{ + return sqlite3_bind_parameter_count(stmt); +} + +__declspec(dllexport) const char * __stdcall sqlite3_bind_parameter_name_interop(sqlite3_stmt *stmt, int iCol, int *plen) +{ + const char *pval = sqlite3_bind_parameter_name(stmt, iCol); + *plen = (pval != 0) ? strlen(pval) : 0; + return pval; +} + +__declspec(dllexport) int __stdcall sqlite3_bind_parameter_index_interop(sqlite3_stmt *stmt, const char *zName) +{ + return sqlite3_bind_parameter_index(stmt, zName); +} + +__declspec(dllexport) int __stdcall sqlite3_column_count_interop(sqlite3_stmt *stmt) +{ + return sqlite3_column_count(stmt); +} + +__declspec(dllexport) const char * __stdcall sqlite3_column_name_interop(sqlite3_stmt *stmt, int iCol, int *plen) +{ + const char *pval = sqlite3_column_name(stmt, iCol); + *plen = (pval != 0) ? strlen(pval) : 0; + return pval; +} + +__declspec(dllexport) const void * __stdcall sqlite3_column_name16_interop(sqlite3_stmt *stmt, int iCol, int *plen) +{ + const void *pval = sqlite3_column_name16(stmt, iCol); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; + return pval; +} + +__declspec(dllexport) const char * __stdcall sqlite3_column_decltype_interop(sqlite3_stmt *stmt, int iCol, int *plen) +{ + const char *pval = sqlite3_column_decltype(stmt, iCol); + *plen = (pval != 0) ? strlen(pval) : 0; + return pval; +} + +__declspec(dllexport) const void * __stdcall sqlite3_column_decltype16_interop(sqlite3_stmt *stmt, int iCol, int *plen) +{ + const void *pval = sqlite3_column_decltype16(stmt, iCol); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; + return pval; +} + +__declspec(dllexport) int __stdcall sqlite3_step_interop(sqlite3_stmt *stmt) +{ + return sqlite3_step(stmt); +} + +__declspec(dllexport) int __stdcall sqlite3_data_count_interop(sqlite3_stmt *stmt) +{ + return sqlite3_data_count(stmt); +} + +__declspec(dllexport) const void * __stdcall sqlite3_column_blob_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_blob(stmt, iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_column_bytes_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_bytes(stmt, iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_column_bytes16_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_bytes16(stmt, iCol); +} + +__declspec(dllexport) void __stdcall sqlite3_column_double_interop(sqlite3_stmt *stmt, int iCol, double *val) +{ + *val = sqlite3_column_double(stmt,iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_column_int_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_int(stmt, iCol); +} + +__declspec(dllexport) void __stdcall sqlite3_column_int64_interop(sqlite3_stmt *stmt, int iCol, sqlite_int64 *val) +{ + *val = sqlite3_column_int64(stmt,iCol); +} + +__declspec(dllexport) const unsigned char * __stdcall sqlite3_column_text_interop(sqlite3_stmt *stmt, int iCol, int *plen) +{ + const unsigned char *pval = sqlite3_column_text(stmt, iCol); + *plen = (pval != 0) ? strlen((char *)pval) : 0; + return pval; +} + +__declspec(dllexport) const void * __stdcall sqlite3_column_text16_interop(sqlite3_stmt *stmt, int iCol, int *plen) +{ + const void *pval = sqlite3_column_text16(stmt, iCol); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t): 0; + return pval; +} + +__declspec(dllexport) int __stdcall sqlite3_column_type_interop(sqlite3_stmt *stmt, int iCol) +{ + return sqlite3_column_type(stmt, iCol); +} + +__declspec(dllexport) int __stdcall sqlite3_finalize_interop(sqlite3_stmt *stmt) +{ + return sqlite3_finalize(stmt); +} + +__declspec(dllexport) int __stdcall sqlite3_reset_interop(sqlite3_stmt *stmt) +{ + return sqlite3_reset(stmt); +} + +__declspec(dllexport) int __stdcall sqlite3_create_function_interop(sqlite3 *psql, const char *zFunctionName, int nArg, int eTextRep, SQLITEUSERFUNC func, SQLITEUSERFUNC funcstep, SQLITEUSERFUNC funcfinal, void **ppCookie) +{ + int n; + SQLITEUSERFUNC *p = (SQLITEUSERFUNC *)malloc(sizeof(SQLITEUSERFUNC) * 3); + + p[0] = func; + p[1] = funcstep; + p[2] = funcfinal; + + *ppCookie = 0; + + n = sqlite3_create_function(psql, zFunctionName, nArg, eTextRep, p, (func != 0) ? sqlite3_interop_func : 0, (funcstep != 0) ? sqlite3_interop_step : 0, (funcfinal != 0) ? sqlite3_interop_final : 0); + if (n != 0) + free(p); + else + *ppCookie = p; + + return n; +} + +__declspec(dllexport) int __stdcall sqlite3_create_function16_interop(sqlite3 *psql, void *zFunctionName, int nArg, int eTextRep, SQLITEUSERFUNC func, SQLITEUSERFUNC funcstep, SQLITEUSERFUNC funcfinal, void **ppCookie) +{ + int n; + SQLITEUSERFUNC *p = (SQLITEUSERFUNC *)malloc(sizeof(SQLITEUSERFUNC) * 3); + + p[0] = func; + p[1] = funcstep; + p[2] = funcfinal; + + *ppCookie = 0; + + n = sqlite3_create_function16(psql, zFunctionName, nArg, eTextRep, p, (func != 0) ? sqlite3_interop_func : 0, (funcstep != 0) ? sqlite3_interop_step : 0, (funcfinal != 0) ? sqlite3_interop_final : 0); + if (n != 0) + free(p); + else + *ppCookie = p; + + return n; +} + +__declspec(dllexport) int __stdcall sqlite3_create_collation_interop(sqlite3* db, const char *zName, int eTextRep, void* pvUser, SQLITECOLLATION func, void **ppCookie) +{ + int n; + SQLITECOLLATION *p = (SQLITECOLLATION *)malloc(sizeof(SQLITECOLLATION)); + + p[0] = func; + + *ppCookie = 0; + + n = sqlite3_create_collation(db, zName, eTextRep, p, sqlite3_interop_collationfunc); + if (n != 0) + free(p); + else + *ppCookie = p; + + return n; +} + +__declspec(dllexport) int __stdcall sqlite3_create_collation16_interop(sqlite3* db, const void *zName, int eTextRep, void* pvUser, SQLITECOLLATION func, void **ppCookie) +{ + int n; + SQLITECOLLATION *p = (SQLITECOLLATION *)malloc(sizeof(SQLITECOLLATION)); + + p[0] = func; + + *ppCookie = 0; + + n = sqlite3_create_collation16(db, (const char *)zName, eTextRep, p, sqlite3_interop_collationfunc); + if (n != 0) + free(p); + else + *ppCookie = p; + + return n; +} + +__declspec(dllexport) int __stdcall sqlite3_aggregate_count_interop(sqlite3_context *pctx) +{ + return sqlite3_aggregate_count(pctx); +} + +__declspec(dllexport) const void * __stdcall sqlite3_value_blob_interop(sqlite3_value *val) +{ + return sqlite3_value_blob(val); +} + +__declspec(dllexport) int __stdcall sqlite3_value_bytes_interop(sqlite3_value *val) +{ + return sqlite3_value_bytes(val); +} + +__declspec(dllexport) int __stdcall sqlite3_value_bytes16_interop(sqlite3_value *val) +{ + return sqlite3_value_bytes16(val); +} + +__declspec(dllexport) void __stdcall sqlite3_value_double_interop(sqlite3_value *pval, double *val) +{ + *val = sqlite3_value_double(pval); +} + +__declspec(dllexport) int __stdcall sqlite3_value_int_interop(sqlite3_value *val) +{ + return sqlite3_value_int(val); +} + +__declspec(dllexport) void __stdcall sqlite3_value_int64_interop(sqlite3_value *pval, sqlite_int64 *val) +{ + *val = sqlite3_value_int64(pval); +} + +__declspec(dllexport) const unsigned char * __stdcall sqlite3_value_text_interop(sqlite3_value *val, int *plen) +{ + const unsigned char *pval = sqlite3_value_text(val); + *plen = (pval != 0) ? strlen((char *)pval) : 0; + return pval; +} + +__declspec(dllexport) const void * __stdcall sqlite3_value_text16_interop(sqlite3_value *val, int *plen) +{ + const void *pval = sqlite3_value_text16(val); + *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; + return pval; +} + +__declspec(dllexport) int __stdcall sqlite3_value_type_interop(sqlite3_value *val) +{ + return sqlite3_value_type(val); +} + +__declspec(dllexport) void * __stdcall sqlite3_aggregate_context_interop(sqlite3_context *pctx, int n) +{ + return sqlite3_aggregate_context(pctx, n); +} + +__declspec(dllexport) void __stdcall sqlite3_result_blob_interop(sqlite3_context *ctx, const void *pv, int n, void(*cb)(void *)) +{ + sqlite3_result_blob(ctx, pv, n, cb); +} + +__declspec(dllexport) void __stdcall sqlite3_result_double_interop(sqlite3_context *pctx, double *val) +{ + sqlite3_result_double(pctx, *val); +} + +__declspec(dllexport) void __stdcall sqlite3_result_int_interop(sqlite3_context *pctx, int val) +{ + sqlite3_result_int(pctx, val); +} + +__declspec(dllexport) void __stdcall sqlite3_result_int64_interop(sqlite3_context *pctx, sqlite_int64 *val) +{ + sqlite3_result_int64(pctx, *val); +} + +__declspec(dllexport) void __stdcall sqlite3_result_null_interop(sqlite3_context *pctx) +{ + sqlite3_result_null(pctx); +} + +__declspec(dllexport) void __stdcall sqlite3_result_error_interop(sqlite3_context *ctx, const char *pv, int n) +{ + sqlite3_result_error(ctx, pv, n); +} + +__declspec(dllexport) void __stdcall sqlite3_result_error16_interop(sqlite3_context *ctx, const void *pv, int n) +{ + sqlite3_result_error16(ctx, pv, n); +} + +__declspec(dllexport) void __stdcall sqlite3_result_text_interop(sqlite3_context *ctx, const char *pv, int n, void(*cb)(void *)) +{ + sqlite3_result_text(ctx, pv, n, cb); +} + +__declspec(dllexport) void __stdcall sqlite3_result_text16_interop(sqlite3_context *ctx, const void *pv, int n, void(*cb)(void *)) +{ + sqlite3_result_text16(ctx, pv, n, cb); +} + +__declspec(dllexport) void __stdcall sqlite3_realcolnames(sqlite3 *db, int bOn) +{ + if (bOn) + db->flags |= 0x01000000; + else + db->flags &= (~0x01000000); +} + +#endif // OS_WIN DELETED SQLite.Interop/interop.h Index: SQLite.Interop/interop.h ================================================================== --- SQLite.Interop/interop.h +++ /dev/null @@ -1,763 +0,0 @@ -/* - This interop file must be included at or near the top of the select.c file of the SQLite3 source distribution. - - generateColumnNames() in the select.c must be renamed to _generateColumnNames - -*/ -#include "os.h" -#include "sqliteint.h" - -static void generateColumnTypes( - Parse *pParse, /* Parser context */ - SrcList *pTabList, /* List of tables */ - ExprList *pEList /* Expressions defining the result set */ -); - -static void _generateColumnNames( - Parse *pParse, /* Parser context */ - SrcList *pTabList, /* List of tables */ - ExprList *pEList /* Expressions defining the result set */ -); - -/* -** Generate code that will tell the VDBE the names of columns -** in the result set. This information is used to provide the -** azCol[] values in the callback. -*/ -static void generateColumnNames( - Parse *pParse, /* Parser context */ - SrcList *pTabList, /* List of tables */ - ExprList *pEList /* Expressions defining the result set */ -){ - Vdbe *v = pParse->pVdbe; - int i, j; - sqlite3 *db = pParse->db; - int fullNames, shortNames; - int realNames; /*** ADDED - SQLite.Interop ***/ - - realNames = (db->flags & 0x01000000)!=0; /*** ADDED - SQLite.Interop ***/ - if (!realNames) // Default to normal Sqlite3 /*** ADDED - SQLite.Interop ***/ - { /*** ADDED - SQLite.Interop ***/ - _generateColumnNames(pParse, pTabList, pEList); /*** ADDED - SQLite.Interop ***/ - return; /*** ADDED - SQLite.Interop ***/ - } /*** ADDED - SQLite.Interop ***/ - -#ifndef SQLITE_OMIT_EXPLAIN - /* If this is an EXPLAIN, skip this step */ - if( pParse->explain ){ - return; - } -#endif - - assert( v!=0 ); - if( pParse->colNamesSet || v==0 || sqlite3_malloc_failed ) return; - pParse->colNamesSet = 1; - fullNames = (db->flags & SQLITE_FullColNames)!=0; - shortNames = (db->flags & SQLITE_ShortColNames)!=0; - if (realNames) fullNames = 1; /*** ADDED - SQLite.Interop ***/ - - sqlite3VdbeSetNumCols(v, pEList->nExpr); - for(i=0; inExpr; i++){ - Expr *p; - p = pEList->a[i].pExpr; - if( p==0 ) continue; - if( pEList->a[i].zName && (realNames == 0 || p->op != TK_COLUMN)){ /*** CHANGED - SQLite.Interop ***/ - char *zName = pEList->a[i].zName; - sqlite3VdbeSetColName(v, i, zName, strlen(zName)); - continue; - } - if( p->op==TK_COLUMN && pTabList ){ - Table *pTab; - char *zCol; - int iCol = p->iColumn; - for(j=0; jnSrc && pTabList->a[j].iCursor!=p->iTable; j++){} - assert( jnSrc ); - pTab = pTabList->a[j].pTab; - if( iCol<0 ) iCol = pTab->iPKey; - assert( iCol==-1 || (iCol>=0 && iColnCol) ); - if( iCol<0 ){ - zCol = "rowid"; - }else{ - zCol = pTab->aCol[iCol].zName; - } - if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){ - sqlite3VdbeSetColName(v, i, (char *)p->span.z, p->span.n); - }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){ - char *zName = 0; - char *zTab; - char *zDb = 0; /*** ADDED - SQLite.Interop ***/ - - zTab = pTabList->a[j].zAlias; - if( fullNames || zTab==0 ){ - if (pTab->iDb > 1) zDb = db->aDb[pTab->iDb].zName; /*** ADDED - SQLite.Interop ***/ - zTab = pTab->zName; - } - if (!zDb || !realNames) sqlite3SetString(&zName, zTab, ".", zCol, 0); /*** CHANGED - SQLite.Interop ***/ - else sqlite3SetString(&zName, zDb, ".", zTab, ".", zCol, 0); /*** ADDED - SQLite.Interop ***/ - sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC); - }else{ - sqlite3VdbeSetColName(v, i, zCol, strlen(zCol)); - } - }else if( p->span.z && p->span.z[0] ){ - sqlite3VdbeSetColName(v, i, (char *)p->span.z, p->span.n); - /* sqlite3VdbeCompressSpace(v, addr); */ - }else{ - char zName[30]; - assert( p->op!=TK_COLUMN || pTabList==0 ); - sprintf(zName, "column%d", i+1); - sqlite3VdbeSetColName(v, i, zName, 0); - } - } - generateColumnTypes(pParse, pTabList, pEList); -} - -#ifdef OS_WIN - -#include - -typedef void (__stdcall *SQLITEUSERFUNC)(void *, int, void **); -typedef int (__stdcall *SQLITECOLLATION)(int, const void *, int, const void*); - -typedef int (__stdcall *ENCRYPTFILEW)(const wchar_t *); -typedef int (__stdcall *ENCRYPTEDSTATUSW)(const wchar_t *, unsigned long *); -typedef int (__stdcall *DECRYPTFILEW)(const wchar_t *, unsigned long); - -typedef HANDLE (__stdcall *CREATEFILEW)( - LPCWSTR, - DWORD, - DWORD, - LPSECURITY_ATTRIBUTES, - DWORD, - DWORD, - HANDLE); - -// Callback wrappers -int sqlite3_interop_collationfunc(void *pv, int len1, const void *pv1, int len2, const void *pv2) -{ - SQLITECOLLATION *p = (SQLITECOLLATION *)pv; - return p[0](len1, pv1, len2, pv2); -} - -void sqlite3_interop_func(sqlite3_context *pctx, int n, sqlite3_value **pv) -{ - SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); - pf[0](pctx, n, (void **)pv); -} - -void sqlite3_interop_step(sqlite3_context *pctx, int n, sqlite3_value **pv) -{ - SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); - pf[1](pctx, n, (void **)pv); -} - -void sqlite3_interop_final(sqlite3_context *pctx) -{ - SQLITEUSERFUNC *pf = (SQLITEUSERFUNC *)sqlite3_user_data(pctx); - pf[2](pctx, 0, 0); -} - -__declspec(dllexport) void __stdcall sqlite3_sleep_interop(int milliseconds) -{ - Sleep(milliseconds); -} - -__declspec(dllexport) int sqlite3_encryptfile(const wchar_t *pwszFilename) -{ - HMODULE hMod = LoadLibrary(_T("ADVAPI32")); - ENCRYPTFILEW pfunc; - int n; - - if (hMod == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - pfunc = (ENCRYPTFILEW)GetProcAddress(hMod, _T("EncryptFileW")); - if (pfunc == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - n = pfunc(pwszFilename); - - FreeLibrary(hMod); - - return n; -} - -__declspec(dllexport) int sqlite3_decryptfile(const wchar_t *pwszFilename) -{ - HMODULE hMod = LoadLibrary(_T("ADVAPI32")); - DECRYPTFILEW pfunc; - int n; - - if (hMod == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - pfunc = (DECRYPTFILEW)GetProcAddress(hMod, _T("DecryptFileW")); - if (pfunc == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - n = pfunc(pwszFilename, 0); - - FreeLibrary(hMod); - - return n; -} - -__declspec(dllexport) unsigned long sqlite3_encryptedstatus(const wchar_t *pwszFilename, unsigned long *pdwStatus) -{ - HMODULE hMod = LoadLibrary(_T("ADVAPI32")); - ENCRYPTEDSTATUSW pfunc; - int n; - - if (hMod == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - pfunc = (ENCRYPTEDSTATUSW)GetProcAddress(hMod, _T("FileEncryptionStatusW")); - if (pfunc == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - n = pfunc(pwszFilename, pdwStatus); - - FreeLibrary(hMod); - - return n; -} - -int SetCompression(const wchar_t *pwszFilename, unsigned short ufLevel) -{ -#ifdef FSCTL_SET_COMPRESSION - HMODULE hMod = GetModuleHandle(_T("KERNEL32")); - CREATEFILEW pfunc; - HANDLE hFile; - unsigned long dw = 0; - int n; - - if (hMod == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - pfunc = (CREATEFILEW)GetProcAddress(hMod, _T("CreateFileW")); - if (pfunc == NULL) - { - SetLastError(ERROR_NOT_SUPPORTED); - return 0; - } - - hFile = pfunc(pwszFilename, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == NULL) - return 0; - - n = DeviceIoControl(hFile, FSCTL_SET_COMPRESSION, &ufLevel, sizeof(ufLevel), NULL, 0, &dw, NULL); - - CloseHandle(hFile); - - return n; -#else - SetLastError(ERROR_NOT_SUPPORTED); - return 0; -#endif -} - -__declspec(dllexport) int __stdcall sqlite3_compressfile(const wchar_t *pwszFilename) -{ - return SetCompression(pwszFilename, COMPRESSION_FORMAT_DEFAULT); -} - -__declspec(dllexport) int __stdcall sqlite3_decompressfile(const wchar_t *pwszFilename) -{ - return SetCompression(pwszFilename, COMPRESSION_FORMAT_NONE); -} - -__declspec(dllexport) void __stdcall sqlite3_function_free_callbackcookie(void *pCookie) -{ - if (pCookie) - free(pCookie); -} - -// sqlite3 wrappers -__declspec(dllexport) const char * __stdcall sqlite3_libversion_interop(int *plen) -{ - const char *val = sqlite3_libversion(); - *plen = (val != 0) ? strlen(val) : 0; - - return val; -} - -__declspec(dllexport) int __stdcall sqlite3_libversion_number_interop(void) -{ - return sqlite3_libversion_number(); -} - -__declspec(dllexport) int __stdcall sqlite3_close_interop(sqlite3 *db) -{ - return sqlite3_close(db); -} - -__declspec(dllexport) int __stdcall sqlite3_exec_interop(sqlite3 *db, const char *sql, sqlite3_callback cb, void *pv, char **errmsg, int *plen) -{ - int n = sqlite3_exec(db, sql, cb, pv, errmsg); - *plen = (*errmsg != 0) ? strlen(*errmsg) : 0; - return n; -} - -__declspec(dllexport) sqlite_int64 __stdcall sqlite3_last_insert_rowid_interop(sqlite3 *db) -{ - return sqlite3_last_insert_rowid(db); -} - -__declspec(dllexport) int __stdcall sqlite3_changes_interop(sqlite3 *db) -{ - return sqlite3_changes(db); -} - -__declspec(dllexport) int __stdcall sqlite3_total_changes_interop(sqlite3 *db) -{ - return sqlite3_total_changes(db); -} - -__declspec(dllexport) void __stdcall sqlite3_interrupt_interop(sqlite3 *db) -{ - sqlite3_interrupt(db); -} - -__declspec(dllexport) int __stdcall sqlite3_complete_interop(const char *sql) -{ - return sqlite3_complete(sql); -} - -__declspec(dllexport) int __stdcall sqlite3_complete16_interop(const void *sql) -{ - return sqlite3_complete16(sql); -} - -__declspec(dllexport) int __stdcall sqlite3_busy_handler_interop(sqlite3 *db, int(*cb)(void *, int), void *pv) -{ - return sqlite3_busy_handler(db, cb, pv); -} - -__declspec(dllexport) int __stdcall sqlite3_busy_timeout_interop(sqlite3 *db, int ms) -{ - return sqlite3_busy_timeout(db, ms); -} - -__declspec(dllexport) int __stdcall sqlite3_get_table_interop(sqlite3 *db, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg, int *plen) -{ - int n = sqlite3_get_table(db, sql, resultp, nrow, ncolumn, errmsg); - *plen = (*errmsg != 0) ? strlen((char *)*errmsg) : 0; - return n; -} - -__declspec(dllexport) void __stdcall sqlite3_free_table_interop(char **result) -{ - sqlite3_free_table(result); -} - -__declspec(dllexport) void __stdcall sqlite3_free_interop(char *z) -{ - sqlite3_free(z); -} - -__declspec(dllexport) int __stdcall sqlite3_open_interop(const char*filename, sqlite3 **ppdb) -{ - return sqlite3_open(filename, ppdb); -} - -__declspec(dllexport) int __stdcall sqlite3_open16_interop(const void *filename, sqlite3 **ppdb) -{ - return sqlite3_open16(filename, ppdb); -} - -__declspec(dllexport) int __stdcall sqlite3_errcode_interop(sqlite3 *db) -{ - return sqlite3_errcode(db); -} - -__declspec(dllexport) const char * __stdcall sqlite3_errmsg_interop(sqlite3 *db, int *plen) -{ - const char *pval = sqlite3_errmsg(db); - *plen = (pval != 0) ? strlen(pval) : 0; - return pval; -} - -__declspec(dllexport) const void * __stdcall sqlite3_errmsg16_interop(sqlite3 *db, int *plen) -{ - const void *pval = sqlite3_errmsg16(db); - *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t): 0; - return pval; -} - -__declspec(dllexport) int __stdcall sqlite3_prepare_interop(sqlite3 *db, const char *sql, int nbytes, sqlite3_stmt **ppstmt, const char **pztail, int *plen) -{ - int n = sqlite3_prepare(db, sql, nbytes, ppstmt, pztail); - *plen = (*pztail != 0) ? strlen(*pztail) : 0; - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_prepare16_interop(sqlite3 *db, const void *sql, int nbytes, sqlite3_stmt **ppstmt, const void **pztail, int *plen) -{ - int n = sqlite3_prepare16(db, sql, nbytes, ppstmt, pztail); - *plen = (*pztail != 0) ? wcslen((wchar_t *)*pztail) * sizeof(wchar_t) : 0; - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_bind_blob_interop(sqlite3_stmt *stmt, int iCol, const void *pv, int n, void(*cb)(void*)) -{ - return sqlite3_bind_blob(stmt, iCol, pv, n, cb); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_double_interop(sqlite3_stmt *stmt, int iCol, double *val) -{ - return sqlite3_bind_double(stmt,iCol,*val); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_int_interop(sqlite3_stmt *stmt, int iCol, int val) -{ - return sqlite3_bind_int(stmt, iCol, val); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_int64_interop(sqlite3_stmt *stmt, int iCol, sqlite_int64 *val) -{ - return sqlite3_bind_int64(stmt,iCol,*val); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_null_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_bind_null(stmt, iCol); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_text_interop(sqlite3_stmt *stmt, int iCol, const char *val, int n, void(*cb)(void *)) -{ - return sqlite3_bind_text(stmt, iCol, val, n, cb); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_text16_interop(sqlite3_stmt *stmt, int iCol, const void *val, int n, void(*cb)(void *)) -{ - return sqlite3_bind_text16(stmt, iCol, val, n, cb); -} - -__declspec(dllexport) int __stdcall sqlite3_bind_parameter_count_interop(sqlite3_stmt *stmt) -{ - return sqlite3_bind_parameter_count(stmt); -} - -__declspec(dllexport) const char * __stdcall sqlite3_bind_parameter_name_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const char *pval = sqlite3_bind_parameter_name(stmt, iCol); - *plen = (pval != 0) ? strlen(pval) : 0; - return pval; -} - -__declspec(dllexport) int __stdcall sqlite3_bind_parameter_index_interop(sqlite3_stmt *stmt, const char *zName) -{ - return sqlite3_bind_parameter_index(stmt, zName); -} - -__declspec(dllexport) int __stdcall sqlite3_column_count_interop(sqlite3_stmt *stmt) -{ - return sqlite3_column_count(stmt); -} - -__declspec(dllexport) const char * __stdcall sqlite3_column_name_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const char *pval = sqlite3_column_name(stmt, iCol); - *plen = (pval != 0) ? strlen(pval) : 0; - return pval; -} - -__declspec(dllexport) const void * __stdcall sqlite3_column_name16_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const void *pval = sqlite3_column_name16(stmt, iCol); - *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; - return pval; -} - -__declspec(dllexport) const char * __stdcall sqlite3_column_decltype_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const char *pval = sqlite3_column_decltype(stmt, iCol); - *plen = (pval != 0) ? strlen(pval) : 0; - return pval; -} - -__declspec(dllexport) const void * __stdcall sqlite3_column_decltype16_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const void *pval = sqlite3_column_decltype16(stmt, iCol); - *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; - return pval; -} - -__declspec(dllexport) int __stdcall sqlite3_step_interop(sqlite3_stmt *stmt) -{ - return sqlite3_step(stmt); -} - -__declspec(dllexport) int __stdcall sqlite3_data_count_interop(sqlite3_stmt *stmt) -{ - return sqlite3_data_count(stmt); -} - -__declspec(dllexport) const void * __stdcall sqlite3_column_blob_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_column_blob(stmt, iCol); -} - -__declspec(dllexport) int __stdcall sqlite3_column_bytes_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_column_bytes(stmt, iCol); -} - -__declspec(dllexport) int __stdcall sqlite3_column_bytes16_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_column_bytes16(stmt, iCol); -} - -__declspec(dllexport) void __stdcall sqlite3_column_double_interop(sqlite3_stmt *stmt, int iCol, double *val) -{ - *val = sqlite3_column_double(stmt,iCol); -} - -__declspec(dllexport) int __stdcall sqlite3_column_int_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_column_int(stmt, iCol); -} - -__declspec(dllexport) void __stdcall sqlite3_column_int64_interop(sqlite3_stmt *stmt, int iCol, sqlite_int64 *val) -{ - *val = sqlite3_column_int64(stmt,iCol); -} - -__declspec(dllexport) const unsigned char * __stdcall sqlite3_column_text_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const unsigned char *pval = sqlite3_column_text(stmt, iCol); - *plen = (pval != 0) ? strlen((char *)pval) : 0; - return pval; -} - -__declspec(dllexport) const void * __stdcall sqlite3_column_text16_interop(sqlite3_stmt *stmt, int iCol, int *plen) -{ - const void *pval = sqlite3_column_text16(stmt, iCol); - *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t): 0; - return pval; -} - -__declspec(dllexport) int __stdcall sqlite3_column_type_interop(sqlite3_stmt *stmt, int iCol) -{ - return sqlite3_column_type(stmt, iCol); -} - -__declspec(dllexport) int __stdcall sqlite3_finalize_interop(sqlite3_stmt *stmt) -{ - return sqlite3_finalize(stmt); -} - -__declspec(dllexport) int __stdcall sqlite3_reset_interop(sqlite3_stmt *stmt) -{ - return sqlite3_reset(stmt); -} - -__declspec(dllexport) int __stdcall sqlite3_create_function_interop(sqlite3 *psql, const char *zFunctionName, int nArg, int eTextRep, SQLITEUSERFUNC func, SQLITEUSERFUNC funcstep, SQLITEUSERFUNC funcfinal, void **ppCookie) -{ - int n; - SQLITEUSERFUNC *p = (SQLITEUSERFUNC *)malloc(sizeof(SQLITEUSERFUNC) * 3); - - p[0] = func; - p[1] = funcstep; - p[2] = funcfinal; - - *ppCookie = 0; - - n = sqlite3_create_function(psql, zFunctionName, nArg, eTextRep, p, (func != 0) ? sqlite3_interop_func : 0, (funcstep != 0) ? sqlite3_interop_step : 0, (funcfinal != 0) ? sqlite3_interop_final : 0); - if (n != 0) - free(p); - else - *ppCookie = p; - - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_create_function16_interop(sqlite3 *psql, void *zFunctionName, int nArg, int eTextRep, SQLITEUSERFUNC func, SQLITEUSERFUNC funcstep, SQLITEUSERFUNC funcfinal, void **ppCookie) -{ - int n; - SQLITEUSERFUNC *p = (SQLITEUSERFUNC *)malloc(sizeof(SQLITEUSERFUNC) * 3); - - p[0] = func; - p[1] = funcstep; - p[2] = funcfinal; - - *ppCookie = 0; - - n = sqlite3_create_function16(psql, zFunctionName, nArg, eTextRep, p, (func != 0) ? sqlite3_interop_func : 0, (funcstep != 0) ? sqlite3_interop_step : 0, (funcfinal != 0) ? sqlite3_interop_final : 0); - if (n != 0) - free(p); - else - *ppCookie = p; - - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_create_collation_interop(sqlite3* db, const char *zName, int eTextRep, void* pvUser, SQLITECOLLATION func, void **ppCookie) -{ - int n; - SQLITECOLLATION *p = (SQLITECOLLATION *)malloc(sizeof(SQLITECOLLATION)); - - p[0] = func; - - *ppCookie = 0; - - n = sqlite3_create_collation(db, zName, eTextRep, p, sqlite3_interop_collationfunc); - if (n != 0) - free(p); - else - *ppCookie = p; - - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_create_collation16_interop(sqlite3* db, const void *zName, int eTextRep, void* pvUser, SQLITECOLLATION func, void **ppCookie) -{ - int n; - SQLITECOLLATION *p = (SQLITECOLLATION *)malloc(sizeof(SQLITECOLLATION)); - - p[0] = func; - - *ppCookie = 0; - - n = sqlite3_create_collation16(db, (const char *)zName, eTextRep, p, sqlite3_interop_collationfunc); - if (n != 0) - free(p); - else - *ppCookie = p; - - return n; -} - -__declspec(dllexport) int __stdcall sqlite3_aggregate_count_interop(sqlite3_context *pctx) -{ - return sqlite3_aggregate_count(pctx); -} - -__declspec(dllexport) const void * __stdcall sqlite3_value_blob_interop(sqlite3_value *val) -{ - return sqlite3_value_blob(val); -} - -__declspec(dllexport) int __stdcall sqlite3_value_bytes_interop(sqlite3_value *val) -{ - return sqlite3_value_bytes(val); -} - -__declspec(dllexport) int __stdcall sqlite3_value_bytes16_interop(sqlite3_value *val) -{ - return sqlite3_value_bytes16(val); -} - -__declspec(dllexport) void __stdcall sqlite3_value_double_interop(sqlite3_value *pval, double *val) -{ - *val = sqlite3_value_double(pval); -} - -__declspec(dllexport) int __stdcall sqlite3_value_int_interop(sqlite3_value *val) -{ - return sqlite3_value_int(val); -} - -__declspec(dllexport) void __stdcall sqlite3_value_int64_interop(sqlite3_value *pval, sqlite_int64 *val) -{ - *val = sqlite3_value_int64(pval); -} - -__declspec(dllexport) const unsigned char * __stdcall sqlite3_value_text_interop(sqlite3_value *val, int *plen) -{ - const unsigned char *pval = sqlite3_value_text(val); - *plen = (pval != 0) ? strlen((char *)pval) : 0; - return pval; -} - -__declspec(dllexport) const void * __stdcall sqlite3_value_text16_interop(sqlite3_value *val, int *plen) -{ - const void *pval = sqlite3_value_text16(val); - *plen = (pval != 0) ? wcslen((wchar_t *)pval) * sizeof(wchar_t) : 0; - return pval; -} - -__declspec(dllexport) int __stdcall sqlite3_value_type_interop(sqlite3_value *val) -{ - return sqlite3_value_type(val); -} - -__declspec(dllexport) void * __stdcall sqlite3_aggregate_context_interop(sqlite3_context *pctx, int n) -{ - return sqlite3_aggregate_context(pctx, n); -} - -__declspec(dllexport) void __stdcall sqlite3_result_blob_interop(sqlite3_context *ctx, const void *pv, int n, void(*cb)(void *)) -{ - sqlite3_result_blob(ctx, pv, n, cb); -} - -__declspec(dllexport) void __stdcall sqlite3_result_double_interop(sqlite3_context *pctx, double *val) -{ - sqlite3_result_double(pctx, *val); -} - -__declspec(dllexport) void __stdcall sqlite3_result_int_interop(sqlite3_context *pctx, int val) -{ - sqlite3_result_int(pctx, val); -} - -__declspec(dllexport) void __stdcall sqlite3_result_int64_interop(sqlite3_context *pctx, sqlite_int64 *val) -{ - sqlite3_result_int64(pctx, *val); -} - -__declspec(dllexport) void __stdcall sqlite3_result_null_interop(sqlite3_context *pctx) -{ - sqlite3_result_null(pctx); -} - -__declspec(dllexport) void __stdcall sqlite3_result_error_interop(sqlite3_context *ctx, const char *pv, int n) -{ - sqlite3_result_error(ctx, pv, n); -} - -__declspec(dllexport) void __stdcall sqlite3_result_error16_interop(sqlite3_context *ctx, const void *pv, int n) -{ - sqlite3_result_error16(ctx, pv, n); -} - -__declspec(dllexport) void __stdcall sqlite3_result_text_interop(sqlite3_context *ctx, const char *pv, int n, void(*cb)(void *)) -{ - sqlite3_result_text(ctx, pv, n, cb); -} - -__declspec(dllexport) void __stdcall sqlite3_result_text16_interop(sqlite3_context *ctx, const void *pv, int n, void(*cb)(void *)) -{ - sqlite3_result_text16(ctx, pv, n, cb); -} - -__declspec(dllexport) void __stdcall sqlite3_realcolnames(sqlite3 *db, int bOn) -{ - if (bOn) - db->flags |= 0x01000000; - else - db->flags &= (~0x01000000); -} - -#endif // OS_WIN Index: SQLite.Interop/src/alter.c ================================================================== --- SQLite.Interop/src/alter.c +++ SQLite.Interop/src/alter.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that used to generate VDBE code ** that implements the ALTER TABLE command. ** -** $Id: alter.c,v 1.10 2005/12/19 17:57:46 rmsimpson Exp $ +** $Id: alter.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* @@ -45,11 +45,11 @@ unsigned char const *zSql = sqlite3_value_text(argv[0]); unsigned char const *zTableName = sqlite3_value_text(argv[1]); int token; Token tname; - char const *zCsr = zSql; + unsigned char const *zCsr = zSql; int len = 0; char *zRet; /* The principle used to locate the table name in the CREATE TABLE ** statement is that the table name is the first token that is immediatedly @@ -94,11 +94,11 @@ unsigned char const *zTableName = sqlite3_value_text(argv[1]); int token; Token tname; int dist = 3; - char const *zCsr = zSql; + unsigned char const *zCsr = zSql; int len = 0; char *zRet; /* The principle used to locate the table name in the CREATE TRIGGER ** statement is that the table name is the first token that is immediatedly @@ -175,13 +175,20 @@ */ static char *whereTempTriggers(Parse *pParse, Table *pTab){ Trigger *pTrig; char *zWhere = 0; char *tmp = 0; - if( pTab->iDb!=1 ){ + const Schema *pTempSchema = pParse->db->aDb[1].pSchema; /* Temp db schema */ + + /* If the table is not located in the temp-db (in which case NULL is + ** returned, loop through the tables list of triggers. For each trigger + ** that is not part of the temp-db schema, add a clause to the WHERE + ** expression being built up in zWhere. + */ + if( pTab->pSchema!=pTempSchema ){ for( pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext ){ - if( pTrig->iDb==1 ){ + if( pTrig->pSchema==pTempSchema ){ if( !zWhere ){ zWhere = sqlite3MPrintf("name=%Q", pTrig->name); }else{ tmp = zWhere; zWhere = sqlite3MPrintf("%s OR name=%Q", zWhere, pTrig->name); @@ -202,24 +209,26 @@ ** "ALTER TABLE RENAME TO" statement. */ static void reloadTableSchema(Parse *pParse, Table *pTab, const char *zName){ Vdbe *v; char *zWhere; - int iDb; + int iDb; /* Index of database containing pTab */ #ifndef SQLITE_OMIT_TRIGGER Trigger *pTrig; #endif v = sqlite3GetVdbe(pParse); if( !v ) return; - iDb = pTab->iDb; + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + assert( iDb>=0 ); #ifndef SQLITE_OMIT_TRIGGER /* Drop any table triggers from the internal schema. */ for(pTrig=pTab->pTrigger; pTrig; pTrig=pTrig->pNext){ - assert( pTrig->iDb==iDb || pTrig->iDb==1 ); - sqlite3VdbeOp3(v, OP_DropTrigger, pTrig->iDb, 0, pTrig->name, 0); + int iTrigDb = sqlite3SchemaToIndex(pParse->db, pTrig->pSchema); + assert( iTrigDb==iDb || iTrigDb==1 ); + sqlite3VdbeOp3(v, OP_DropTrigger, iTrigDb, 0, pTrig->name, 0); } #endif /* Drop the table and index from the internal schema */ sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); @@ -231,11 +240,11 @@ #ifndef SQLITE_OMIT_TRIGGER /* Now, if the table is not stored in the temp database, reload any temp ** triggers. Don't use IN(...) in case SQLITE_OMIT_SUBQUERY is defined. */ - if( (zWhere=whereTempTriggers(pParse, pTab)) ){ + if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ sqlite3VdbeOp3(v, OP_ParseSchema, 1, 0, zWhere, P3_DYNAMIC); } #endif } @@ -256,16 +265,16 @@ Vdbe *v; #ifndef SQLITE_OMIT_TRIGGER char *zWhere = 0; /* Where clause to locate temp triggers */ #endif - if( sqlite3_malloc_failed ) goto exit_rename_table; + if( sqlite3ThreadData()->mallocFailed ) goto exit_rename_table; assert( pSrc->nSrc==1 ); pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); if( !pTab ) goto exit_rename_table; - iDb = pTab->iDb; + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); zDb = db->aDb[iDb].zName; /* Get a NULL terminated version of the new table name. */ zName = sqlite3NameFromToken(pName); if( !zName ) goto exit_rename_table; @@ -347,11 +356,11 @@ #ifndef SQLITE_OMIT_TRIGGER /* If there are TEMP triggers on this table, modify the sqlite_temp_master ** table. Don't do this if the table being ALTERed is itself located in ** the temp database. */ - if( (zWhere=whereTempTriggers(pParse, pTab)) ){ + if( (zWhere=whereTempTriggers(pParse, pTab))!=0 ){ sqlite3NestedParse(pParse, "UPDATE sqlite_temp_master SET " "sql = sqlite_rename_trigger(sql, %Q), " "tbl_name = %Q " "WHERE %s;", zName, zName, zWhere); @@ -383,17 +392,16 @@ const char *zDb; /* Database name */ const char *zTab; /* Table name */ char *zCol; /* Null-terminated column definition */ Column *pCol; /* The new column */ Expr *pDflt; /* Default value for the new column */ - Vdbe *v; if( pParse->nErr ) return; pNew = pParse->pNewTable; assert( pNew ); - iDb = pNew->iDb; + iDb = sqlite3SchemaToIndex(pParse->db, pNew->pSchema); zDb = pParse->db->aDb[iDb].zName; zTab = pNew->zName; pCol = &pNew->aCol[pNew->nCol-1]; pDflt = pCol->pDflt; pTab = sqlite3FindTable(pParse->db, zTab, zDb); @@ -440,11 +448,11 @@ } sqlite3ValueFree(pVal); } /* Modify the CREATE TABLE statement. */ - zCol = sqliteStrNDup(pColDef->z, pColDef->n); + zCol = sqliteStrNDup((char*)pColDef->z, pColDef->n); if( zCol ){ char *zEnd = &zCol[pColDef->n-1]; while( (zEnd>zCol && *zEnd==';') || isspace(*(unsigned char *)zEnd) ){ *zEnd-- = '\0'; } @@ -460,25 +468,15 @@ /* If the default value of the new column is NULL, then set the file ** format to 2. If the default value of the new column is not NULL, ** the file format becomes 3. */ - if( (v=sqlite3GetVdbe(pParse)) ){ - int f = (pDflt?3:2); - - /* Only set the file format to $f if it is currently less than $f. */ - sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); - sqlite3VdbeAddOp(v, OP_Integer, f, 0); - sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3); - sqlite3VdbeAddOp(v, OP_Integer, f, 0); - sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); - } + sqlite3MinimumFileFormat(pParse, iDb, pDflt ? 3 : 2); /* Reload the schema of the modified table. */ reloadTableSchema(pParse, pTab, pTab->zName); } - /* ** This function is called by the parser after the table-name in ** an "ALTER TABLE ADD" statement is parsed. Argument ** pSrc is the full-name of the table being altered. @@ -499,14 +497,13 @@ Vdbe *v; int iDb; int i; int nAlloc; - /* Look up the table being altered. */ assert( pParse->pNewTable==0 ); - if( sqlite3_malloc_failed ) goto exit_begin_add_column; + if( sqlite3ThreadData()->mallocFailed ) goto exit_begin_add_column; pTab = sqlite3LocateTable(pParse, pSrc->a[0].zName, pSrc->a[0].zDatabase); if( !pTab ) goto exit_begin_add_column; /* Make sure this is not an attempt to ALTER a view. */ if( pTab->pSelect ){ @@ -513,11 +510,11 @@ sqlite3ErrorMsg(pParse, "Cannot add a column to a view"); goto exit_begin_add_column; } assert( pTab->addColOffset>0 ); - iDb = pTab->iDb; + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); /* Put a copy of the Table struct in Parse.pNewTable for the ** sqlite3AddColumn() function and friends to modify. */ pNew = (Table *)sqliteMalloc(sizeof(Table)); @@ -538,11 +535,11 @@ Column *pCol = &pNew->aCol[i]; pCol->zName = sqliteStrDup(pCol->zName); pCol->zType = 0; pCol->pDflt = 0; } - pNew->iDb = iDb; + pNew->pSchema = pParse->db->aDb[iDb].pSchema; pNew->addColOffset = pTab->addColOffset; pNew->nRef = 1; /* Begin a transaction and increment the schema cookie. */ sqlite3BeginWriteOperation(pParse, 0, iDb); Index: SQLite.Interop/src/analyze.c ================================================================== --- SQLite.Interop/src/analyze.c +++ SQLite.Interop/src/analyze.c @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code associated with the ANALYZE command. ** -** @(#) $Id: analyze.c,v 1.4 2005/12/19 17:57:46 rmsimpson Exp $ +** @(#) $Id: analyze.c,v 1.5 2006/01/10 18:40:37 rmsimpson Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" /* @@ -59,12 +59,18 @@ /* The sqlite_stat1 table already exists. Delete all rows. */ iRootPage = pStat->tnum; sqlite3VdbeAddOp(v, OP_Clear, pStat->tnum, iDb); } - /* Open the sqlite_stat1 table for writing. + /* Open the sqlite_stat1 table for writing. Unless it was created + ** by this vdbe program, lock it for writing at the shared-cache level. + ** If this vdbe did create the sqlite_stat1 table, then it must have + ** already obtained a schema-lock, making the write-lock redundant. */ + if( iRootPage>0 ){ + sqlite3TableLock(pParse, iDb, iRootPage, 1, "sqlite_stat1"); + } sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp(v, OP_OpenWrite, iStatCur, iRootPage); sqlite3VdbeAddOp(v, OP_SetNumColumns, iStatCur, 3); } @@ -84,29 +90,36 @@ Vdbe *v; /* The virtual machine being built up */ int i; /* Loop counter */ int topOfLoop; /* The top of the loop */ int endOfLoop; /* The end of the loop */ int addr; /* The address of an instruction */ + int iDb; /* Index of database containing pTab */ v = sqlite3GetVdbe(pParse); if( pTab==0 || pTab->pIndex==0 ){ /* Do no analysis for tables that have no indices */ return; } + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + assert( iDb>=0 ); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_ANALYZE, pTab->zName, 0, - pParse->db->aDb[pTab->iDb].zName ) ){ + pParse->db->aDb[iDb].zName ) ){ return; } #endif + + /* Establish a read-lock on the table at the shared-cache level. */ + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); iIdxCur = pParse->nTab; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ /* Open a cursor to the index to be analyzed */ - sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + assert( iDb==sqlite3SchemaToIndex(pParse->db, pIdx->pSchema) ); + sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); VdbeComment((v, "# %s", pIdx->zName)); sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIdx->tnum, (char*)&pIdx->keyInfo, P3_KEYINFO); nCol = pIdx->nColumn; if( iMem+nCol*2>=pParse->nMem ){ @@ -137,19 +150,19 @@ /* Do the analysis. */ endOfLoop = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_Rewind, iIdxCur, endOfLoop); topOfLoop = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp(v, OP_MemIncr, iMem, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, 1, iMem); for(i=0; idb; + Schema *pSchema = db->aDb[iDb].pSchema; /* Schema of database iDb */ HashElem *k; int iStatCur; int iMem; sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab++; openStatTable(pParse, iDb, iStatCur, 0); iMem = pParse->nMem; - for(k=sqliteHashFirst(&db->aDb[iDb].tblHash); k; k=sqliteHashNext(k)){ + for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){ Table *pTab = (Table*)sqliteHashData(k); analyzeOneTable(pParse, pTab, iStatCur, iMem); } loadAnalysis(pParse, iDb); } @@ -236,11 +251,11 @@ static void analyzeTable(Parse *pParse, Table *pTab){ int iDb; int iStatCur; assert( pTab!=0 ); - iDb = pTab->iDb; + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); sqlite3BeginWriteOperation(pParse, 0, iDb); iStatCur = pParse->nTab++; openStatTable(pParse, iDb, iStatCur, pTab->zName); analyzeOneTable(pParse, pTab, iStatCur, pParse->nMem); loadAnalysis(pParse, iDb); @@ -358,11 +373,11 @@ analysisInfo sInfo; HashElem *i; char *zSql; /* Clear any prior statistics */ - for(i=sqliteHashFirst(&db->aDb[iDb].idxHash); i; i=sqliteHashNext(i)){ + for(i=sqliteHashFirst(&db->aDb[iDb].pSchema->idxHash);i;i=sqliteHashNext(i)){ Index *pIdx = sqliteHashData(i); sqlite3DefaultRowEst(pIdx); } /* Check to make sure the sqlite_stat1 table existss */ Index: SQLite.Interop/src/attach.c ================================================================== --- SQLite.Interop/src/attach.c +++ SQLite.Interop/src/attach.c @@ -9,205 +9,347 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. ** -** $Id: attach.c,v 1.10 2005/12/19 17:57:46 rmsimpson Exp $ +** $Id: attach.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" /* -** This routine is called by the parser to process an ATTACH statement: +** Resolve an expression that was part of an ATTACH or DETACH statement. This +** is slightly different from resolving a normal SQL expression, because simple +** identifiers are treated as strings, not possible column names or aliases. +** +** i.e. if the parser sees: +** +** ATTACH DATABASE abc AS def +** +** it treats the two expressions as literal strings 'abc' and 'def' instead of +** looking for columns of the same name. +** +** This only applies to the root node of pExpr, so the statement: +** +** ATTACH DATABASE abc||def AS 'db2' +** +** will fail because neither abc or def can be resolved. +*/ +int resolveAttachExpr(NameContext *pName, Expr *pExpr) +{ + int rc = SQLITE_OK; + if( pExpr ){ + if( pExpr->op!=TK_ID ){ + rc = sqlite3ExprResolveNames(pName, pExpr); + }else{ + pExpr->op = TK_STRING; + } + } + return rc; +} + +/* +** An SQL user-function registered to do the work of an ATTACH statement. The +** three arguments to the function come directly from an attach statement: +** +** ATTACH DATABASE x AS y KEY z ** -** ATTACH DATABASE filename AS dbname +** SELECT sqlite_attach(x, y, z) ** -** The pFilename and pDbname arguments are the tokens that define the -** filename and dbname in the ATTACH statement. +** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the +** third argument. */ -void sqlite3Attach( - Parse *pParse, /* The parser context */ - Token *pFilename, /* Name of database file */ - Token *pDbname, /* Name of the database to use internally */ - int keyType, /* 0: no key. 1: TEXT, 2: BLOB */ - Token *pKey /* Text of the key for keytype 1 and 2 */ +static void attachFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv ){ + int i; + int rc = 0; + sqlite3 *db = sqlite3_user_data(context); + const char *zName; + const char *zFile; Db *aNew; - int rc, i; - char *zFile = 0; - char *zName = 0; - sqlite3 *db; - Vdbe *v; - - v = sqlite3GetVdbe(pParse); - if( !v ) return; - sqlite3VdbeAddOp(v, OP_Expire, 1, 0); - sqlite3VdbeAddOp(v, OP_Halt, 0, 0); - if( pParse->explain ) return; - db = pParse->db; + char zErr[128]; + char *zErrDyn = 0; + + zFile = (const char *)sqlite3_value_text(argv[0]); + zName = (const char *)sqlite3_value_text(argv[1]); + + /* Check for the following errors: + ** + ** * Too many attached databases, + ** * Transaction currently open + ** * Specified database name already being used. + */ if( db->nDb>=MAX_ATTACHED+2 ){ - sqlite3ErrorMsg(pParse, "too many attached databases - max %d", - MAX_ATTACHED); - pParse->rc = SQLITE_ERROR; - return; + sqlite3_snprintf( + 127, zErr, "too many attached databases - max %d", MAX_ATTACHED + ); + goto attach_error; } - if( !db->autoCommit ){ - sqlite3ErrorMsg(pParse, "cannot ATTACH database within transaction"); - pParse->rc = SQLITE_ERROR; - return; - } - - zFile = sqlite3NameFromToken(pFilename); - if( zFile==0 ){ - goto attach_end; - } -#ifndef SQLITE_OMIT_AUTHORIZATION - if( sqlite3AuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){ - goto attach_end; - } -#endif /* SQLITE_OMIT_AUTHORIZATION */ - - zName = sqlite3NameFromToken(pDbname); - if( zName==0 ){ - goto attach_end; + strcpy(zErr, "cannot ATTACH database within transaction"); + goto attach_error; } for(i=0; inDb; i++){ char *z = db->aDb[i].zName; if( z && sqlite3StrICmp(z, zName)==0 ){ - sqlite3ErrorMsg(pParse, "database %s is already in use", zName); - pParse->rc = SQLITE_ERROR; - goto attach_end; + sqlite3_snprintf(127, zErr, "database %s is already in use", zName); + goto attach_error; } } + /* Allocate the new entry in the db->aDb[] array and initialise the schema + ** hash tables. + */ if( db->aDb==db->aDbStatic ){ aNew = sqliteMalloc( sizeof(db->aDb[0])*3 ); if( aNew==0 ){ - goto attach_end; + return; } memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); if( aNew==0 ){ - goto attach_end; + return; } } db->aDb = aNew; aNew = &db->aDb[db->nDb++]; memset(aNew, 0, sizeof(*aNew)); - sqlite3HashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0); - sqlite3HashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0); - sqlite3HashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0); - sqlite3HashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1); - aNew->zName = zName; - zName = 0; - aNew->safety_level = 3; + + /* Open the database file. If the btree is successfully opened, use + ** it to obtain the database schema. At this point the schema may + ** or may not be initialised. + */ rc = sqlite3BtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt); - if( rc ){ - sqlite3ErrorMsg(pParse, "unable to open database: %s", zFile); + if( rc==SQLITE_OK ){ + aNew->pSchema = sqlite3SchemaGet(aNew->pBt); + if( !aNew->pSchema ){ + rc = SQLITE_NOMEM; + }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ + strcpy(zErr, + "attached databases must use the same text encoding as main database"); + goto attach_error; + } } + aNew->zName = sqliteStrDup(zName); + aNew->safety_level = 3; + #if SQLITE_HAS_CODEC { extern int sqlite3CodecAttach(sqlite3*, int, void*, int); - char *zKey; + extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); int nKey; - if( keyType==0 ){ - /* No key specified. Use the key from the main database */ - extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); - sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); - }else if( keyType==1 ){ - /* Key specified as text */ - zKey = sqlite3NameFromToken(pKey); - nKey = strlen(zKey); - }else{ - /* Key specified as a BLOB */ - char *zTemp; - assert( keyType==2 ); - pKey->z++; - pKey->n--; - zTemp = sqlite3NameFromToken(pKey); - zKey = sqlite3HexToBlob(zTemp); - sqliteFree(zTemp); - } - sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); - if( keyType ){ - sqliteFree(zKey); + char *zKey; + int t = sqlite3_value_type(argv[2]); + switch( t ){ + case SQLITE_INTEGER: + case SQLITE_FLOAT: + zErrDyn = sqliteStrDup("Invalid key value"); + rc = SQLITE_ERROR; + break; + + case SQLITE_TEXT: + case SQLITE_BLOB: + nKey = sqlite3_value_bytes(argv[2]); + zKey = (char *)sqlite3_value_blob(argv[2]); + sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); + break; + + case SQLITE_NULL: + /* No key specified. Use the key from the main database */ + sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); + sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); + break; } } #endif - db->flags &= ~SQLITE_Initialized; - if( pParse->nErr==0 && rc==SQLITE_OK ){ - rc = sqlite3ReadSchema(pParse); + + /* If the file was opened successfully, read the schema for the new database. + ** If this fails, or if opening the file failed, then close the file and + ** remove the entry from the db->aDb[] array. i.e. put everything back the way + ** we found it. + */ + if( rc==SQLITE_OK ){ + db->flags &= ~SQLITE_Initialized; + sqlite3SafetyOn(db); + rc = sqlite3Init(db, &zErrDyn); + sqlite3SafetyOff(db); } if( rc ){ int i = db->nDb - 1; assert( i>=2 ); if( db->aDb[i].pBt ){ sqlite3BtreeClose(db->aDb[i].pBt); db->aDb[i].pBt = 0; + db->aDb[i].pSchema = 0; } sqlite3ResetInternalSchema(db, 0); - assert( pParse->nErr>0 ); /* Always set by sqlite3ReadSchema() */ - if( pParse->rc==SQLITE_OK ){ - pParse->rc = SQLITE_ERROR; - } - } - -attach_end: - sqliteFree(zFile); - sqliteFree(zName); -} - -/* -** This routine is called by the parser to process a DETACH statement: -** -** DETACH DATABASE dbname -** -** The pDbname argument is the name of the database in the DETACH statement. -*/ -void sqlite3Detach(Parse *pParse, Token *pDbname){ - int i; - sqlite3 *db; - Vdbe *v; - Db *pDb = 0; - char *zName; - - v = sqlite3GetVdbe(pParse); - if( !v ) return; - sqlite3VdbeAddOp(v, OP_Expire, 0, 0); - sqlite3VdbeAddOp(v, OP_Halt, 0, 0); - if( pParse->explain ) return; - db = pParse->db; - zName = sqlite3NameFromToken(pDbname); - if( zName==0 ) return; + db->nDb = i; + sqlite3_snprintf(127, zErr, "unable to open database: %s", zFile); + goto attach_error; + } + + return; + +attach_error: + /* Return an error if we get here */ + if( zErrDyn ){ + sqlite3_result_error(context, zErrDyn, -1); + sqliteFree(zErrDyn); + }else{ + zErr[sizeof(zErr)-1] = 0; + sqlite3_result_error(context, zErr, -1); + } +} + +/* +** An SQL user-function registered to do the work of an DETACH statement. The +** three arguments to the function come directly from a detach statement: +** +** DETACH DATABASE x +** +** SELECT sqlite_detach(x) +*/ +static void detachFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + const char *zName = (const char *)sqlite3_value_text(argv[0]); + sqlite3 *db = sqlite3_user_data(context); + int i; + Db *pDb = 0; + char zErr[128]; + + assert(zName); for(i=0; inDb; i++){ pDb = &db->aDb[i]; if( pDb->pBt==0 ) continue; if( sqlite3StrICmp(pDb->zName, zName)==0 ) break; } + if( i>=db->nDb ){ - sqlite3ErrorMsg(pParse, "no such database: %z", zName); - return; + sqlite3_snprintf(sizeof(zErr), zErr, "no such database: %s", zName); + goto detach_error; } if( i<2 ){ - sqlite3ErrorMsg(pParse, "cannot detach database %z", zName); - return; + sqlite3_snprintf(sizeof(zErr), zErr, "cannot detach database %s", zName); + goto detach_error; } - sqliteFree(zName); if( !db->autoCommit ){ - sqlite3ErrorMsg(pParse, "cannot DETACH database within transaction"); - pParse->rc = SQLITE_ERROR; - return; - } -#ifndef SQLITE_OMIT_AUTHORIZATION - if( sqlite3AuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){ - return; - } -#endif /* SQLITE_OMIT_AUTHORIZATION */ + strcpy(zErr, "cannot DETACH database within transaction"); + goto detach_error; + } + sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; + pDb->pSchema = 0; sqlite3ResetInternalSchema(db, 0); + return; + +detach_error: + sqlite3_result_error(context, zErr, -1); +} + +/* +** This procedure generates VDBE code for a single invocation of either the +** sqlite_detach() or sqlite_attach() SQL user functions. +*/ +static void codeAttach( + Parse *pParse, /* The parser context */ + int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */ + const char *zFunc, /* Either "sqlite_attach" or "sqlite_detach */ + int nFunc, /* Number of args to pass to zFunc */ + Expr *pAuthArg, /* Expression to pass to authorization callback */ + Expr *pFilename, /* Name of database file */ + Expr *pDbname, /* Name of the database to use internally */ + Expr *pKey /* Database key for encryption extension */ +){ + int rc; + NameContext sName; + Vdbe *v; + FuncDef *pFunc; + sqlite3* db = pParse->db; + +#ifndef SQLITE_OMIT_AUTHORIZATION + assert( sqlite3ThreadData()->mallocFailed || pAuthArg ); + if( pAuthArg ){ + char *zAuthArg = sqlite3NameFromToken(&pAuthArg->span); + if( !zAuthArg ){ + goto attach_end; + } + rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0); + sqliteFree(zAuthArg); + if(rc!=SQLITE_OK ){ + goto attach_end; + } + } +#endif /* SQLITE_OMIT_AUTHORIZATION */ + + memset(&sName, 0, sizeof(NameContext)); + sName.pParse = pParse; + + if( + SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) || + SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || + SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) + ){ + pParse->nErr++; + goto attach_end; + } + + v = sqlite3GetVdbe(pParse); + sqlite3ExprCode(pParse, pFilename); + sqlite3ExprCode(pParse, pDbname); + sqlite3ExprCode(pParse, pKey); + + assert(v || sqlite3ThreadData()->mallocFailed); + if( v ){ + sqlite3VdbeAddOp(v, OP_Function, 0, nFunc); + pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); + sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF); + + /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this + ** statement only). For DETACH, set it to false (expire all existing + ** statements). + */ + sqlite3VdbeAddOp(v, OP_Expire, (type==SQLITE_ATTACH), 0); + } + +attach_end: + sqlite3ExprDelete(pFilename); + sqlite3ExprDelete(pDbname); + sqlite3ExprDelete(pKey); +} + +/* +** Called by the parser to compile a DETACH statement. +** +** DETACH pDbname +*/ +void sqlite3Detach(Parse *pParse, Expr *pDbname){ + codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname); +} + +/* +** Called by the parser to compile an ATTACH statement. +** +** ATTACH p AS pDbname KEY pKey +*/ +void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){ + codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey); +} + +/* +** Register the functions sqlite_attach and sqlite_detach. +*/ +void sqlite3AttachFunctions(sqlite3 *db){ + static const int enc = SQLITE_UTF8; + sqlite3_create_function(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0); + sqlite3_create_function(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0); } /* ** Initialize a DbFixer structure. This routine must be called prior ** to passing the structure to one of the sqliteFixAAAA() routines below. Index: SQLite.Interop/src/auth.c ================================================================== --- SQLite.Interop/src/auth.c +++ SQLite.Interop/src/auth.c @@ -12,11 +12,11 @@ ** This file contains code used to implement the sqlite3_set_authorizer() ** API. This facility is an optional feature of the library. Embedded ** systems that do not need this facility may omit it by recompiling ** the library with -DSQLITE_OMIT_AUTHORIZATION=1 ** -** $Id: auth.c,v 1.10 2005/12/19 17:57:46 rmsimpson Exp $ +** $Id: auth.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" /* ** All of the code in this file may be omitted by defining a single @@ -110,14 +110,16 @@ Table *pTab; /* The table being read */ const char *zCol; /* Name of the column of the table */ int iSrc; /* Index in pTabList->a[] of table being read */ const char *zDBase; /* Name of database being accessed */ TriggerStack *pStack; /* The stack of current triggers */ + int iDb; /* The index of the database the expression refers to */ if( db->xAuth==0 ) return; if( pExpr->op==TK_AS ) return; assert( pExpr->op==TK_COLUMN ); + iDb = sqlite3SchemaToIndex(pParse->db, pExpr->pSchema); for(iSrc=0; pTabList && iSrcnSrc; iSrc++){ if( pExpr->iTable==pTabList->a[iSrc].iCursor ) break; } if( iSrc>=0 && pTabList && iSrcnSrc ){ pTab = pTabList->a[iSrc].pTab; @@ -138,18 +140,18 @@ assert( pTab->iPKeynCol ); zCol = pTab->aCol[pTab->iPKey].zName; }else{ zCol = "ROWID"; } - assert( pExpr->iDbnDb ); - zDBase = db->aDb[pExpr->iDb].zName; + assert( iDbnDb ); + zDBase = db->aDb[iDb].zName; rc = db->xAuth(db->pAuthArg, SQLITE_READ, pTab->zName, zCol, zDBase, pParse->zAuthContext); if( rc==SQLITE_IGNORE ){ pExpr->op = TK_NULL; }else if( rc==SQLITE_DENY ){ - if( db->nDb>2 || pExpr->iDb!=0 ){ + if( db->nDb>2 || iDb!=0 ){ sqlite3ErrorMsg(pParse, "access to %s.%s.%s is prohibited", zDBase, pTab->zName, zCol); }else{ sqlite3ErrorMsg(pParse, "access to %s.%s is prohibited",pTab->zName,zCol); } Index: SQLite.Interop/src/btree.c ================================================================== --- SQLite.Interop/src/btree.c +++ SQLite.Interop/src/btree.c @@ -7,11 +7,11 @@ ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.12 2005/12/19 17:57:46 rmsimpson Exp $ +** $Id: btree.c,v 1.13 2006/01/10 18:40:37 rmsimpson Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: @@ -228,10 +228,11 @@ */ #define MX_CELL(pBt) ((pBt->pageSize-8)/3) /* Forward declarations */ typedef struct MemPage MemPage; +typedef struct BtLock BtLock; /* ** This is a magic string that appears at the beginning of every ** SQLite database in order to identify the file as a real database. ** @@ -283,14 +284,14 @@ u16 cellOffset; /* Index in aData of first cell pointer */ u16 idxParent; /* Index in parent of this node */ u16 nFree; /* Number of free bytes on the page */ u16 nCell; /* Number of cells on this page, local and ovfl */ struct _OvflCell { /* Cells that will not fit on aData[] */ - u8 *pCell; /* Pointers to the body of the overflow cell */ - u16 idx; /* Insert this cell before idx-th non-overflow cell */ + u8 *pCell; /* Pointers to the body of the overflow cell */ + u16 idx; /* Insert this cell before idx-th non-overflow cell */ } aOvfl[5]; - struct Btree *pBt; /* Pointer back to BTree structure */ + BtShared *pBt; /* Pointer back to BTree structure */ u8 *aData; /* Pointer back to the start of the page */ Pgno pgno; /* Page number for this page */ MemPage *pParent; /* The parent of this page. NULL for root */ }; @@ -299,18 +300,36 @@ ** to the end. EXTRA_SIZE is the number of bytes of space needed to hold ** that extra information. */ #define EXTRA_SIZE sizeof(MemPage) +/* Btree handle */ +struct Btree { + sqlite3 *pSqlite; + BtShared *pBt; + u8 inTrans; /* TRANS_NONE, TRANS_READ or TRANS_WRITE */ +}; + +/* +** Btree.inTrans may take one of the following values. +** +** If the shared-data extension is enabled, there may be multiple users +** of the Btree structure. At most one of these may open a write transaction, +** but any number may have active read transactions. Variable Btree.pDb +** points to the handle that owns any current write-transaction. +*/ +#define TRANS_NONE 0 +#define TRANS_READ 1 +#define TRANS_WRITE 2 + /* ** Everything we need to know about an open database */ -struct Btree { +struct BtShared { Pager *pPager; /* The page cache */ BtCursor *pCursor; /* A list of all open cursors */ MemPage *pPage1; /* First page of the database */ - u8 inTrans; /* True if a transaction is in progress */ u8 inStmt; /* True if we are in a statement subtransaction */ u8 readOnly; /* True if the underlying file is readonly */ u8 maxEmbedFrac; /* Maximum payload as % of total page size */ u8 minEmbedFrac; /* Minimum payload as % of total page size */ u8 minLeafFrac; /* Minimum leaf payload as % of total page size */ @@ -323,19 +342,20 @@ int maxLocal; /* Maximum local payload in non-LEAFDATA tables */ int minLocal; /* Minimum local payload in non-LEAFDATA tables */ int maxLeaf; /* Maximum local payload in a LEAFDATA table */ int minLeaf; /* Minimum local payload in a LEAFDATA table */ BusyHandler *pBusyHandler; /* Callback for when there is lock contention */ + u8 inTransaction; /* Transaction state */ + int nRef; /* Number of references to this structure */ + int nTransaction; /* Number of open transactions (read + write) */ + void *pSchema; /* Pointer to space allocated by sqlite3BtreeSchema() */ + void (*xFreeSchema)(void*); /* Destructor for BtShared.pSchema */ +#ifndef SQLITE_OMIT_SHARED_CACHE + BtLock *pLock; /* List of locks held on this shared-btree struct */ + BtShared *pNext; /* Next in ThreadData.pBtree linked list */ +#endif }; -typedef Btree Bt; - -/* -** Btree.inTrans may take one of the following values. -*/ -#define TRANS_NONE 0 -#define TRANS_READ 1 -#define TRANS_WRITE 2 /* ** An instance of the following structure is used to hold information ** about a cell. The parseCellPtr() function fills in this structure ** based on information extract from the raw disk page. @@ -355,22 +375,51 @@ ** A cursor is a pointer to a particular entry in the BTree. ** The entry is identified by its MemPage and the index in ** MemPage.aCell[] of the entry. */ struct BtCursor { - Btree *pBt; /* The Btree to which this cursor belongs */ + Btree *pBtree; /* The Btree to which this cursor belongs */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */ void *pArg; /* First arg to xCompare() */ Pgno pgnoRoot; /* The root page of this tree */ MemPage *pPage; /* Page that contains the entry */ int idx; /* Index of the entry in pPage->aCell[] */ CellInfo info; /* A parse of the cell we are pointing at */ u8 wrFlag; /* True if writable */ - u8 isValid; /* TRUE if points to a valid entry */ + u8 eState; /* One of the CURSOR_XXX constants (see below) */ +#ifndef SQLITE_OMIT_SHARED_CACHE + void *pKey; + i64 nKey; + int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */ +#endif }; +/* +** Potential values for BtCursor.eState. The first two values (VALID and +** INVALID) may occur in any build. The third (REQUIRESEEK) may only occur +** if sqlite was compiled without the OMIT_SHARED_CACHE symbol defined. +** +** CURSOR_VALID: +** Cursor points to a valid entry. getPayload() etc. may be called. +** +** CURSOR_INVALID: +** Cursor does not point to a valid entry. This can happen (for example) +** because the table is empty or because BtreeCursorFirst() has not been +** called. +** +** CURSOR_REQUIRESEEK: +** The table that this cursor was opened on still exists, but has been +** modified since the cursor was last used. The cursor position is saved +** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in +** this state, restoreCursorPosition() can be called to attempt to seek +** the cursor to the saved position. +*/ +#define CURSOR_INVALID 0 +#define CURSOR_VALID 1 +#define CURSOR_REQUIRESEEK 2 + /* ** The TRACE macro will print high-level status information about the ** btree operation when the global variable sqlite3_btree_trace is ** enabled. */ @@ -383,11 +432,11 @@ int sqlite3_btree_trace=0; /* True to enable tracing */ /* ** Forward declaration */ -static int checkReadLocks(Btree*,Pgno,BtCursor*); +static int checkReadLocks(BtShared*,Pgno,BtCursor*); /* ** Read or write a two- and four-byte big-endian integer values. */ static u32 get2byte(unsigned char *p){ @@ -420,10 +469,276 @@ ** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They ** should possibly be consolidated (presumably in pager.h). */ #define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1) +/* +** A linked list of the following structures is stored at BtShared.pLock. +** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor +** is opened on the table with root page BtShared.iTable. Locks are removed +** from this list when a transaction is committed or rolled back, or when +** a btree handle is closed. +*/ +struct BtLock { + Btree *pBtree; /* Btree handle holding this lock */ + Pgno iTable; /* Root page of table */ + u8 eLock; /* READ_LOCK or WRITE_LOCK */ + BtLock *pNext; /* Next in BtShared.pLock list */ +}; + +/* Candidate values for BtLock.eLock */ +#define READ_LOCK 1 +#define WRITE_LOCK 2 + +#ifdef SQLITE_OMIT_SHARED_CACHE + /* + ** The functions queryTableLock(), lockTable() and unlockAllTables() + ** manipulate entries in the BtShared.pLock linked list used to store + ** shared-cache table level locks. If the library is compiled with the + ** shared-cache feature disabled, then there is only ever one user + ** of each BtShared structure and so this locking is not necessary. + ** So define the lock related functions as no-ops. + */ + #define queryTableLock(a,b,c) SQLITE_OK + #define lockTable(a,b,c) SQLITE_OK + #define unlockAllTables(a) + #define restoreCursorPosition(a,b) SQLITE_OK + #define saveAllCursors(a,b,c) SQLITE_OK + +#else + +/* +** Save the current cursor position in the variables BtCursor.nKey +** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. +*/ +static int saveCursorPosition(BtCursor *pCur){ + int rc = SQLITE_OK; + + assert( CURSOR_VALID==pCur->eState|| CURSOR_INVALID==pCur->eState ); + assert( 0==pCur->pKey ); + + if( pCur->eState==CURSOR_VALID ){ + rc = sqlite3BtreeKeySize(pCur, &pCur->nKey); + + /* If this is an intKey table, then the above call to BtreeKeySize() + ** stores the integer key in pCur->nKey. In this case this value is + ** all that is required. Otherwise, if pCur is not open on an intKey + ** table, then malloc space for and store the pCur->nKey bytes of key + ** data. + */ + if( rc==SQLITE_OK && 0==pCur->pPage->intKey){ + void *pKey = sqliteMalloc(pCur->nKey); + if( pKey ){ + rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey); + if( rc==SQLITE_OK ){ + pCur->pKey = pKey; + }else{ + sqliteFree(pKey); + } + }else{ + rc = SQLITE_NOMEM; + } + } + assert( !pCur->pPage->intKey || !pCur->pKey ); + + /* Todo: Should we drop the reference to pCur->pPage here? */ + + if( rc==SQLITE_OK ){ + pCur->eState = CURSOR_REQUIRESEEK; + } + } + + return rc; +} + +/* +** Save the positions of all cursors except pExcept open on the table +** with root-page iRoot. Usually, this is called just before cursor +** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()). +*/ +static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){ + BtCursor *p; + if( sqlite3ThreadData()->useSharedData ){ + for(p=pBt->pCursor; p; p=p->pNext){ + if( p!=pExcept && p->pgnoRoot==iRoot && p->eState==CURSOR_VALID ){ + int rc = saveCursorPosition(p); + if( SQLITE_OK!=rc ){ + return rc; + } + } + } + } + return SQLITE_OK; +} + +/* +** Restore the cursor to the position it was in (or as close to as possible) +** when saveCursorPosition() was called. Note that this call deletes the +** saved position info stored by saveCursorPosition(), so there can be +** at most one effective restoreCursorPosition() call after each +** saveCursorPosition(). +** +** If the second argument argument - doSeek - is false, then instead of +** returning the cursor to it's saved position, any saved position is deleted +** and the cursor state set to CURSOR_INVALID. +*/ +static int restoreCursorPosition(BtCursor *pCur, int doSeek){ + int rc = SQLITE_OK; + if( pCur->eState==CURSOR_REQUIRESEEK ){ + assert( sqlite3ThreadData()->useSharedData ); + if( doSeek ){ + rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip); + }else{ + pCur->eState = CURSOR_INVALID; + } + if( rc==SQLITE_OK ){ + sqliteFree(pCur->pKey); + pCur->pKey = 0; + assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState ); + } + } + return rc; +} + +/* +** Query to see if btree handle p may obtain a lock of type eLock +** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return +** SQLITE_OK if the lock may be obtained (by calling lockTable()), or +** SQLITE_LOCKED if not. +*/ +static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){ + BtShared *pBt = p->pBt; + BtLock *pIter; + + /* This is a no-op if the shared-cache is not enabled */ + if( 0==sqlite3ThreadData()->useSharedData ){ + return SQLITE_OK; + } + + /* This (along with lockTable()) is where the ReadUncommitted flag is + ** dealt with. If the caller is querying for a read-lock and the flag is + ** set, it is unconditionally granted - even if there are write-locks + ** on the table. If a write-lock is requested, the ReadUncommitted flag + ** is not considered. + ** + ** In function lockTable(), if a read-lock is demanded and the + ** ReadUncommitted flag is set, no entry is added to the locks list + ** (BtShared.pLock). + ** + ** To summarize: If the ReadUncommitted flag is set, then read cursors do + ** not create or respect table locks. The locking procedure for a + ** write-cursor does not change. + */ + if( + !p->pSqlite || + 0==(p->pSqlite->flags&SQLITE_ReadUncommitted) || + eLock==WRITE_LOCK || + iTab==MASTER_ROOT + ){ + for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ + if( pIter->pBtree!=p && pIter->iTable==iTab && + (pIter->eLock!=eLock || eLock!=READ_LOCK) ){ + return SQLITE_LOCKED; + } + } + } + return SQLITE_OK; +} + +/* +** Add a lock on the table with root-page iTable to the shared-btree used +** by Btree handle p. Parameter eLock must be either READ_LOCK or +** WRITE_LOCK. +** +** SQLITE_OK is returned if the lock is added successfully. SQLITE_BUSY and +** SQLITE_NOMEM may also be returned. +*/ +static int lockTable(Btree *p, Pgno iTable, u8 eLock){ + BtShared *pBt = p->pBt; + BtLock *pLock = 0; + BtLock *pIter; + + /* This is a no-op if the shared-cache is not enabled */ + if( 0==sqlite3ThreadData()->useSharedData ){ + return SQLITE_OK; + } + + assert( SQLITE_OK==queryTableLock(p, iTable, eLock) ); + + /* If the read-uncommitted flag is set and a read-lock is requested, + ** return early without adding an entry to the BtShared.pLock list. See + ** comment in function queryTableLock() for more info on handling + ** the ReadUncommitted flag. + */ + if( + (p->pSqlite) && + (p->pSqlite->flags&SQLITE_ReadUncommitted) && + (eLock==READ_LOCK) && + iTable!=MASTER_ROOT + ){ + return SQLITE_OK; + } + + /* First search the list for an existing lock on this table. */ + for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){ + if( pIter->iTable==iTable && pIter->pBtree==p ){ + pLock = pIter; + break; + } + } + + /* If the above search did not find a BtLock struct associating Btree p + ** with table iTable, allocate one and link it into the list. + */ + if( !pLock ){ + pLock = (BtLock *)sqliteMalloc(sizeof(BtLock)); + if( !pLock ){ + return SQLITE_NOMEM; + } + pLock->iTable = iTable; + pLock->pBtree = p; + pLock->pNext = pBt->pLock; + pBt->pLock = pLock; + } + + /* Set the BtLock.eLock variable to the maximum of the current lock + ** and the requested lock. This means if a write-lock was already held + ** and a read-lock requested, we don't incorrectly downgrade the lock. + */ + assert( WRITE_LOCK>READ_LOCK ); + if( eLock>pLock->eLock ){ + pLock->eLock = eLock; + } + + return SQLITE_OK; +} + +/* +** Release all the table locks (locks obtained via calls to the lockTable() +** procedure) held by Btree handle p. +*/ +static void unlockAllTables(Btree *p){ + BtLock **ppIter = &p->pBt->pLock; + + /* If the shared-cache extension is not enabled, there should be no + ** locks in the BtShared.pLock list, making this procedure a no-op. Assert + ** that this is the case. + */ + assert( sqlite3ThreadData()->useSharedData || 0==*ppIter ); + + while( *ppIter ){ + BtLock *pLock = *ppIter; + if( pLock->pBtree==p ){ + *ppIter = pLock->pNext; + sqliteFree(pLock); + }else{ + ppIter = &pLock->pNext; + } + } +} +#endif /* SQLITE_OMIT_SHARED_CACHE */ + #ifndef SQLITE_OMIT_AUTOVACUUM /* ** These macros define the location of the pointer-map entry for a ** database page. The first argument to each is the number of usable ** bytes on each page of the database (often 1024). The second is the @@ -484,11 +799,11 @@ ** ** This routine updates the pointer map entry for page number 'key' ** so that it maps to type 'eType' and parent page number 'pgno'. ** An error code is returned if something goes wrong, otherwise SQLITE_OK. */ -static int ptrmapPut(Btree *pBt, Pgno key, u8 eType, Pgno parent){ +static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){ u8 *pPtrmap; /* The pointer map page */ Pgno iPtrmap; /* The pointer map page number */ int offset; /* Offset in pointer map page */ int rc; @@ -521,11 +836,11 @@ ** ** This routine retrieves the pointer map entry for page 'key', writing ** the type and parent page number to *pEType and *pPgno respectively. ** An error code is returned if something goes wrong, otherwise SQLITE_OK. */ -static int ptrmapGet(Btree *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ +static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){ int iPtrmap; /* Pointer map page index */ u8 *pPtrmap; /* Pointer map page data */ int offset; /* Offset of entry in pointer map */ int rc; @@ -788,14 +1103,24 @@ #define pageIntegrity(X) _pageIntegrity(X) #else # define pageIntegrity(X) #endif +/* A bunch of assert() statements to check the transaction state variables +** of handle p (type Btree*) are internally consistent. +*/ +#define btreeIntegrity(p) \ + assert( p->inTrans!=TRANS_NONE || p->pBt->nTransactionpBt->nRef ); \ + assert( p->pBt->nTransaction<=p->pBt->nRef ); \ + assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \ + assert( p->pBt->inTransaction>=p->inTrans ); + /* ** Defragment the page given. All Cells are moved to the -** beginning of the page and all free space is collected -** into one big FreeBlk at the end of the page. +** end of the page and all free space is collected into one +** big FreeBlk that occurs in between the header and cell +** pointer array and the cell content area. */ static int defragmentPage(MemPage *pPage){ int i; /* Loop counter */ int pc; /* Address of a i-th cell */ int addr; /* Offset of first byte after cell pointer array */ @@ -975,11 +1300,11 @@ /* ** Decode the flags byte (the first byte of the header) for a page ** and initialize fields of the MemPage structure accordingly. */ static void decodeFlags(MemPage *pPage, int flagByte){ - Btree *pBt; /* A copy of pPage->pBt */ + BtShared *pBt; /* A copy of pPage->pBt */ assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) ); pPage->intKey = (flagByte & (PTF_INTKEY|PTF_LEAFDATA))!=0; pPage->zeroData = (flagByte & PTF_ZERODATA)!=0; pPage->leaf = (flagByte & PTF_LEAF)!=0; @@ -1015,11 +1340,11 @@ MemPage *pParent /* The parent. Might be NULL */ ){ int pc; /* Address of a freeblock within pPage->aData[] */ int hdr; /* Offset to beginning of page header */ u8 *data; /* Equal to pPage->aData */ - Btree *pBt; /* The main btree structure */ + BtShared *pBt; /* The main btree structure */ int usableSize; /* Amount of usable space on each page */ int cellOffset; /* Offset from start of page to first cell pointer */ int nFree; /* Number of unused bytes on the page */ int top; /* First byte of the cell content area */ @@ -1088,11 +1413,11 @@ ** Set up a raw page so that it looks like a database page holding ** no entries. */ static void zeroPage(MemPage *pPage, int flags){ unsigned char *data = pPage->aData; - Btree *pBt = pPage->pBt; + BtShared *pBt = pPage->pBt; int hdr = pPage->hdrOffset; int first; assert( sqlite3pager_pagenumber(data)==pPage->pgno ); assert( &data[pBt->pageSize] == (unsigned char*)pPage ); @@ -1116,11 +1441,11 @@ /* ** Get a page from the pager. Initialize the MemPage.pBt and ** MemPage.aData elements if needed. */ -static int getPage(Btree *pBt, Pgno pgno, MemPage **ppPage){ +static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage){ int rc; unsigned char *aData; MemPage *pPage; rc = sqlite3pager_get(pBt->pPager, pgno, (void**)&aData); if( rc ) return rc; @@ -1137,11 +1462,11 @@ ** Get a page from the pager and initialize it. This routine ** is just a convenience wrapper around separate calls to ** getPage() and initPage(). */ static int getAndInitPage( - Btree *pBt, /* The database file */ + BtShared *pBt, /* The database file */ Pgno pgno, /* Number of the page to get */ MemPage **ppPage, /* Write the page pointer here */ MemPage *pParent /* Parent of the page */ ){ int rc; @@ -1210,17 +1535,63 @@ ** a new database with a random name is created. This randomly named ** database file will be deleted when sqlite3BtreeClose() is called. */ int sqlite3BtreeOpen( const char *zFilename, /* Name of the file containing the BTree database */ + sqlite3 *pSqlite, /* Associated database handle */ Btree **ppBtree, /* Pointer to new Btree object written here */ int flags /* Options */ ){ - Btree *pBt; + BtShared *pBt; /* Shared part of btree structure */ + Btree *p; /* Handle to return */ int rc; int nReserve; unsigned char zDbHeader[100]; +#ifndef SQLITE_OMIT_SHARED_CACHE + ThreadData *pTsd = sqlite3ThreadData(); +#endif + + /* Set the variable isMemdb to true for an in-memory database, or + ** false for a file-based database. This symbol is only required if + ** either of the shared-data or autovacuum features are compiled + ** into the library. + */ +#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM) + #ifdef SQLITE_OMIT_MEMORYDB + const int isMemdb = !zFilename; + #else + const int isMemdb = !zFilename || (strcmp(zFilename, ":memory:")?0:1); + #endif +#endif + + p = sqliteMalloc(sizeof(Btree)); + if( !p ){ + return SQLITE_NOMEM; + } + p->inTrans = TRANS_NONE; + p->pSqlite = pSqlite; + + /* Try to find an existing Btree structure opened on zFilename. */ +#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO) + if( pTsd->useSharedData && zFilename && !isMemdb ){ + char *zFullPathname = sqlite3OsFullPathname(zFilename); + if( !zFullPathname ){ + sqliteFree(p); + return SQLITE_NOMEM; + } + for(pBt=pTsd->pBtree; pBt; pBt=pBt->pNext){ + if( 0==strcmp(zFullPathname, sqlite3pager_filename(pBt->pPager)) ){ + p->pBt = pBt; + *ppBtree = p; + pBt->nRef++; + sqliteFree(zFullPathname); + return SQLITE_OK; + } + } + sqliteFree(zFullPathname); + } +#endif /* ** The following asserts make sure that structures used by the btree are ** the right size. This is to guard against size changes that result ** when compiling on a different architecture. @@ -1232,19 +1603,23 @@ assert( sizeof(Pgno)==4 ); pBt = sqliteMalloc( sizeof(*pBt) ); if( pBt==0 ){ *ppBtree = 0; + sqliteFree(p); return SQLITE_NOMEM; } rc = sqlite3pager_open(&pBt->pPager, zFilename, EXTRA_SIZE, flags); if( rc!=SQLITE_OK ){ if( pBt->pPager ) sqlite3pager_close(pBt->pPager); sqliteFree(pBt); + sqliteFree(p); *ppBtree = 0; return rc; } + p->pBt = pBt; + sqlite3pager_set_destructor(pBt->pPager, pageDestructor); sqlite3pager_set_reiniter(pBt->pPager, pageReinit); pBt->pCursor = 0; pBt->pPage1 = 0; pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager); @@ -1261,15 +1636,11 @@ ** do not set the auto-vacuum flag, even if SQLITE_DEFAULT_AUTOVACUUM ** is true. On the other hand, if SQLITE_OMIT_MEMORYDB has been defined, ** then ":memory:" is just a regular file-name. Respect the auto-vacuum ** default in this case. */ -#ifndef SQLITE_OMIT_MEMORYDB - if( zFilename && strcmp(zFilename,":memory:") ){ -#else - if( zFilename ){ -#endif + if( zFilename && !isMemdb ){ pBt->autoVacuum = SQLITE_DEFAULT_AUTOVACUUM; } #endif nReserve = 0; }else{ @@ -1283,30 +1654,88 @@ #endif } pBt->usableSize = pBt->pageSize - nReserve; assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */ sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize); - *ppBtree = pBt; + +#ifndef SQLITE_OMIT_SHARED_CACHE + /* Add the new btree to the linked list starting at ThreadData.pBtree */ + if( pTsd->useSharedData && zFilename && !isMemdb ){ + pBt->pNext = pTsd->pBtree; + pTsd->pBtree = pBt; + } +#endif + pBt->nRef = 1; + *ppBtree = p; return SQLITE_OK; } /* ** Close an open database and invalidate all cursors. */ -int sqlite3BtreeClose(Btree *pBt){ - while( pBt->pCursor ){ - sqlite3BtreeCloseCursor(pBt->pCursor); +int sqlite3BtreeClose(Btree *p){ + BtShared *pBt = p->pBt; + BtCursor *pCur; + +#ifndef SQLITE_OMIT_SHARED_CACHE + ThreadData *pTsd = sqlite3ThreadData(); +#endif + + /* Drop any table-locks */ + unlockAllTables(p); + + /* Close all cursors opened via this handle. */ + pCur = pBt->pCursor; + while( pCur ){ + BtCursor *pTmp = pCur; + pCur = pCur->pNext; + if( pTmp->pBtree==p ){ + sqlite3BtreeCloseCursor(pTmp); + } } + + sqliteFree(p); + +#ifndef SQLITE_OMIT_SHARED_CACHE + /* If there are still other outstanding references to the shared-btree + ** structure, return now. The remainder of this procedure cleans + ** up the shared-btree. + */ + assert( pBt->nRef>0 ); + pBt->nRef--; + if( pBt->nRef ){ + return SQLITE_OK; + } + + /* Remove the shared-btree from the thread wide list */ + if( pTsd->pBtree==pBt ){ + pTsd->pBtree = pBt->pNext; + }else{ + BtShared *pPrev; + for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext); + if( pPrev ){ + pPrev->pNext = pBt->pNext; + } + } +#endif + + /* Close the pager and free the shared-btree structure */ + assert( !pBt->pCursor ); sqlite3pager_close(pBt->pPager); + if( pBt->xFreeSchema && pBt->pSchema ){ + pBt->xFreeSchema(pBt->pSchema); + } + sqliteFree(pBt->pSchema); sqliteFree(pBt); return SQLITE_OK; } /* ** Change the busy handler callback function. */ -int sqlite3BtreeSetBusyHandler(Btree *pBt, BusyHandler *pHandler){ +int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){ + BtShared *pBt = p->pBt; pBt->pBusyHandler = pHandler; sqlite3pager_set_busyhandler(pBt->pPager, pHandler); return SQLITE_OK; } @@ -1323,11 +1752,12 @@ ** an abrupt power failure when synchronous is off, the database ** could be left in an inconsistent and unrecoverable state. ** Synchronous is on by default so database corruption is not ** normally a worry. */ -int sqlite3BtreeSetCacheSize(Btree *pBt, int mxPage){ +int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){ + BtShared *pBt = p->pBt; sqlite3pager_set_cachesize(pBt->pPager, mxPage); return SQLITE_OK; } /* @@ -1337,21 +1767,23 @@ ** there is a high probability of damage) Level 2 is the default. There ** is a very low but non-zero probability of damage. Level 3 reduces the ** probability of damage to near zero but with a write performance reduction. */ #ifndef SQLITE_OMIT_PAGER_PRAGMAS -int sqlite3BtreeSetSafetyLevel(Btree *pBt, int level){ +int sqlite3BtreeSetSafetyLevel(Btree *p, int level){ + BtShared *pBt = p->pBt; sqlite3pager_set_safety_level(pBt->pPager, level); return SQLITE_OK; } #endif /* ** Return TRUE if the given btree is set to safety level 1. In other ** words, return TRUE if no sync() occurs on the disk files. */ -int sqlite3BtreeSyncDisabled(Btree *pBt){ +int sqlite3BtreeSyncDisabled(Btree *p){ + BtShared *pBt = p->pBt; assert( pBt && pBt->pPager ); return sqlite3pager_nosync(pBt->pPager); } #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) @@ -1368,44 +1800,47 @@ ** at the beginning of a page. ** ** If parameter nReserve is less than zero, then the number of reserved ** bytes per page is left unchanged. */ -int sqlite3BtreeSetPageSize(Btree *pBt, int pageSize, int nReserve){ +int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){ + BtShared *pBt = p->pBt; if( pBt->pageSizeFixed ){ return SQLITE_READONLY; } if( nReserve<0 ){ nReserve = pBt->pageSize - pBt->usableSize; } if( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE && ((pageSize-1)&pageSize)==0 ){ assert( (pageSize & 7)==0 ); + assert( !pBt->pPage1 && !pBt->pCursor ); pBt->pageSize = sqlite3pager_set_pagesize(pBt->pPager, pageSize); } pBt->usableSize = pBt->pageSize - nReserve; return SQLITE_OK; } /* ** Return the currently defined page size */ -int sqlite3BtreeGetPageSize(Btree *pBt){ - return pBt->pageSize; +int sqlite3BtreeGetPageSize(Btree *p){ + return p->pBt->pageSize; } -int sqlite3BtreeGetReserve(Btree *pBt){ - return pBt->pageSize - pBt->usableSize; +int sqlite3BtreeGetReserve(Btree *p){ + return p->pBt->pageSize - p->pBt->usableSize; } #endif /* !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM) */ /* ** Change the 'auto-vacuum' property of the database. If the 'autoVacuum' ** parameter is non-zero, then auto-vacuum mode is enabled. If zero, it ** is disabled. The default value for the auto-vacuum property is ** determined by the SQLITE_DEFAULT_AUTOVACUUM macro. */ -int sqlite3BtreeSetAutoVacuum(Btree *pBt, int autoVacuum){ +int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){ + BtShared *pBt = p->pBt;; #ifdef SQLITE_OMIT_AUTOVACUUM return SQLITE_READONLY; #else if( pBt->pageSizeFixed ){ return SQLITE_READONLY; @@ -1417,15 +1852,15 @@ /* ** Return the value of the 'auto-vacuum' property. If auto-vacuum is ** enabled 1 is returned. Otherwise 0. */ -int sqlite3BtreeGetAutoVacuum(Btree *pBt){ +int sqlite3BtreeGetAutoVacuum(Btree *p){ #ifdef SQLITE_OMIT_AUTOVACUUM return 0; #else - return pBt->autoVacuum; + return p->pBt->autoVacuum; #endif } /* @@ -1436,11 +1871,11 @@ ** well-formed database file, then SQLITE_CORRUPT is returned. ** SQLITE_BUSY is returned if the database is locked. SQLITE_NOMEM ** is returned if we run out of memory. SQLITE_PROTOCOL is returned ** if there is a locking protocol violation. */ -static int lockBtree(Btree *pBt){ +static int lockBtree(BtShared *pBt){ int rc, pageSize; MemPage *pPage1; if( pBt->pPage1 ) return SQLITE_OK; rc = getPage(pBt, 1, &pPage1); if( rc!=SQLITE_OK ) return rc; @@ -1508,15 +1943,22 @@ /* ** This routine works like lockBtree() except that it also invokes the ** busy callback if there is lock contention. */ -static int lockBtreeWithRetry(Btree *pBt){ +static int lockBtreeWithRetry(Btree *pRef){ int rc = SQLITE_OK; - if( pBt->inTrans==TRANS_NONE ){ - rc = sqlite3BtreeBeginTrans(pBt, 0); - pBt->inTrans = TRANS_NONE; + if( pRef->inTrans==TRANS_NONE ){ + u8 inTransaction = pRef->pBt->inTransaction; + btreeIntegrity(pRef); + rc = sqlite3BtreeBeginTrans(pRef, 0); + pRef->pBt->inTransaction = inTransaction; + pRef->inTrans = TRANS_NONE; + if( rc==SQLITE_OK ){ + pRef->pBt->nTransaction--; + } + btreeIntegrity(pRef); } return rc; } @@ -1528,15 +1970,15 @@ ** ** If there are any outstanding cursors, this routine is a no-op. ** ** If there is a transaction in progress, this routine is a no-op. */ -static void unlockBtreeIfUnused(Btree *pBt){ - if( pBt->inTrans==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){ +static void unlockBtreeIfUnused(BtShared *pBt){ + if( pBt->inTransaction==TRANS_NONE && pBt->pCursor==0 && pBt->pPage1!=0 ){ if( pBt->pPage1->aData==0 ){ MemPage *pPage = pBt->pPage1; - pPage->aData = &((char*)pPage)[-pBt->pageSize]; + pPage->aData = &((u8*)pPage)[-pBt->pageSize]; pPage->pBt = pBt; pPage->pgno = 1; } releasePage(pBt->pPage1); pBt->pPage1 = 0; @@ -1546,11 +1988,11 @@ /* ** Create a new database by initializing the first page of the ** file. */ -static int newDatabase(Btree *pBt){ +static int newDatabase(BtShared *pBt){ MemPage *pP1; unsigned char *data; int rc; if( sqlite3pager_pagecount(pBt->pPager)>0 ) return SQLITE_OK; pP1 = pBt->pPage1; @@ -1611,25 +2053,36 @@ ** One or the other of the two processes must give way or there can be ** no progress. By returning SQLITE_BUSY and not invoking the busy callback ** when A already has a read lock, we encourage A to give up and let B ** proceed. */ -int sqlite3BtreeBeginTrans(Btree *pBt, int wrflag){ +int sqlite3BtreeBeginTrans(Btree *p, int wrflag){ + BtShared *pBt = p->pBt; int rc = SQLITE_OK; + + btreeIntegrity(p); /* If the btree is already in a write-transaction, or it ** is already in a read-transaction and a read-transaction ** is requested, this is a no-op. */ - if( pBt->inTrans==TRANS_WRITE || (pBt->inTrans==TRANS_READ && !wrflag) ){ + if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){ return SQLITE_OK; } /* Write transactions are not possible on a read-only database */ if( pBt->readOnly && wrflag ){ return SQLITE_READONLY; } + + /* If another database handle has already opened a write transaction + ** on this shared-btree structure and a second write transaction is + ** requested, return SQLITE_BUSY. + */ + if( pBt->inTransaction==TRANS_WRITE && wrflag ){ + return SQLITE_BUSY; + } do { if( pBt->pPage1==0 ){ rc = lockBtree(pBt); } @@ -1640,17 +2093,28 @@ rc = newDatabase(pBt); } } if( rc==SQLITE_OK ){ - pBt->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); if( wrflag ) pBt->inStmt = 0; }else{ unlockBtreeIfUnused(pBt); } - }while( rc==SQLITE_BUSY && pBt->inTrans==TRANS_NONE && + }while( rc==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE && sqlite3InvokeBusyHandler(pBt->pBusyHandler) ); + + if( rc==SQLITE_OK ){ + if( p->inTrans==TRANS_NONE ){ + pBt->nTransaction++; + } + p->inTrans = (wrflag?TRANS_WRITE:TRANS_READ); + if( p->inTrans>pBt->inTransaction ){ + pBt->inTransaction = p->inTrans; + } + } + + btreeIntegrity(p); return rc; } #ifndef SQLITE_OMIT_AUTOVACUUM @@ -1661,11 +2125,11 @@ */ static int setChildPtrmaps(MemPage *pPage){ int i; /* Counter variable */ int nCell; /* Number of cells in page pPage */ int rc = SQLITE_OK; /* Return code */ - Btree *pBt = pPage->pBt; + BtShared *pBt = pPage->pBt; int isInitOrig = pPage->isInit; Pgno pgno = pPage->pgno; initPage(pPage, 0); nCell = pPage->nCell; @@ -1761,11 +2225,11 @@ /* ** Move the open database page pDbPage to location iFreePage in the ** database. The pDbPage reference remains valid. */ static int relocatePage( - Btree *pBt, /* Btree */ + BtShared *pBt, /* Btree */ MemPage *pDbPage, /* Open page to move */ u8 eType, /* Pointer map 'type' entry for pDbPage */ Pgno iPtrPage, /* Pointer map 'page-no' entry for pDbPage */ Pgno iFreePage /* The location to move pDbPage to */ ){ @@ -1831,23 +2295,23 @@ } return rc; } /* Forward declaration required by autoVacuumCommit(). */ -static int allocatePage(Btree *, MemPage **, Pgno *, Pgno, u8); +static int allocatePage(BtShared *, MemPage **, Pgno *, Pgno, u8); /* ** This routine is called prior to sqlite3pager_commit when a transaction ** is commited for an auto-vacuum database. */ -static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){ +static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){ Pager *pPager = pBt->pPager; - Pgno nFreeList; /* Number of pages remaining on the free-list. */ - int nPtrMap; /* Number of pointer-map pages deallocated */ - Pgno origSize; /* Pages in the database file */ - Pgno finSize; /* Pages in the database file after truncation */ - int rc; /* Return code */ + Pgno nFreeList; /* Number of pages remaining on the free-list. */ + int nPtrMap; /* Number of pointer-map pages deallocated */ + Pgno origSize; /* Pages in the database file */ + Pgno finSize; /* Pages in the database file after truncation */ + int rc; /* Return code */ u8 eType; int pgsz = pBt->pageSize; /* Page size for this database */ Pgno iDbPage; /* The database page to move */ MemPage *pDbMemPage = 0; /* "" */ Pgno iPtrPage; /* The page that contains a pointer to iDbPage */ @@ -1926,10 +2390,16 @@ assert( iFreePage<=origSize ); }while( iFreePage>finSize ); releasePage(pFreeMemPage); pFreeMemPage = 0; + /* Relocate the page into the body of the file. Note that although the + ** page has moved within the database file, the pDbMemPage pointer + ** remains valid. This means that this function can run without + ** invalidating cursors open on the btree. This is important in + ** shared-cache mode. + */ rc = relocatePage(pBt, pDbMemPage, eType, iPtrPage, iFreePage); releasePage(pDbMemPage); if( rc!=SQLITE_OK ) goto autovacuum_out; } @@ -1957,50 +2427,80 @@ ** Commit the transaction currently in progress. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ -int sqlite3BtreeCommit(Btree *pBt){ +int sqlite3BtreeCommit(Btree *p){ int rc = SQLITE_OK; - if( pBt->inTrans==TRANS_WRITE ){ + BtShared *pBt = p->pBt; + + btreeIntegrity(p); + unlockAllTables(p); + + /* If the handle has a write-transaction open, commit the shared-btrees + ** transaction and set the shared state to TRANS_READ. + */ + if( p->inTrans==TRANS_WRITE ){ + assert( pBt->inTransaction==TRANS_WRITE ); + assert( pBt->nTransaction>0 ); rc = sqlite3pager_commit(pBt->pPager); + pBt->inTransaction = TRANS_READ; + pBt->inStmt = 0; } - pBt->inTrans = TRANS_NONE; - pBt->inStmt = 0; + + /* If the handle has any kind of transaction open, decrement the transaction + ** count of the shared btree. If the transaction count reaches 0, set + ** the shared state to TRANS_NONE. The unlockBtreeIfUnused() call below + ** will unlock the pager. + */ + if( p->inTrans!=TRANS_NONE ){ + pBt->nTransaction--; + if( 0==pBt->nTransaction ){ + pBt->inTransaction = TRANS_NONE; + } + } + + /* Set the handles current transaction state to TRANS_NONE and unlock + ** the pager if this call closed the only read or write transaction. + */ + p->inTrans = TRANS_NONE; unlockBtreeIfUnused(pBt); + + btreeIntegrity(p); return rc; } #ifndef NDEBUG /* ** Return the number of write-cursors open on this handle. This is for use ** in assert() expressions, so it is only compiled if NDEBUG is not ** defined. */ -static int countWriteCursors(Btree *pBt){ +static int countWriteCursors(BtShared *pBt){ BtCursor *pCur; int r = 0; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ - if( pCur->wrFlag ) r++; + if( pCur->wrFlag ) r++; } return r; } #endif #ifdef SQLITE_TEST /* ** Print debugging information about all cursors to standard output. */ -void sqlite3BtreeCursorList(Btree *pBt){ +void sqlite3BtreeCursorList(Btree *p){ BtCursor *pCur; + BtShared *pBt = p->pBt; for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ MemPage *pPage = pCur->pPage; char *zMode = pCur->wrFlag ? "rw" : "ro"; sqlite3DebugPrintf("CURSOR %p rooted at %4d(%s) currently at %d.%d%s\n", pCur, pCur->pgnoRoot, zMode, pPage ? pPage->pgno : 0, pCur->idx, - pCur->isValid ? "" : " eof" + (pCur->eState==CURSOR_VALID) ? "" : " eof" ); } } #endif @@ -2011,26 +2511,45 @@ ** in an error. ** ** This will release the write lock on the database file. If there ** are no active cursors, it also releases the read lock. */ -int sqlite3BtreeRollback(Btree *pBt){ +int sqlite3BtreeRollback(Btree *p){ int rc = SQLITE_OK; + BtShared *pBt = p->pBt; MemPage *pPage1; - if( pBt->inTrans==TRANS_WRITE ){ + + btreeIntegrity(p); + unlockAllTables(p); + + if( p->inTrans==TRANS_WRITE ){ + assert( TRANS_WRITE==pBt->inTransaction ); + rc = sqlite3pager_rollback(pBt->pPager); /* The rollback may have destroyed the pPage1->aData value. So ** call getPage() on page 1 again to make sure pPage1->aData is ** set correctly. */ if( getPage(pBt, 1, &pPage1)==SQLITE_OK ){ releasePage(pPage1); } assert( countWriteCursors(pBt)==0 ); + pBt->inTransaction = TRANS_READ; } - pBt->inTrans = TRANS_NONE; + + if( p->inTrans!=TRANS_NONE ){ + assert( pBt->nTransaction>0 ); + pBt->nTransaction--; + if( 0==pBt->nTransaction ){ + pBt->inTransaction = TRANS_NONE; + } + } + + p->inTrans = TRANS_NONE; pBt->inStmt = 0; unlockBtreeIfUnused(pBt); + + btreeIntegrity(p); return rc; } /* ** Start a statement subtransaction. The subtransaction can @@ -2045,15 +2564,17 @@ ** Statement subtransactions are used around individual SQL statements ** that are contained within a BEGIN...COMMIT block. If a constraint ** error occurs within the statement, the effect of that one statement ** can be rolled back without having to rollback the entire transaction. */ -int sqlite3BtreeBeginStmt(Btree *pBt){ +int sqlite3BtreeBeginStmt(Btree *p){ int rc; - if( (pBt->inTrans!=TRANS_WRITE) || pBt->inStmt ){ + BtShared *pBt = p->pBt; + if( (p->inTrans!=TRANS_WRITE) || pBt->inStmt ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } + assert( pBt->inTransaction==TRANS_WRITE ); rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_stmt_begin(pBt->pPager); pBt->inStmt = 1; return rc; } @@ -2060,12 +2581,13 @@ /* ** Commit the statment subtransaction currently in progress. If no ** subtransaction is active, this is a no-op. */ -int sqlite3BtreeCommitStmt(Btree *pBt){ +int sqlite3BtreeCommitStmt(Btree *p){ int rc; + BtShared *pBt = p->pBt; if( pBt->inStmt && !pBt->readOnly ){ rc = sqlite3pager_stmt_commit(pBt->pPager); }else{ rc = SQLITE_OK; } @@ -2079,12 +2601,13 @@ ** ** All cursors will be invalidated by this operation. Any attempt ** to use a cursor that was open at the beginning of this operation ** will result in an error. */ -int sqlite3BtreeRollbackStmt(Btree *pBt){ +int sqlite3BtreeRollbackStmt(Btree *p){ int rc; + BtShared *pBt = p->pBt; if( pBt->inStmt==0 || pBt->readOnly ) return SQLITE_OK; rc = sqlite3pager_stmt_rollback(pBt->pPager); assert( countWriteCursors(pBt)==0 ); pBt->inStmt = 0; return rc; @@ -2148,19 +2671,20 @@ ** in incorrect operations. If the comparison function is NULL, a ** default comparison function is used. The comparison function is ** always ignored for INTKEY tables. */ int sqlite3BtreeCursor( - Btree *pBt, /* The btree */ + Btree *p, /* The btree */ int iTable, /* Root page of table to open */ int wrFlag, /* 1 to write. 0 read-only */ int (*xCmp)(void*,int,const void*,int,const void*), /* Key Comparison func */ void *pArg, /* First arg to xCompare() */ BtCursor **ppCur /* Write new cursor here */ ){ int rc; BtCursor *pCur; + BtShared *pBt = p->pBt; *ppCur = 0; if( wrFlag ){ if( pBt->readOnly ){ return SQLITE_READONLY; @@ -2167,17 +2691,18 @@ } if( checkReadLocks(pBt, iTable, 0) ){ return SQLITE_LOCKED; } } + if( pBt->pPage1==0 ){ - rc = lockBtreeWithRetry(pBt); + rc = lockBtreeWithRetry(p); if( rc!=SQLITE_OK ){ return rc; } } - pCur = sqliteMallocRaw( sizeof(*pCur) ); + pCur = sqliteMalloc( sizeof(*pCur) ); if( pCur==0 ){ rc = SQLITE_NOMEM; goto create_cursor_exception; } pCur->pgnoRoot = (Pgno)iTable; @@ -2188,26 +2713,31 @@ } rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->pPage, 0); if( rc!=SQLITE_OK ){ goto create_cursor_exception; } + + /* Now that no other errors can occur, finish filling in the BtCursor + ** variables, link the cursor into the BtShared list and set *ppCur (the + ** output argument to this function). + */ pCur->xCompare = xCmp ? xCmp : dfltCompare; pCur->pArg = pArg; - pCur->pBt = pBt; + pCur->pBtree = p; pCur->wrFlag = wrFlag; pCur->idx = 0; memset(&pCur->info, 0, sizeof(pCur->info)); pCur->pNext = pBt->pCursor; if( pCur->pNext ){ pCur->pNext->pPrev = pCur; } pCur->pPrev = 0; pBt->pCursor = pCur; - pCur->isValid = 0; + pCur->eState = CURSOR_INVALID; *ppCur = pCur; + return SQLITE_OK; - create_cursor_exception: if( pCur ){ releasePage(pCur->pPage); sqliteFree(pCur); } @@ -2232,11 +2762,12 @@ /* ** Close a cursor. The read lock on the database file is released ** when the last cursor is closed. */ int sqlite3BtreeCloseCursor(BtCursor *pCur){ - Btree *pBt = pCur->pBt; + BtShared *pBt = pCur->pBtree->pBt; + restoreCursorPosition(pCur, 0); if( pCur->pPrev ){ pCur->pPrev->pNext = pCur->pNext; }else{ pBt->pCursor = pCur->pNext; } @@ -2299,17 +2830,21 @@ ** ** For a table with the INTKEY flag set, this routine returns the key ** itself, not the number of bytes in the key. */ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){ - if( !pCur->isValid ){ - *pSize = 0; - }else{ - getCellInfo(pCur); - *pSize = pCur->info.nKey; + int rc = restoreCursorPosition(pCur, 1); + if( rc==SQLITE_OK ){ + assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); + if( pCur->eState==CURSOR_INVALID ){ + *pSize = 0; + }else{ + getCellInfo(pCur); + *pSize = pCur->info.nKey; + } } - return SQLITE_OK; + return rc; } /* ** Set *pSize to the number of bytes of data in the entry the ** cursor currently points to. Always return SQLITE_OK. @@ -2316,18 +2851,22 @@ ** Failure is not possible. If the cursor is not currently ** pointing to an entry (which can happen, for example, if ** the database is empty) then *pSize is set to 0. */ int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){ - if( !pCur->isValid ){ - /* Not pointing at a valid entry - set *pSize to 0. */ - *pSize = 0; - }else{ - getCellInfo(pCur); - *pSize = pCur->info.nData; - } - return SQLITE_OK; + int rc = restoreCursorPosition(pCur, 1); + if( rc==SQLITE_OK ){ + assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID ); + if( pCur->eState==CURSOR_INVALID ){ + /* Not pointing at a valid entry - set *pSize to 0. */ + *pSize = 0; + }else{ + getCellInfo(pCur); + *pSize = pCur->info.nData; + } + } + return rc; } /* ** Read payload information from the entry that the pCur cursor is ** pointing to. Begin reading the payload at "offset" and read @@ -2346,17 +2885,17 @@ ){ unsigned char *aPayload; Pgno nextPage; int rc; MemPage *pPage; - Btree *pBt; + BtShared *pBt; int ovflSize; u32 nKey; assert( pCur!=0 && pCur->pPage!=0 ); - assert( pCur->isValid ); - pBt = pCur->pBt; + assert( pCur->eState==CURSOR_VALID ); + pBt = pCur->pBtree->pBt; pPage = pCur->pPage; pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idxnCell ); getCellInfo(pCur); aPayload = pCur->info.pCell; @@ -2427,18 +2966,22 @@ ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ - assert( pCur->isValid ); - assert( pCur->pPage!=0 ); - if( pCur->pPage->intKey ){ - return SQLITE_CORRUPT_BKPT; - } - assert( pCur->pPage->intKey==0 ); - assert( pCur->idx>=0 && pCur->idxpPage->nCell ); - return getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); + int rc = restoreCursorPosition(pCur, 1); + if( rc==SQLITE_OK ){ + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->pPage!=0 ); + if( pCur->pPage->intKey ){ + return SQLITE_CORRUPT_BKPT; + } + assert( pCur->pPage->intKey==0 ); + assert( pCur->idx>=0 && pCur->idxpPage->nCell ); + rc = getPayload(pCur, offset, amt, (unsigned char*)pBuf, 0); + } + return rc; } /* ** Read part of the data associated with cursor pCur. Exactly ** "amt" bytes will be transfered into pBuf[]. The transfer @@ -2447,14 +2990,18 @@ ** Return SQLITE_OK on success or an error code if anything goes ** wrong. An error is returned if "offset+amt" is larger than ** the available payload. */ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){ - assert( pCur->isValid ); - assert( pCur->pPage!=0 ); - assert( pCur->idx>=0 && pCur->idxpPage->nCell ); - return getPayload(pCur, offset, amt, pBuf, 1); + int rc = restoreCursorPosition(pCur, 1); + if( rc==SQLITE_OK ){ + assert( pCur->eState==CURSOR_VALID ); + assert( pCur->pPage!=0 ); + assert( pCur->idx>=0 && pCur->idxpPage->nCell ); + rc = getPayload(pCur, offset, amt, pBuf, 1); + } + return rc; } /* ** Return a pointer to payload information from the entry that the ** pCur cursor is pointing to. The pointer is to the beginning of @@ -2483,11 +3030,11 @@ MemPage *pPage; u32 nKey; int nLocal; assert( pCur!=0 && pCur->pPage!=0 ); - assert( pCur->isValid ); + assert( pCur->eState==CURSOR_VALID ); pPage = pCur->pPage; pageIntegrity(pPage); assert( pCur->idx>=0 && pCur->idxnCell ); getCellInfo(pCur); aPayload = pCur->info.pCell; @@ -2521,14 +3068,20 @@ ** ** These routines is used to get quick access to key and data ** in the common case where no overflow pages are used. */ const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){ - return (const void*)fetchPayload(pCur, pAmt, 0); + if( pCur->eState==CURSOR_VALID ){ + return (const void*)fetchPayload(pCur, pAmt, 0); + } + return 0; } const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){ - return (const void*)fetchPayload(pCur, pAmt, 1); + if( pCur->eState==CURSOR_VALID ){ + return (const void*)fetchPayload(pCur, pAmt, 1); + } + return 0; } /* ** Move the cursor down to a new child page. The newPgno argument is the @@ -2536,13 +3089,13 @@ */ static int moveToChild(BtCursor *pCur, u32 newPgno){ int rc; MemPage *pNewPage; MemPage *pOldPage; - Btree *pBt = pCur->pBt; + BtShared *pBt = pCur->pBtree->pBt; - assert( pCur->isValid ); + assert( pCur->eState==CURSOR_VALID ); rc = getAndInitPage(pBt, newPgno, &pNewPage, pCur->pPage); if( rc ) return rc; pageIntegrity(pNewPage); pNewPage->idxParent = pCur->idx; pOldPage = pCur->pPage; @@ -2585,11 +3138,11 @@ static void moveToParent(BtCursor *pCur){ MemPage *pParent; MemPage *pPage; int idxParent; - assert( pCur->isValid ); + assert( pCur->eState==CURSOR_VALID ); pPage = pCur->pPage; assert( pPage!=0 ); assert( !isRootPage(pPage) ); pageIntegrity(pPage); pParent = pPage->pParent; @@ -2608,15 +3161,17 @@ ** Move the cursor to the root page */ static int moveToRoot(BtCursor *pCur){ MemPage *pRoot; int rc; - Btree *pBt = pCur->pBt; + BtShared *pBt = pCur->pBtree->pBt; - rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0); - if( rc ){ - pCur->isValid = 0; + if( + SQLITE_OK!=(rc = restoreCursorPosition(pCur, 0)) || + SQLITE_OK!=(rc = getAndInitPage(pBt, pCur->pgnoRoot, &pRoot, 0)) + ){ + pCur->eState = CURSOR_INVALID; return rc; } releasePage(pCur->pPage); pageIntegrity(pRoot); pCur->pPage = pRoot; @@ -2625,14 +3180,14 @@ if( pRoot->nCell==0 && !pRoot->leaf ){ Pgno subpage; assert( pRoot->pgno==1 ); subpage = get4byte(&pRoot->aData[pRoot->hdrOffset+8]); assert( subpage>0 ); - pCur->isValid = 1; + pCur->eState = CURSOR_VALID; rc = moveToChild(pCur, subpage); } - pCur->isValid = pCur->pPage->nCell>0; + pCur->eState = ((pCur->pPage->nCell>0)?CURSOR_VALID:CURSOR_INVALID); return rc; } /* ** Move the cursor down to the left-most leaf entry beneath the @@ -2641,11 +3196,11 @@ static int moveToLeftmost(BtCursor *pCur){ Pgno pgno; int rc; MemPage *pPage; - assert( pCur->isValid ); + assert( pCur->eState==CURSOR_VALID ); while( !(pPage = pCur->pPage)->leaf ){ assert( pCur->idx>=0 && pCur->idxnCell ); pgno = get4byte(findCell(pPage, pCur->idx)); rc = moveToChild(pCur, pgno); if( rc ) return rc; @@ -2663,11 +3218,11 @@ static int moveToRightmost(BtCursor *pCur){ Pgno pgno; int rc; MemPage *pPage; - assert( pCur->isValid ); + assert( pCur->eState==CURSOR_VALID ); while( !(pPage = pCur->pPage)->leaf ){ pgno = get4byte(&pPage->aData[pPage->hdrOffset+8]); pCur->idx = pPage->nCell; rc = moveToChild(pCur, pgno); if( rc ) return rc; @@ -2683,11 +3238,11 @@ */ int sqlite3BtreeFirst(BtCursor *pCur, int *pRes){ int rc; rc = moveToRoot(pCur); if( rc ) return rc; - if( pCur->isValid==0 ){ + if( pCur->eState==CURSOR_INVALID ){ assert( pCur->pPage->nCell==0 ); *pRes = 1; return SQLITE_OK; } assert( pCur->pPage->nCell>0 ); @@ -2702,16 +3257,16 @@ */ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){ int rc; rc = moveToRoot(pCur); if( rc ) return rc; - if( pCur->isValid==0 ){ + if( CURSOR_INVALID==pCur->eState ){ assert( pCur->pPage->nCell==0 ); *pRes = 1; return SQLITE_OK; } - assert( pCur->isValid ); + assert( pCur->eState==CURSOR_VALID ); *pRes = 0; rc = moveToRightmost(pCur); return rc; } @@ -2718,11 +3273,11 @@ /* Move the cursor so that it points to an entry near pKey/nKey. ** Return a success code. ** ** For INTKEY tables, only the nKey parameter is used. pKey is ** ignored. For other tables, nKey is the number of bytes of data -** in nKey. The comparison function specified when the cursor was +** in pKey. The comparison function specified when the cursor was ** created is used to compare keys. ** ** If an exact match is not found, then the cursor is always ** left pointing at a leaf page which would hold the entry if it ** were present. The cursor might point to an entry that comes @@ -2746,11 +3301,11 @@ int rc; rc = moveToRoot(pCur); if( rc ) return rc; assert( pCur->pPage ); assert( pCur->pPage->isInit ); - if( pCur->isValid==0 ){ + if( pCur->eState==CURSOR_INVALID ){ *pRes = -1; assert( pCur->pPage->nCell==0 ); return SQLITE_OK; } for(;;){ @@ -2838,11 +3393,15 @@ ** TRUE will be returned after a call to sqlite3BtreeNext() moves ** past the last entry in the table or sqlite3BtreePrev() moves past ** the first entry. TRUE is also returned if the table is empty. */ int sqlite3BtreeEof(BtCursor *pCur){ - return pCur->isValid==0; + /* TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries + ** have been deleted? This API will need to change to return an error code + ** as well as the boolean result value. + */ + return (CURSOR_VALID!=pCur->eState); } /* ** Advance the cursor to the next entry in the database. If ** successful then set *pRes=0. If the cursor @@ -2850,13 +3409,26 @@ ** this routine was called, then set *pRes=1. */ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){ int rc; MemPage *pPage = pCur->pPage; + +#ifndef SQLITE_OMIT_SHARED_CACHE + rc = restoreCursorPosition(pCur, 1); + if( rc!=SQLITE_OK ){ + return rc; + } + if( pCur->skip>0 ){ + pCur->skip = 0; + *pRes = 0; + return SQLITE_OK; + } + pCur->skip = 0; +#endif assert( pRes!=0 ); - if( pCur->isValid==0 ){ + if( CURSOR_INVALID==pCur->eState ){ *pRes = 1; return SQLITE_OK; } assert( pPage->isInit ); assert( pCur->idxnCell ); @@ -2872,11 +3444,11 @@ return rc; } do{ if( isRootPage(pPage) ){ *pRes = 1; - pCur->isValid = 0; + pCur->eState = CURSOR_INVALID; return SQLITE_OK; } moveToParent(pCur); pPage = pCur->pPage; }while( pCur->idx>=pPage->nCell ); @@ -2904,11 +3476,25 @@ */ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){ int rc; Pgno pgno; MemPage *pPage; - if( pCur->isValid==0 ){ + +#ifndef SQLITE_OMIT_SHARED_CACHE + rc = restoreCursorPosition(pCur, 1); + if( rc!=SQLITE_OK ){ + return rc; + } + if( pCur->skip<0 ){ + pCur->skip = 0; + *pRes = 0; + return SQLITE_OK; + } + pCur->skip = 0; +#endif + + if( CURSOR_INVALID==pCur->eState ){ *pRes = 1; return SQLITE_OK; } pPage = pCur->pPage; @@ -2920,11 +3506,11 @@ if( rc ) return rc; rc = moveToRightmost(pCur); }else{ while( pCur->idx==0 ){ if( isRootPage(pPage) ){ - pCur->isValid = 0; + pCur->eState = CURSOR_INVALID; *pRes = 1; return SQLITE_OK; } moveToParent(pCur); pPage = pCur->pPage; @@ -2961,11 +3547,11 @@ ** If the "exact" parameter is not 0, and the page-number nearby exists ** anywhere on the free-list, then it is guarenteed to be returned. This ** is only used by auto-vacuum databases when allocating a new table. */ static int allocatePage( - Btree *pBt, + BtShared *pBt, MemPage **ppPage, Pgno *pPgno, Pgno nearby, u8 exact ){ @@ -3179,11 +3765,11 @@ ** Add a page of the database file to the freelist. ** ** sqlite3pager_unref() is NOT called for pPage. */ static int freePage(MemPage *pPage){ - Btree *pBt = pPage->pBt; + BtShared *pBt = pPage->pBt; MemPage *pPage1 = pBt->pPage1; int rc, n, k; /* Prepare the page for freeing */ assert( pPage->pgno>1 ); @@ -3247,11 +3833,11 @@ /* ** Free any overflow pages associated with the given Cell. */ static int clearCell(MemPage *pPage, unsigned char *pCell){ - Btree *pBt = pPage->pBt; + BtShared *pBt = pPage->pBt; CellInfo info; Pgno ovflPgno; int rc; parseCellPtr(pPage, pCell, &info); @@ -3299,11 +3885,11 @@ int spaceLeft; MemPage *pOvfl = 0; MemPage *pToRelease = 0; unsigned char *pPrior; unsigned char *pPayload; - Btree *pBt = pPage->pBt; + BtShared *pBt = pPage->pBt; Pgno pgnoOvfl = 0; int nHeader; CellInfo info; /* Fill in the header. */ @@ -3388,11 +3974,11 @@ /* ** Change the MemPage.pParent pointer on the page whose number is ** given in the second argument so that MemPage.pParent holds the ** pointer in the third argument. */ -static int reparentPage(Btree *pBt, Pgno pgno, MemPage *pNewParent, int idx){ +static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){ MemPage *pThis; unsigned char *aData; if( pgno==0 ) return SQLITE_OK; assert( pBt->pPager!=0 ); @@ -3431,11 +4017,11 @@ ** This routine gets called after you memcpy() one page into ** another. */ static int reparentChildPages(MemPage *pPage){ int i; - Btree *pBt = pPage->pBt; + BtShared *pBt = pPage->pBt; int rc = SQLITE_OK; if( pPage->leaf ) return SQLITE_OK; for(i=0; inCell; i++){ @@ -3664,11 +4250,11 @@ MemPage *pNew; Pgno pgnoNew; u8 *pCell; int szCell; CellInfo info; - Btree *pBt = pPage->pBt; + BtShared *pBt = pPage->pBt; int parentIdx = pParent->nCell; /* pParent new divider cell index */ int parentSize; /* Size of new divider cell */ u8 parentCell[64]; /* Space for the new divider cell */ /* Allocate a new page. Insert the overflow cell from pPage @@ -3773,11 +4359,11 @@ ** in a corrupted state. So if this routine fails, the database should ** be rolled back. */ static int balance_nonroot(MemPage *pPage){ MemPage *pParent; /* The parent of pPage */ - Btree *pBt; /* The whole database */ + BtShared *pBt; /* The whole database */ int nCell = 0; /* Number of cells in apCell[] */ int nMaxCells = 0; /* Allocated size of apCell, szCell, aFrom. */ int nOld; /* Number of pages in apOld[] */ int nNew; /* Number of pages in apNew[] */ int nDiv; /* Number of cells in apDiv[] */ @@ -3794,11 +4380,10 @@ MemPage *apOld[NB]; /* pPage and up to two siblings */ Pgno pgnoOld[NB]; /* Page numbers for each page in apOld[] */ MemPage *apCopy[NB]; /* Private copies of apOld[] pages */ MemPage *apNew[NB+2]; /* pPage and up to NB siblings after balancing */ Pgno pgnoNew[NB+2]; /* Page numbers for each page in apNew[] */ - int idxDiv[NB]; /* Indices of divider cells in pParent */ u8 *apDiv[NB]; /* Divider cells in pParent */ int cntNew[NB+2]; /* Index in aCell[] of cell after i-th page */ int szNew[NB+2]; /* Combined size of cells place on i-th page */ u8 **apCell = 0; /* All cells begin balanced */ int *szCell; /* Local size of all cells in apCell[] */ @@ -3886,11 +4471,10 @@ nxDiv = 0; } nDiv = 0; for(i=0, k=nxDiv; inCell ){ - idxDiv[i] = k; apDiv[i] = findCell(pParent, k); nDiv++; assert( !pParent->leaf ); pgnoOld[i] = get4byte(apDiv[i]); }else if( k==pParent->nCell ){ @@ -4324,11 +4908,11 @@ */ static int balance_shallower(MemPage *pPage){ MemPage *pChild; /* The only child page of pPage */ Pgno pgnoChild; /* Page number for pChild */ int rc = SQLITE_OK; /* Return code from subprocedures */ - Btree *pBt; /* The main BTree structure */ + BtShared *pBt; /* The main BTree structure */ int mxCellPerPage; /* Maximum number of cells per page */ u8 **apCell; /* All cells from pages being balanced */ int *szCell; /* Local size of all cells */ assert( pPage->pParent==0 ); @@ -4426,11 +5010,11 @@ */ static int balance_deeper(MemPage *pPage){ int rc; /* Return value from subprocedures */ MemPage *pChild; /* Pointer to a new child page */ Pgno pgnoChild; /* Page number of the new child page */ - Btree *pBt; /* The BTree */ + BtShared *pBt; /* The BTree */ int usableSize; /* Total usable size of a page */ u8 *data; /* Content of the parent page */ u8 *cdata; /* Content of the child page */ int hdr; /* Offset to page header in parent */ int brk; /* Offset to content of first cell in parent */ @@ -4515,14 +5099,16 @@ ** first Cell on root page. This is necessary because an insert ** or delete might change the number of cells on a page or delete ** a page entirely and we do not want to leave any cursors ** pointing to non-existant pages or cells. */ -static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){ +static int checkReadLocks(BtShared *pBt, Pgno pgnoRoot, BtCursor *pExclude){ BtCursor *p; for(p=pBt->pCursor; p; p=p->pNext){ + u32 flags = (p->pBtree->pSqlite ? p->pBtree->pSqlite->flags : 0); if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue; + if( p->wrFlag==0 && flags&SQLITE_ReadUncommitted ) continue; if( p->wrFlag==0 ) return SQLITE_LOCKED; if( p->pPage->pgno!=p->pgnoRoot ){ moveToRoot(p); } } @@ -4545,15 +5131,15 @@ ){ int rc; int loc; int szNew; MemPage *pPage; - Btree *pBt = pCur->pBt; + BtShared *pBt = pCur->pBtree->pBt; unsigned char *oldCell; unsigned char *newCell = 0; - if( pBt->inTrans!=TRANS_WRITE ){ + if( pBt->inTransaction!=TRANS_WRITE ){ /* Must start a transaction before doing an insert */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( !pBt->readOnly ); if( !pCur->wrFlag ){ @@ -4560,12 +5146,20 @@ return SQLITE_PERM; /* Cursor not open for writing */ } if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){ return SQLITE_LOCKED; /* The table pCur points to has a read lock */ } - rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc); - if( rc ) return rc; + + /* Save the positions of any other cursors open on this table */ + if( + SQLITE_OK!=(rc = restoreCursorPosition(pCur, 0)) || + SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) || + SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc)) + ){ + return rc; + } + pPage = pCur->pPage; assert( pPage->intKey || nKey>=0 ); assert( pPage->leaf || !pPage->leafData ); TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, nKey, nData, pPage->pgno, @@ -4577,11 +5171,11 @@ if( newCell==0 ) return SQLITE_NOMEM; rc = fillInCell(pPage, newCell, pKey, nKey, pData, nData, &szNew); if( rc ) goto end_insert; assert( szNew==cellSizePtr(pPage, newCell) ); assert( szNew<=MX_CELL_SIZE(pBt) ); - if( loc==0 && pCur->isValid ){ + if( loc==0 && CURSOR_VALID==pCur->eState ){ int szOld; assert( pCur->idx>=0 && pCur->idxnCell ); oldCell = findCell(pPage, pCur->idx); if( !pPage->leaf ){ memcpy(newCell, oldCell, 4); @@ -4617,14 +5211,14 @@ int sqlite3BtreeDelete(BtCursor *pCur){ MemPage *pPage = pCur->pPage; unsigned char *pCell; int rc; Pgno pgnoChild = 0; - Btree *pBt = pCur->pBt; + BtShared *pBt = pCur->pBtree->pBt; assert( pPage->isInit ); - if( pBt->inTrans!=TRANS_WRITE ){ + if( pBt->inTransaction!=TRANS_WRITE ){ /* Must start a transaction before doing a delete */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( !pBt->readOnly ); if( pCur->idx >= pPage->nCell ){ @@ -4634,12 +5228,23 @@ return SQLITE_PERM; /* Did not open this cursor for writing */ } if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){ return SQLITE_LOCKED; /* The table pCur points to has a read lock */ } - rc = sqlite3pager_write(pPage->aData); - if( rc ) return rc; + + /* Restore the current cursor position (a no-op if the cursor is not in + ** CURSOR_REQUIRESEEK state) and save the positions of any other cursors + ** open on the same table. Then call sqlite3pager_write() on the page + ** that the entry will be deleted from. + */ + if( + (rc = restoreCursorPosition(pCur, 1)) || + (rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) || + (rc = sqlite3pager_write(pPage->aData)) + ){ + return rc; + } /* Locate the cell within it's page and leave pCell pointing to the ** data. The clearCell() call frees any overflow pages associated with the ** cell. The cell itself is still intact. */ @@ -4720,15 +5325,16 @@ ** flags might not work: ** ** BTREE_INTKEY|BTREE_LEAFDATA Used for SQL tables with rowid keys ** BTREE_ZERODATA Used for SQL indices */ -int sqlite3BtreeCreateTable(Btree *pBt, int *piTable, int flags){ +int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){ + BtShared *pBt = p->pBt; MemPage *pRoot; Pgno pgnoRoot; int rc; - if( pBt->inTrans!=TRANS_WRITE ){ + if( pBt->inTransaction!=TRANS_WRITE ){ /* Must start a transaction first */ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( !pBt->readOnly ); @@ -4751,11 +5357,11 @@ /* Read the value of meta[3] from the database to determine where the ** root page of the new table should go. meta[3] is the largest root-page ** created so far, so the new root-page is (meta[3]+1). */ - rc = sqlite3BtreeGetMeta(pBt, 4, &pgnoRoot); + rc = sqlite3BtreeGetMeta(p, 4, &pgnoRoot); if( rc!=SQLITE_OK ) return rc; pgnoRoot++; /* The new root-page may not be allocated on a pointer-map page, or the ** PENDING_BYTE page. @@ -4818,11 +5424,11 @@ rc = ptrmapPut(pBt, pgnoRoot, PTRMAP_ROOTPAGE, 0); if( rc ){ releasePage(pRoot); return rc; } - rc = sqlite3BtreeUpdateMeta(pBt, 4, pgnoRoot); + rc = sqlite3BtreeUpdateMeta(p, 4, pgnoRoot); if( rc ){ releasePage(pRoot); return rc; } @@ -4841,11 +5447,11 @@ /* ** Erase the given database page and all its children. Return ** the page to the freelist. */ static int clearDatabasePage( - Btree *pBt, /* The BTree that contains the table */ + BtShared *pBt, /* The BTree that contains the table */ Pgno pgno, /* Page number to clear */ MemPage *pParent, /* Parent page. NULL for the root */ int freePageFlag /* Deallocate page if true */ ){ MemPage *pPage = 0; @@ -4892,26 +5498,29 @@ ** ** This routine will fail with SQLITE_LOCKED if there are any open ** read cursors on the table. Open write cursors are moved to the ** root of the table. */ -int sqlite3BtreeClearTable(Btree *pBt, int iTable){ +int sqlite3BtreeClearTable(Btree *p, int iTable){ int rc; BtCursor *pCur; - if( pBt->inTrans!=TRANS_WRITE ){ + BtShared *pBt = p->pBt; + if( p->inTrans!=TRANS_WRITE ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){ if( pCur->pgnoRoot==(Pgno)iTable ){ if( pCur->wrFlag==0 ) return SQLITE_LOCKED; moveToRoot(pCur); } } rc = clearDatabasePage(pBt, (Pgno)iTable, 0, 0); +#if 0 if( rc ){ sqlite3BtreeRollback(pBt); } +#endif return rc; } /* ** Erase all information in a table and add the root of the table to @@ -4931,15 +5540,16 @@ ** page number that used to be the last root page in the file before ** the move. If no page gets moved, *piMoved is set to 0. ** The last root page is recorded in meta[3] and the value of ** meta[3] is updated by this procedure. */ -int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){ +int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){ int rc; MemPage *pPage = 0; + BtShared *pBt = p->pBt; - if( pBt->inTrans!=TRANS_WRITE ){ + if( p->inTrans!=TRANS_WRITE ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } /* It is illegal to drop a table if any cursors are open on the ** database. This is because in auto-vacuum mode the backend may @@ -4951,11 +5561,11 @@ return SQLITE_LOCKED; } rc = getPage(pBt, (Pgno)iTable, &pPage); if( rc ) return rc; - rc = sqlite3BtreeClearTable(pBt, iTable); + rc = sqlite3BtreeClearTable(p, iTable); if( rc ){ releasePage(pPage); return rc; } @@ -4966,11 +5576,11 @@ rc = freePage(pPage); releasePage(pPage); #else if( pBt->autoVacuum ){ Pgno maxRootPgno; - rc = sqlite3BtreeGetMeta(pBt, 4, &maxRootPgno); + rc = sqlite3BtreeGetMeta(p, 4, &maxRootPgno); if( rc!=SQLITE_OK ){ releasePage(pPage); return rc; } @@ -5023,11 +5633,11 @@ if( maxRootPgno==PTRMAP_PAGENO(pBt->usableSize, maxRootPgno) ){ maxRootPgno--; } assert( maxRootPgno!=PENDING_BYTE_PAGE(pBt) ); - rc = sqlite3BtreeUpdateMeta(pBt, 4, maxRootPgno); + rc = sqlite3BtreeUpdateMeta(p, 4, maxRootPgno); }else{ rc = freePage(pPage); releasePage(pPage); } #endif @@ -5048,13 +5658,24 @@ ** ** The schema layer numbers meta values differently. At the schema ** layer (and the SetCookie and ReadCookie opcodes) the number of ** free pages is not visible. So Cookie[0] is the same as Meta[1]. */ -int sqlite3BtreeGetMeta(Btree *pBt, int idx, u32 *pMeta){ +int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){ int rc; unsigned char *pP1; + BtShared *pBt = p->pBt; + + /* Reading a meta-data value requires a read-lock on page 1 (and hence + ** the sqlite_master table. We grab this lock regardless of whether or + ** not the SQLITE_ReadUncommitted flag is set (the table rooted at page + ** 1 is treated as a special case by queryTableLock() and lockTable()). + */ + rc = queryTableLock(p, 1, READ_LOCK); + if( rc!=SQLITE_OK ){ + return rc; + } assert( idx>=0 && idx<=15 ); rc = sqlite3pager_get(pBt->pPager, 1, (void**)&pP1); if( rc ) return rc; *pMeta = get4byte(&pP1[36 + idx*4]); @@ -5065,22 +5686,25 @@ */ #ifdef SQLITE_OMIT_AUTOVACUUM if( idx==4 && *pMeta>0 ) pBt->readOnly = 1; #endif - return SQLITE_OK; + /* Grab the read-lock on page 1. */ + rc = lockTable(p, 1, READ_LOCK); + return rc; } /* ** Write meta-information back into the database. Meta[0] is ** read-only and may not be written. */ -int sqlite3BtreeUpdateMeta(Btree *pBt, int idx, u32 iMeta){ +int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ + BtShared *pBt = p->pBt; unsigned char *pP1; int rc; assert( idx>=1 && idx<=15 ); - if( pBt->inTrans!=TRANS_WRITE ){ + if( p->inTrans!=TRANS_WRITE ){ return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR; } assert( pBt->pPage1!=0 ); pP1 = pBt->pPage1->aData; rc = sqlite3pager_write(pP1); @@ -5092,20 +5716,23 @@ /* ** Return the flag byte at the beginning of the page that the cursor ** is currently pointing to. */ int sqlite3BtreeFlags(BtCursor *pCur){ + /* TODO: What about CURSOR_REQUIRESEEK state? Probably need to call + ** restoreCursorPosition() here. + */ MemPage *pPage = pCur->pPage; return pPage ? pPage->aData[pPage->hdrOffset] : 0; } #ifdef SQLITE_DEBUG /* ** Print a disassembly of the given page on standard output. This routine ** is used for debugging and testing only. */ -static int btreePageDump(Btree *pBt, int pgno, int recursive, MemPage *pParent){ +static int btreePageDump(BtShared *pBt, int pgno, int recursive, MemPage *pParent){ int rc; MemPage *pPage; int i, j, c; int nFree; u16 idx; @@ -5197,12 +5824,12 @@ pPage->isInit = isInit; sqlite3pager_unref(data); fflush(stdout); return SQLITE_OK; } -int sqlite3BtreePageDump(Btree *pBt, int pgno, int recursive){ - return btreePageDump(pBt, pgno, recursive, 0); +int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){ + return btreePageDump(p->pBt, pgno, recursive, 0); } #endif #ifdef SQLITE_TEST /* @@ -5224,10 +5851,15 @@ */ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){ int cnt, idx; MemPage *pPage = pCur->pPage; BtCursor tmpCur; + + int rc = restoreCursorPosition(pCur, 1); + if( rc!=SQLITE_OK ){ + return rc; + } pageIntegrity(pPage); assert( pPage->isInit ); getTempCursor(pCur, &tmpCur); while( upCnt-- ){ @@ -5271,21 +5903,21 @@ /* ** Return the pager associated with a BTree. This routine is used for ** testing and debugging only. */ -Pager *sqlite3BtreePager(Btree *pBt){ - return pBt->pPager; +Pager *sqlite3BtreePager(Btree *p){ + return p->pBt->pPager; } /* ** This structure is passed around through all the sanity checking routines ** in order to keep track of some global state information. */ typedef struct IntegrityCk IntegrityCk; struct IntegrityCk { - Btree *pBt; /* The tree being checked out */ + BtShared *pBt; /* The tree being checked out */ Pager *pPager; /* The associated pager. Also accessible by pBt->pPager */ int nPage; /* Number of pages in the database */ int *anRef; /* Number of times each page is referenced */ char *zErrMsg; /* An error message. NULL of no errors seen. */ }; @@ -5472,21 +6104,20 @@ MemPage *pPage; int i, rc, depth, d2, pgno, cnt; int hdr, cellStart; int nCell; u8 *data; - BtCursor cur; - Btree *pBt; + BtShared *pBt; int usableSize; char zContext[100]; char *hit; sprintf(zContext, "Page %d: ", iPage); /* Check that the page exists */ - cur.pBt = pBt = pCheck->pBt; + pBt = pCheck->pBt; usableSize = pBt->usableSize; if( iPage==0 ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0; if( (rc = getPage(pBt, (Pgno)iPage, &pPage))!=0 ){ checkAppendMsg(pCheck, zContext, @@ -5500,11 +6131,10 @@ } /* Check out all the cells. */ depth = 0; - cur.pPage = pPage; for(i=0; inCell; i++){ u8 *pCell; int sz; CellInfo info; @@ -5616,17 +6246,18 @@ ** If everything checks out, this routine returns NULL. If something is ** amiss, an error message is written into memory obtained from malloc() ** and a pointer to that error message is returned. The calling function ** is responsible for freeing the error message when it is done. */ -char *sqlite3BtreeIntegrityCheck(Btree *pBt, int *aRoot, int nRoot){ +char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){ int i; int nRef; IntegrityCk sCheck; + BtShared *pBt = p->pBt; nRef = *sqlite3pager_stats(pBt->pPager); - if( lockBtreeWithRetry(pBt)!=SQLITE_OK ){ + if( lockBtreeWithRetry(p)!=SQLITE_OK ){ return sqliteStrDup("Unable to acquire a read lock on the database"); } sCheck.pBt = pBt; sCheck.pPager = pBt->pPager; sCheck.nPage = sqlite3pager_pagecount(sCheck.pPager); @@ -5704,31 +6335,31 @@ #endif /* SQLITE_OMIT_INTEGRITY_CHECK */ /* ** Return the full pathname of the underlying database file. */ -const char *sqlite3BtreeGetFilename(Btree *pBt){ - assert( pBt->pPager!=0 ); - return sqlite3pager_filename(pBt->pPager); +const char *sqlite3BtreeGetFilename(Btree *p){ + assert( p->pBt->pPager!=0 ); + return sqlite3pager_filename(p->pBt->pPager); } /* ** Return the pathname of the directory that contains the database file. */ -const char *sqlite3BtreeGetDirname(Btree *pBt){ - assert( pBt->pPager!=0 ); - return sqlite3pager_dirname(pBt->pPager); +const char *sqlite3BtreeGetDirname(Btree *p){ + assert( p->pBt->pPager!=0 ); + return sqlite3pager_dirname(p->pBt->pPager); } /* ** Return the pathname of the journal file for this database. The return ** value of this routine is the same regardless of whether the journal file ** has been created or not. */ -const char *sqlite3BtreeGetJournalname(Btree *pBt){ - assert( pBt->pPager!=0 ); - return sqlite3pager_journalname(pBt->pPager); +const char *sqlite3BtreeGetJournalname(Btree *p){ + assert( p->pBt->pPager!=0 ); + return sqlite3pager_journalname(p->pBt->pPager); } #ifndef SQLITE_OMIT_VACUUM /* ** Copy the complete content of pBtFrom into pBtTo. A transaction @@ -5735,15 +6366,18 @@ ** must be active for both files. ** ** The size of file pBtFrom may be reduced by this operation. ** If anything goes wrong, the transaction on pBtFrom is rolled back. */ -int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){ +int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){ int rc = SQLITE_OK; Pgno i, nPage, nToPage, iSkip; - if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){ + BtShared *pBtTo = pTo->pBt; + BtShared *pBtFrom = pFrom->pBt; + + if( pTo->inTrans!=TRANS_WRITE || pFrom->inTrans!=TRANS_WRITE ){ return SQLITE_ERROR; } if( pBtTo->pCursor ) return SQLITE_BUSY; nToPage = sqlite3pager_pagecount(pBtTo->pPager); nPage = sqlite3pager_pagecount(pBtFrom->pPager); @@ -5768,28 +6402,28 @@ } if( !rc && nPagepPager, nPage); } if( rc ){ - sqlite3BtreeRollback(pBtTo); + sqlite3BtreeRollback(pTo); } return rc; } #endif /* SQLITE_OMIT_VACUUM */ /* ** Return non-zero if a transaction is active. */ -int sqlite3BtreeIsInTrans(Btree *pBt){ - return (pBt && (pBt->inTrans==TRANS_WRITE)); +int sqlite3BtreeIsInTrans(Btree *p){ + return (p && (p->inTrans==TRANS_WRITE)); } /* ** Return non-zero if a statement transaction is active. */ -int sqlite3BtreeIsInStmt(Btree *pBt){ - return (pBt && pBt->inStmt); +int sqlite3BtreeIsInStmt(Btree *p){ + return (p->pBt && p->pBt->inStmt); } /* ** This call is a no-op if no write-transaction is currently active on pBt. ** @@ -5802,12 +6436,13 @@ ** created, populated with this journal pointer and synced to disk. ** ** Once this is routine has returned, the only thing required to commit ** the write-transaction for this database file is to delete the journal. */ -int sqlite3BtreeSync(Btree *pBt, const char *zMaster){ - if( pBt->inTrans==TRANS_WRITE ){ +int sqlite3BtreeSync(Btree *p, const char *zMaster){ + if( p->inTrans==TRANS_WRITE ){ + BtShared *pBt = p->pBt; #ifndef SQLITE_OMIT_AUTOVACUUM Pgno nTrunc = 0; if( pBt->autoVacuum ){ int rc = autoVacuumCommit(pBt, &nTrunc); if( rc!=SQLITE_OK ) return rc; @@ -5817,17 +6452,49 @@ return sqlite3pager_sync(pBt->pPager, zMaster, 0); } return SQLITE_OK; } -#ifndef SQLITE_OMIT_GLOBALRECOVER -/* -** Reset the btree and underlying pager after a malloc() failure. Any -** transaction that was active when malloc() failed is rolled back. -*/ -int sqlite3BtreeReset(Btree *pBt){ - if( pBt->pCursor ) return SQLITE_BUSY; - pBt->inTrans = TRANS_NONE; - unlockBtreeIfUnused(pBt); - return sqlite3pager_reset(pBt->pPager); -} -#endif +/* +** This function returns a pointer to a blob of memory associated with +** a single shared-btree. The memory is used by client code for it's own +** purposes (for example, to store a high-level schema associated with +** the shared-btree). The btree layer manages reference counting issues. +** +** The first time this is called on a shared-btree, nBytes bytes of memory +** are allocated, zeroed, and returned to the caller. For each subsequent +** call the nBytes parameter is ignored and a pointer to the same blob +** of memory returned. +** +** Just before the shared-btree is closed, the function passed as the +** xFree argument when the memory allocation was made is invoked on the +** blob of allocated memory. This function should not call sqliteFree() +** on the memory, the btree layer does that. +*/ +void *sqlite3BtreeSchema(Btree *p, int nBytes, void(*xFree)(void *)){ + BtShared *pBt = p->pBt; + if( !pBt->pSchema ){ + pBt->pSchema = sqliteMalloc(nBytes); + pBt->xFreeSchema = xFree; + } + return pBt->pSchema; +} + +/* +** Return true if another user of the same shared btree as the argument +** handle holds an exclusive lock on the sqlite_master table. +*/ +int sqlite3BtreeSchemaLocked(Btree *p){ + return (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK); +} + +int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){ + int rc = SQLITE_OK; +#ifndef SQLITE_OMIT_SHARED_CACHE + u8 lockType = (isWriteLock?WRITE_LOCK:READ_LOCK); + rc = queryTableLock(p, iTab, lockType); + if( rc==SQLITE_OK ){ + rc = lockTable(p, iTab, lockType); + } +#endif + return rc; +} Index: SQLite.Interop/src/btree.h ================================================================== --- SQLite.Interop/src/btree.h +++ SQLite.Interop/src/btree.h @@ -11,11 +11,11 @@ ************************************************************************* ** This header file defines the interface that the sqlite B-Tree file ** subsystem. See comments in the source code for a detailed description ** of what each interface routine does. ** -** @(#) $Id: btree.h,v 1.11 2005/12/19 17:57:46 rmsimpson Exp $ +** @(#) $Id: btree.h,v 1.12 2006/01/10 18:40:37 rmsimpson Exp $ */ #ifndef _BTREE_H_ #define _BTREE_H_ /* TODO: This definition is just included so other modules compile. It @@ -34,14 +34,16 @@ /* ** Forward declarations of structure */ typedef struct Btree Btree; typedef struct BtCursor BtCursor; +typedef struct BtShared BtShared; int sqlite3BtreeOpen( const char *zFilename, /* Name of database file to open */ + sqlite3 *db, /* Associated database connection */ Btree **, /* Return open Btree* here */ int flags /* Flags */ ); /* The flags parameter to sqlite3BtreeOpen can be the bitwise or of the @@ -72,11 +74,13 @@ int sqlite3BtreeRollbackStmt(Btree*); int sqlite3BtreeCreateTable(Btree*, int*, int flags); int sqlite3BtreeIsInTrans(Btree*); int sqlite3BtreeIsInStmt(Btree*); int sqlite3BtreeSync(Btree*, const char *zMaster); -int sqlite3BtreeReset(Btree *); +void *sqlite3BtreeSchema(Btree *, int, void(*)(void *)); +int sqlite3BtreeSchemaLocked(Btree *); +int sqlite3BtreeLockTable(Btree *, int, u8); const char *sqlite3BtreeGetFilename(Btree *); const char *sqlite3BtreeGetDirname(Btree *); const char *sqlite3BtreeGetJournalname(Btree *); int sqlite3BtreeCopyFile(Btree *, Btree *); Index: SQLite.Interop/src/build.c ================================================================== --- SQLite.Interop/src/build.c +++ SQLite.Interop/src/build.c @@ -20,11 +20,11 @@ ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.10 2005/12/19 17:57:46 rmsimpson Exp $ +** $Id: build.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* @@ -33,10 +33,91 @@ */ void sqlite3BeginParse(Parse *pParse, int explainFlag){ pParse->explain = explainFlag; pParse->nVar = 0; } + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** The TableLock structure is only used by the sqlite3TableLock() and +** codeTableLocks() functions. +*/ +struct TableLock { + int iDb; + int iTab; + u8 isWriteLock; + const char *zName; +}; + +/* +** Have the compiled statement lock the table with rootpage iTab in database +** iDb at the shared-cache level when executed. The isWriteLock argument +** is zero for a read-lock, or non-zero for a write-lock. +** +** The zName parameter should point to the unqualified table name. This is +** used to provide a more informative error message should the lock fail. +*/ +void sqlite3TableLock( + Parse *pParse, + int iDb, + int iTab, + u8 isWriteLock, + const char *zName +){ + int i; + int nBytes; + TableLock *p; + ThreadData *pTsd = sqlite3ThreadData(); + + if( 0==pTsd->useSharedData || iDb<0 ){ + return; + } + + for(i=0; inTableLock; i++){ + p = &pParse->aTableLock[i]; + if( p->iDb==iDb && p->iTab==iTab ){ + p->isWriteLock = (p->isWriteLock || isWriteLock); + return; + } + } + + nBytes = sizeof(TableLock) * (pParse->nTableLock+1); + sqliteReallocOrFree((void **)&pParse->aTableLock, nBytes); + if( pParse->aTableLock ){ + p = &pParse->aTableLock[pParse->nTableLock++]; + p->iDb = iDb; + p->iTab = iTab; + p->isWriteLock = isWriteLock; + p->zName = zName; + } +} + +/* +** Code an OP_TableLock instruction for each table locked by the +** statement (configured by calls to sqlite3TableLock()). +*/ +static void codeTableLocks(Parse *pParse){ + int i; + Vdbe *pVdbe; + assert( sqlite3ThreadData()->useSharedData || pParse->nTableLock==0 ); + + if( 0==(pVdbe = sqlite3GetVdbe(pParse)) ){ + return; + } + + for(i=0; inTableLock; i++){ + TableLock *p = &pParse->aTableLock[i]; + int p1 = p->iDb; + if( p->isWriteLock ){ + p1 = -1*(p1+1); + } + sqlite3VdbeOp3(pVdbe, OP_TableLock, p1, p->iTab, p->zName, P3_STATIC); + } +} +#else + #define codeTableLocks(x) +#endif /* ** This routine is called after a single SQL statement has been ** parsed and a VDBE program to execute that statement has been ** prepared. This routine puts the finishing touches on the @@ -48,11 +129,11 @@ */ void sqlite3FinishCoding(Parse *pParse){ sqlite3 *db; Vdbe *v; - if( sqlite3_malloc_failed ) return; + if( sqlite3ThreadData()->mallocFailed ) return; if( pParse->nested ) return; if( !pParse->pVdbe ){ if( pParse->rc==SQLITE_OK && pParse->nErr ){ pParse->rc = SQLITE_ERROR; } @@ -80,10 +161,16 @@ for(iDb=0, mask=1; iDbnDb; mask<<=1, iDb++){ if( (mask & pParse->cookieMask)==0 ) continue; sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0); sqlite3VdbeAddOp(v, OP_VerifyCookie, iDb, pParse->cookieValue[iDb]); } + + /* Once all the cookies have been verified and transactions opened, + ** obtain the required table-locks. This is a no-op unless the + ** shared-cache feature is enabled. + */ + codeTableLocks(pParse); sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto); } #ifndef SQLITE_OMIT_TRACE /* Add a No-op that contains the complete text of the compiled SQL @@ -170,11 +257,11 @@ assert( zName!=0 ); assert( (db->flags & SQLITE_Initialized) || db->init.busy ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; - p = sqlite3HashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1); + p = sqlite3HashFind(&db->aDb[j].pSchema->tblHash, zName, strlen(zName)+1); if( p ) break; } return p; } @@ -225,12 +312,16 @@ Index *p = 0; int i; assert( (db->flags & SQLITE_Initialized) || db->init.busy ); for(i=OMIT_TEMPDB; inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ + Schema *pSchema = db->aDb[j].pSchema; if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; - p = sqlite3HashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1); + assert( pSchema || (j==1 && !db->aDb[1].pBt) ); + if( pSchema ){ + p = sqlite3HashFind(&pSchema->idxHash, zName, strlen(zName)+1); + } if( p ) break; } return p; } @@ -250,14 +341,13 @@ ** it is not unlinked from the Table that it indexes. ** Unlinking from the Table must be done by the calling function. */ static void sqliteDeleteIndex(sqlite3 *db, Index *p){ Index *pOld; + const char *zName = p->zName; - assert( db!=0 && p->zName!=0 ); - pOld = sqlite3HashInsert(&db->aDb[p->iDb].idxHash, p->zName, - strlen(p->zName)+1, 0); + pOld = sqlite3HashInsert(&p->pSchema->idxHash, zName, strlen( zName)+1, 0); assert( pOld==0 || pOld==p ); freeIndex(p); } /* @@ -267,13 +357,14 @@ ** with the index. */ void sqlite3UnlinkAndDeleteIndex(sqlite3 *db, int iDb, const char *zIdxName){ Index *pIndex; int len; + Hash *pHash = &db->aDb[iDb].pSchema->idxHash; len = strlen(zIdxName); - pIndex = sqlite3HashInsert(&db->aDb[iDb].idxHash, zIdxName, len+1, 0); + pIndex = sqlite3HashInsert(pHash, zIdxName, len+1, 0); if( pIndex ){ if( pIndex->pTable->pIndex==pIndex ){ pIndex->pTable->pIndex = pIndex->pNext; }else{ Index *p; @@ -297,43 +388,26 @@ ** If iDb<=0 then reset the internal schema tables for all database ** files. If iDb>=2 then reset the internal schema for only the ** single file indicated. */ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ - HashElem *pElem; - Hash temp1; - Hash temp2; int i, j; assert( iDb>=0 && iDbnDb ); db->flags &= ~SQLITE_Initialized; for(i=iDb; inDb; i++){ Db *pDb = &db->aDb[i]; - temp1 = pDb->tblHash; - temp2 = pDb->trigHash; - sqlite3HashInit(&pDb->trigHash, SQLITE_HASH_STRING, 0); - sqlite3HashClear(&pDb->aFKey); - sqlite3HashClear(&pDb->idxHash); - for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ - sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem)); - } - sqlite3HashClear(&temp2); - sqlite3HashInit(&pDb->tblHash, SQLITE_HASH_STRING, 0); - for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ - Table *pTab = sqliteHashData(pElem); - sqlite3DeleteTable(db, pTab); - } - sqlite3HashClear(&temp1); - pDb->pSeqTab = 0; - DbClearProperty(db, i, DB_SchemaLoaded); + if( pDb->pSchema ){ + sqlite3SchemaFree(pDb->pSchema); + } if( iDb>0 ) return; } assert( iDb==0 ); db->flags &= ~SQLITE_InternChanges; /* If one or more of the auxiliary database files has been closed, - ** then remove then from the auxiliary database list. We take the + ** then remove them from the auxiliary database list. We take the ** opportunity to do this here since we have just deleted all of the ** schema hash tables and therefore do not have to make any changes ** to any of those tables. */ for(i=0; inDb; i++){ @@ -417,10 +491,12 @@ ** unlinked. */ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){ Index *pIndex, *pNext; FKey *pFKey, *pNextFKey; + + db = 0; if( pTable==0 ) return; /* Do not delete the table until the reference count reaches zero. */ pTable->nRef--; @@ -431,22 +507,21 @@ /* Delete all indices associated with this table */ for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){ pNext = pIndex->pNext; - assert( pIndex->iDb==pTable->iDb || (pTable->iDb==0 && pIndex->iDb==1) ); + assert( pIndex->pSchema==pTable->pSchema ); sqliteDeleteIndex(db, pIndex); } #ifndef SQLITE_OMIT_FOREIGN_KEY /* Delete all foreign keys associated with this table. The keys ** should have already been unlinked from the db->aFKey hash table */ for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){ pNextFKey = pFKey->pNextFrom; - assert( pTable->iDbnDb ); - assert( sqlite3HashFind(&db->aDb[pTable->iDb].aFKey, + assert( sqlite3HashFind(&pTable->pSchema->aFKey, pFKey->zTo, strlen(pFKey->zTo)+1)!=pFKey ); sqliteFree(pFKey); } #endif @@ -454,10 +529,13 @@ */ sqliteResetColumnNames(pTable); sqliteFree(pTable->zName); sqliteFree(pTable->zColAff); sqlite3SelectDelete(pTable->pSelect); +#ifndef SQLITE_OMIT_CHECK + sqlite3ExprDelete(pTable->pCheck); +#endif sqliteFree(pTable); } /* ** Unlink the given table from the hash tables and the delete the @@ -470,18 +548,18 @@ assert( db!=0 ); assert( iDb>=0 && iDbnDb ); assert( zTabName && zTabName[0] ); pDb = &db->aDb[iDb]; - p = sqlite3HashInsert(&pDb->tblHash, zTabName, strlen(zTabName)+1, 0); + p = sqlite3HashInsert(&pDb->pSchema->tblHash, zTabName, strlen(zTabName)+1,0); if( p ){ #ifndef SQLITE_OMIT_FOREIGN_KEY for(pF1=p->pFKey; pF1; pF1=pF1->pNextFrom){ int nTo = strlen(pF1->zTo) + 1; - pF2 = sqlite3HashFind(&pDb->aFKey, pF1->zTo, nTo); + pF2 = sqlite3HashFind(&pDb->pSchema->aFKey, pF1->zTo, nTo); if( pF2==pF1 ){ - sqlite3HashInsert(&pDb->aFKey, pF1->zTo, nTo, pF1->pNextTo); + sqlite3HashInsert(&pDb->pSchema->aFKey, pF1->zTo, nTo, pF1->pNextTo); }else{ while( pF2 && pF2->pNextTo!=pF1 ){ pF2=pF2->pNextTo; } if( pF2 ){ pF2->pNextTo = pF1->pNextTo; } @@ -504,11 +582,11 @@ ** is \000 terminated and is persistent. */ char *sqlite3NameFromToken(Token *pName){ char *zName; if( pName ){ - zName = sqliteStrNDup(pName->z, pName->n); + zName = sqliteStrNDup((char*)pName->z, pName->n); sqlite3Dequote(zName); }else{ zName = 0; } return zName; @@ -516,11 +594,13 @@ /* ** Open the sqlite_master table stored in database number iDb for ** writing. The table is opened using cursor 0. */ -void sqlite3OpenMasterTable(Vdbe *v, int iDb){ +void sqlite3OpenMasterTable(Parse *p, int iDb){ + Vdbe *v = sqlite3GetVdbe(p); + sqlite3TableLock(p, iDb, MASTER_ROOT, 1, SCHEMA_TABLE(iDb)); sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp(v, OP_OpenWrite, 0, MASTER_ROOT); sqlite3VdbeAddOp(v, OP_SetNumColumns, 0, 5); /* sqlite_master has 5 columns */ } @@ -630,11 +710,12 @@ Parse *pParse, /* Parser context */ Token *pStart, /* The "CREATE" token */ Token *pName1, /* First part of the name of the table or view */ Token *pName2, /* Second part of the name of the table or view */ int isTemp, /* True if this is a TEMP table */ - int isView /* True if this is a VIEW */ + int isView, /* True if this is a VIEW */ + int noErr /* Do nothing if table already exists */ ){ Table *pTable; char *zName = 0; /* The name of the new table */ sqlite3 *db = pParse->db; Vdbe *v; @@ -708,11 +789,13 @@ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto begin_table_error; } pTable = sqlite3FindTable(db, zName, db->aDb[iDb].zName); if( pTable ){ - sqlite3ErrorMsg(pParse, "table %T already exists", pName); + if( !noErr ){ + sqlite3ErrorMsg(pParse, "table %T already exists", pName); + } goto begin_table_error; } if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){ sqlite3ErrorMsg(pParse, "there is already an index named %s", zName); goto begin_table_error; @@ -726,11 +809,11 @@ pTable->zName = zName; pTable->nCol = 0; pTable->aCol = 0; pTable->iPKey = -1; pTable->pIndex = 0; - pTable->iDb = iDb; + pTable->pSchema = db->aDb[iDb].pSchema; pTable->nRef = 1; if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable); pParse->pNewTable = pTable; /* If this is the magic sqlite_sequence table used by autoincrement, @@ -737,11 +820,11 @@ ** then record a pointer to this table in the main database structure ** so that INSERT can find the table easily. */ #ifndef SQLITE_OMIT_AUTOINCREMENT if( !pParse->nested && strcmp(zName, "sqlite_sequence")==0 ){ - db->aDb[iDb].pSeqTab = pTable; + pTable->pSchema->pSeqTab = pTable; } #endif /* Begin generating the code that will insert the table record into ** the SQLITE_MASTER table. Note in particular that we must go ahead @@ -759,13 +842,13 @@ ** set them now. */ sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); /* file_format */ lbl = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_If, 0, lbl); - sqlite3VdbeAddOp(v, OP_Integer, db->file_format, 0); + sqlite3VdbeAddOp(v, OP_Integer, SQLITE_DEFAULT_FILE_FORMAT, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); - sqlite3VdbeAddOp(v, OP_Integer, db->enc, 0); + sqlite3VdbeAddOp(v, OP_Integer, ENC(db), 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 4); sqlite3VdbeResolveLabel(v, lbl); /* This just creates a place-holder record in the sqlite_master table. ** The record created does not contain anything yet. It will be replaced @@ -781,11 +864,11 @@ }else #endif { sqlite3VdbeAddOp(v, OP_CreateTable, iDb, 0); } - sqlite3OpenMasterTable(v, iDb); + sqlite3OpenMasterTable(pParse, iDb); sqlite3VdbeAddOp(v, OP_NewRowid, 0, 0); sqlite3VdbeAddOp(v, OP_Dup, 0, 0); sqlite3VdbeAddOp(v, OP_Null, 0, 0); sqlite3VdbeAddOp(v, OP_Insert, 0, 0); sqlite3VdbeAddOp(v, OP_Close, 0, 0); @@ -889,10 +972,13 @@ ** 'INT' | SQLITE_AFF_INTEGER ** 'CHAR' | SQLITE_AFF_TEXT ** 'CLOB' | SQLITE_AFF_TEXT ** 'TEXT' | SQLITE_AFF_TEXT ** 'BLOB' | SQLITE_AFF_NONE +** 'REAL' | SQLITE_AFF_REAL +** 'FLOA' | SQLITE_AFF_REAL +** 'DOUB' | SQLITE_AFF_REAL ** ** If none of the substrings in the above table are found, ** SQLITE_AFF_NUMERIC is returned. */ char sqlite3AffinityType(const Token *pType){ @@ -909,14 +995,25 @@ }else if( h==(('c'<<24)+('l'<<16)+('o'<<8)+'b') ){ /* CLOB */ aff = SQLITE_AFF_TEXT; }else if( h==(('t'<<24)+('e'<<16)+('x'<<8)+'t') ){ /* TEXT */ aff = SQLITE_AFF_TEXT; }else if( h==(('b'<<24)+('l'<<16)+('o'<<8)+'b') /* BLOB */ - && aff==SQLITE_AFF_NUMERIC ){ + && (aff==SQLITE_AFF_NUMERIC || aff==SQLITE_AFF_REAL) ){ aff = SQLITE_AFF_NONE; +#ifndef SQLITE_OMIT_FLOATING_POINT + }else if( h==(('r'<<24)+('e'<<16)+('a'<<8)+'l') /* REAL */ + && aff==SQLITE_AFF_NUMERIC ){ + aff = SQLITE_AFF_REAL; + }else if( h==(('f'<<24)+('l'<<16)+('o'<<8)+'a') /* FLOA */ + && aff==SQLITE_AFF_NUMERIC ){ + aff = SQLITE_AFF_REAL; + }else if( h==(('d'<<24)+('o'<<16)+('u'<<8)+'b') /* DOUB */ + && aff==SQLITE_AFF_NUMERIC ){ + aff = SQLITE_AFF_REAL; +#endif }else if( (h&0x00FFFFFF)==(('i'<<16)+('n'<<8)+'t') ){ /* INT */ - aff = SQLITE_AFF_INTEGER; + aff = SQLITE_AFF_INTEGER; break; } } return aff; @@ -991,11 +1088,12 @@ */ void sqlite3AddPrimaryKey( Parse *pParse, /* Parsing context */ ExprList *pList, /* List of field names to be indexed */ int onError, /* What to do with a uniqueness conflict */ - int autoInc /* True if the AUTOINCREMENT keyword is present */ + int autoInc, /* True if the AUTOINCREMENT keyword is present */ + int sortOrder /* SQLITE_SO_ASC or SQLITE_SO_DESC */ ){ Table *pTab = pParse->pNewTable; char *zType = 0; int iCol = -1, i; if( pTab==0 ) goto primary_key_exit; @@ -1022,28 +1120,48 @@ if( pList->nExpr>1 ) iCol = -1; } if( iCol>=0 && iColnCol ){ zType = pTab->aCol[iCol].zType; } - if( zType && sqlite3StrICmp(zType, "INTEGER")==0 ){ + if( zType && sqlite3StrICmp(zType, "INTEGER")==0 + && sortOrder==SQLITE_SO_ASC ){ pTab->iPKey = iCol; pTab->keyConf = onError; pTab->autoInc = autoInc; }else if( autoInc ){ #ifndef SQLITE_OMIT_AUTOINCREMENT sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " "INTEGER PRIMARY KEY"); #endif }else{ - sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0); + sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0, sortOrder, 0); pList = 0; } primary_key_exit: sqlite3ExprListDelete(pList); return; } + +/* +** Add a new CHECK constraint to the table currently under construction. +*/ +void sqlite3AddCheckConstraint( + Parse *pParse, /* Parsing context */ + Expr *pCheckExpr /* The check expression */ +){ +#ifndef SQLITE_OMIT_CHECK + Table *pTab = pParse->pNewTable; + if( pTab ){ + /* The CHECK expression must be duplicated so that tokens refer + ** to malloced space and not the (ephemeral) text of the CREATE TABLE + ** statement */ + pTab->pCheck = sqlite3ExprAnd(pTab->pCheck, sqlite3ExprDup(pCheckExpr)); + } +#endif + sqlite3ExprDelete(pCheckExpr); +} /* ** Set the collation function of the most recently parsed table column ** to the CollSeq given. */ @@ -1100,11 +1218,11 @@ ** another error occurs, NULL is returned and an error message written into ** pParse. */ CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){ sqlite3 *db = pParse->db; - u8 enc = db->enc; + u8 enc = ENC(db); u8 initbusy = db->init.busy; CollSeq *pColl = sqlite3FindCollSeq(db, enc, zName, nName, initbusy); if( !initbusy && (!pColl || !pColl->xCmp) ){ pColl = sqlite3GetCollSeq(db, pColl, zName, nName); @@ -1136,11 +1254,11 @@ ** set back to prior value. But schema changes are infrequent ** and the probability of hitting the same cookie value is only ** 1 chance in 2^32. So we're safe enough. */ void sqlite3ChangeCookie(sqlite3 *db, Vdbe *v, int iDb){ - sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].schema_cookie+1, 0); + sqlite3VdbeAddOp(v, OP_Integer, db->aDb[iDb].pSchema->schema_cookie+1, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0); } /* ** Measure the number of characters needed to output the given @@ -1184,11 +1302,11 @@ /* ** Generate a CREATE TABLE statement appropriate for the given ** table. Memory to hold the text of the statement is obtained ** from sqliteMalloc() and must be freed by the calling function. */ -static char *createTableStmt(Table *p){ +static char *createTableStmt(Table *p, int isTemp){ int i, k, n; char *zStmt; char *zSep, *zSep2, *zEnd, *z; Column *pCol; n = 0; @@ -1210,11 +1328,11 @@ zEnd = "\n)"; } n += 35 + 6*p->nCol; zStmt = sqliteMallocRaw( n ); if( zStmt==0 ) return 0; - strcpy(zStmt, !OMIT_TEMPDB&&p->iDb==1 ? "CREATE TEMP TABLE ":"CREATE TABLE "); + strcpy(zStmt, !OMIT_TEMPDB&&isTemp ? "CREATE TEMP TABLE ":"CREATE TABLE "); k = strlen(zStmt); identPut(zStmt, &k, p->zName); zStmt[k++] = '('; for(pCol=p->aCol, i=0; inCol; i++, pCol++){ strcpy(&zStmt[k], zSep); @@ -1257,16 +1375,44 @@ Token *pEnd, /* The final ')' token in the CREATE TABLE */ Select *pSelect /* Select from a "CREATE ... AS SELECT" */ ){ Table *p; sqlite3 *db = pParse->db; + int iDb; - if( (pEnd==0 && pSelect==0) || pParse->nErr || sqlite3_malloc_failed ) return; + if( (pEnd==0 && pSelect==0) || + pParse->nErr || sqlite3ThreadData()->mallocFailed ) { + return; + } p = pParse->pNewTable; if( p==0 ) return; assert( !db->init.busy || !pSelect ); + + iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); + +#ifndef SQLITE_OMIT_CHECK + /* Resolve names in all CHECK constraint expressions. + */ + if( p->pCheck ){ + SrcList sSrc; /* Fake SrcList for pParse->pNewTable */ + NameContext sNC; /* Name context for pParse->pNewTable */ + + memset(&sNC, 0, sizeof(sNC)); + memset(&sSrc, 0, sizeof(sSrc)); + sSrc.nSrc = 1; + sSrc.a[0].zName = p->zName; + sSrc.a[0].pTab = p; + sSrc.a[0].iCursor = -1; + sNC.pParse = pParse; + sNC.pSrcList = &sSrc; + sNC.isCheck = 1; + if( sqlite3ExprResolveNames(&sNC, p->pCheck) ){ + return; + } + } +#endif /* !defined(SQLITE_OMIT_CHECK) */ /* If the db->init.busy is 1 it means we are reading the SQL off the ** "sqlite_master" or "sqlite_temp_master" table on the disk. ** So do not write to the disk again. Extract the root page number ** for the table from the db->init.newTnum field. (The page number @@ -1316,15 +1462,20 @@ ** new table is on the top of the vdbe stack. ** ** Once the SELECT has been coded by sqlite3Select(), it is in a ** suitable state to query for the column names and types to be used ** by the new table. + ** + ** A shared-cache write-lock is not required to write to the new table, + ** as a schema-lock must have already been obtained to create it. Since + ** a schema-lock excludes all other database users, the write-lock would + ** be redundant. */ if( pSelect ){ Table *pSelTab; sqlite3VdbeAddOp(v, OP_Dup, 0, 0); - sqlite3VdbeAddOp(v, OP_Integer, p->iDb, 0); + sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeAddOp(v, OP_OpenWrite, 1, 0); pParse->nTab = 2; sqlite3Select(pParse, pSelect, SRT_Table, 1, 0, 0, 0, 0); sqlite3VdbeAddOp(v, OP_Close, 1, 0); if( pParse->nErr==0 ){ @@ -1339,11 +1490,11 @@ } } /* Compute the complete text of the CREATE statement */ if( pSelect ){ - zStmt = createTableStmt(p); + zStmt = createTableStmt(p, p->pSchema==pParse->db->aDb[1].pSchema); }else{ n = pEnd->z - pParse->sNameToken.z + 1; zStmt = sqlite3MPrintf("CREATE %s %.*s", zType2, n, pParse->sNameToken.z); } @@ -1355,56 +1506,56 @@ */ sqlite3NestedParse(pParse, "UPDATE %Q.%s " "SET type='%s', name=%Q, tbl_name=%Q, rootpage=#0, sql=%Q " "WHERE rowid=#1", - db->aDb[p->iDb].zName, SCHEMA_TABLE(p->iDb), + db->aDb[iDb].zName, SCHEMA_TABLE(iDb), zType, p->zName, p->zName, zStmt ); sqliteFree(zStmt); - sqlite3ChangeCookie(db, v, p->iDb); + sqlite3ChangeCookie(db, v, iDb); #ifndef SQLITE_OMIT_AUTOINCREMENT /* Check to see if we need to create an sqlite_sequence table for ** keeping track of autoincrement keys. */ if( p->autoInc ){ - Db *pDb = &db->aDb[p->iDb]; - if( pDb->pSeqTab==0 ){ + Db *pDb = &db->aDb[iDb]; + if( pDb->pSchema->pSeqTab==0 ){ sqlite3NestedParse(pParse, "CREATE TABLE %Q.sqlite_sequence(name,seq)", pDb->zName ); } } #endif /* Reparse everything to update our internal data structures */ - sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0, + sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC); } /* Add the table to the in-memory representation of the database. */ if( db->init.busy && pParse->nErr==0 ){ Table *pOld; FKey *pFKey; - Db *pDb = &db->aDb[p->iDb]; - pOld = sqlite3HashInsert(&pDb->tblHash, p->zName, strlen(p->zName)+1, p); + Schema *pSchema = p->pSchema; + pOld = sqlite3HashInsert(&pSchema->tblHash, p->zName, strlen(p->zName)+1,p); if( pOld ){ assert( p==pOld ); /* Malloc must have failed inside HashInsert() */ return; } #ifndef SQLITE_OMIT_FOREIGN_KEY for(pFKey=p->pFKey; pFKey; pFKey=pFKey->pNextFrom){ int nTo = strlen(pFKey->zTo) + 1; - pFKey->pNextTo = sqlite3HashFind(&pDb->aFKey, pFKey->zTo, nTo); - sqlite3HashInsert(&pDb->aFKey, pFKey->zTo, nTo, pFKey); + pFKey->pNextTo = sqlite3HashFind(&pSchema->aFKey, pFKey->zTo, nTo); + sqlite3HashInsert(&pSchema->aFKey, pFKey->zTo, nTo, pFKey); } #endif pParse->pNewTable = 0; db->nTable++; db->flags |= SQLITE_InternChanges; @@ -1435,24 +1586,26 @@ int n; const unsigned char *z; Token sEnd; DbFixer sFix; Token *pName; + int iDb; if( pParse->nVar>0 ){ sqlite3ErrorMsg(pParse, "parameters are not allowed in views"); sqlite3SelectDelete(pSelect); return; } - sqlite3StartTable(pParse, pBegin, pName1, pName2, isTemp, 1); + sqlite3StartTable(pParse, pBegin, pName1, pName2, isTemp, 1, 0); p = pParse->pNewTable; if( p==0 || pParse->nErr ){ sqlite3SelectDelete(pSelect); return; } sqlite3TwoPartName(pParse, pName1, pName2, &pName); - if( sqlite3FixInit(&sFix, pParse, p->iDb, "view", pName) + iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); + if( sqlite3FixInit(&sFix, pParse, iDb, "view", pName) && sqlite3FixSelect(&sFix, pSelect) ){ sqlite3SelectDelete(pSelect); return; } @@ -1462,10 +1615,13 @@ ** allocated rather than point to the input string - which means that ** they will persist after the current sqlite3_exec() call returns. */ p->pSelect = sqlite3SelectDup(pSelect); sqlite3SelectDelete(pSelect); + if( sqlite3ThreadData()->mallocFailed ){ + return; + } if( !pParse->db->init.busy ){ sqlite3ViewGetColumnNames(pParse, p); } /* Locate the end of the CREATE VIEW statement. Make sEnd point to @@ -1532,28 +1688,32 @@ ** to be permanent. So the computation is done on a copy of the SELECT ** statement that defines the view. */ assert( pTable->pSelect ); pSel = sqlite3SelectDup(pTable->pSelect); - n = pParse->nTab; - sqlite3SrcListAssignCursors(pParse, pSel->pSrc); - pTable->nCol = -1; - pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel); - pParse->nTab = n; - if( pSelTab ){ - assert( pTable->aCol==0 ); - pTable->nCol = pSelTab->nCol; - pTable->aCol = pSelTab->aCol; - pSelTab->nCol = 0; - pSelTab->aCol = 0; - sqlite3DeleteTable(0, pSelTab); - DbSetProperty(pParse->db, pTable->iDb, DB_UnresetViews); - }else{ - pTable->nCol = 0; + if( pSel ){ + n = pParse->nTab; + sqlite3SrcListAssignCursors(pParse, pSel->pSrc); + pTable->nCol = -1; + pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSel); + pParse->nTab = n; + if( pSelTab ){ + assert( pTable->aCol==0 ); + pTable->nCol = pSelTab->nCol; + pTable->aCol = pSelTab->aCol; + pSelTab->nCol = 0; + pSelTab->aCol = 0; + sqlite3DeleteTable(0, pSelTab); + pTable->pSchema->flags |= DB_UnresetViews; + }else{ + pTable->nCol = 0; + nErr++; + } + sqlite3SelectDelete(pSel); + } else { nErr++; } - sqlite3SelectDelete(pSel); return nErr; } #endif /* SQLITE_OMIT_VIEW */ #ifndef SQLITE_OMIT_VIEW @@ -1561,11 +1721,11 @@ ** Clear the column names from every VIEW in database idx. */ static void sqliteViewResetAll(sqlite3 *db, int idx){ HashElem *i; if( !DbHasProperty(db, idx, DB_UnresetViews) ) return; - for(i=sqliteHashFirst(&db->aDb[idx].tblHash); i; i=sqliteHashNext(i)){ + for(i=sqliteHashFirst(&db->aDb[idx].pSchema->tblHash); i;i=sqliteHashNext(i)){ Table *pTab = sqliteHashData(i); if( pTab->pSelect ){ sqliteResetColumnNames(pTab); } } @@ -1582,19 +1742,22 @@ ** to iTo. */ #ifndef SQLITE_OMIT_AUTOVACUUM void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){ HashElem *pElem; - - for(pElem=sqliteHashFirst(&pDb->tblHash); pElem; pElem=sqliteHashNext(pElem)){ + Hash *pHash; + + pHash = &pDb->pSchema->tblHash; + for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ Table *pTab = sqliteHashData(pElem); if( pTab->tnum==iFrom ){ pTab->tnum = iTo; return; } } - for(pElem=sqliteHashFirst(&pDb->idxHash); pElem; pElem=sqliteHashNext(pElem)){ + pHash = &pDb->pSchema->idxHash; + for(pElem=sqliteHashFirst(pHash); pElem; pElem=sqliteHashNext(pElem)){ Index *pIdx = sqliteHashData(pElem); if( pIdx->tnum==iFrom ){ pIdx->tnum = iTo; return; } @@ -1634,13 +1797,14 @@ ** is also added (this can happen with an auto-vacuum database). */ static void destroyTable(Parse *pParse, Table *pTab){ #ifdef SQLITE_OMIT_AUTOVACUUM Index *pIdx; - destroyRootPage(pParse, pTab->tnum, pTab->iDb); + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + destroyRootPage(pParse, pTab->tnum, iDb); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - destroyRootPage(pParse, pIdx->tnum, pIdx->iDb); + destroyRootPage(pParse, pIdx->tnum, iDb); } #else /* If the database may be auto-vacuum capable (if SQLITE_OMIT_AUTOVACUUM ** is not defined), then it is important to call OP_Destroy on the ** table and index root-pages in order, starting with the numerically @@ -1667,44 +1831,53 @@ if( iDestroyed==0 || iTabpIndex; pIdx; pIdx=pIdx->pNext){ int iIdx = pIdx->tnum; - assert( pIdx->iDb==pTab->iDb ); + assert( pIdx->pSchema==pTab->pSchema ); if( (iDestroyed==0 || (iIdxiLargest ){ iLargest = iIdx; } } - if( iLargest==0 ) return; - destroyRootPage(pParse, iLargest, pTab->iDb); - iDestroyed = iLargest; + if( iLargest==0 ){ + return; + }else{ + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + destroyRootPage(pParse, iLargest, iDb); + iDestroyed = iLargest; + } } #endif } /* ** This routine is called to do the work of a DROP TABLE statement. ** pName is the name of the table to be dropped. */ -void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){ +void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){ Table *pTab; Vdbe *v; sqlite3 *db = pParse->db; int iDb; - if( pParse->nErr || sqlite3_malloc_failed ) goto exit_drop_table; + if( pParse->nErr || sqlite3ThreadData()->mallocFailed ) goto exit_drop_table; assert( pName->nSrc==1 ); pTab = sqlite3LocateTable(pParse, pName->a[0].zName, pName->a[0].zDatabase); - if( pTab==0 ) goto exit_drop_table; - iDb = pTab->iDb; + if( pTab==0 ){ + if( noErr ){ + sqlite3ErrorClear(pParse); + } + goto exit_drop_table; + } + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 && iDbnDb ); #ifndef SQLITE_OMIT_AUTHORIZATION { int code; - const char *zTab = SCHEMA_TABLE(pTab->iDb); - const char *zDb = db->aDb[pTab->iDb].zName; + const char *zTab = SCHEMA_TABLE(iDb); + const char *zDb = db->aDb[iDb].zName; if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb)){ goto exit_drop_table; } if( isView ){ if( !OMIT_TEMPDB && iDb==1 ){ @@ -1725,11 +1898,11 @@ if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ goto exit_drop_table; } } #endif - if( pTab->readOnly || pTab==db->aDb[iDb].pSeqTab ){ + if( pTab->readOnly || pTab==db->aDb[iDb].pSchema->pSeqTab ){ sqlite3ErrorMsg(pParse, "table %s may not be dropped", pTab->zName); goto exit_drop_table; } #ifndef SQLITE_OMIT_VIEW @@ -1750,21 +1923,21 @@ ** on disk. */ v = sqlite3GetVdbe(pParse); if( v ){ Trigger *pTrigger; - int iDb = pTab->iDb; Db *pDb = &db->aDb[iDb]; sqlite3BeginWriteOperation(pParse, 0, iDb); /* Drop all triggers associated with the table being dropped. Code ** is generated to remove entries from sqlite_master and/or ** sqlite_temp_master if required. */ pTrigger = pTab->pTrigger; while( pTrigger ){ - assert( pTrigger->iDb==iDb || pTrigger->iDb==1 ); + assert( pTrigger->pSchema==pTab->pSchema || + pTrigger->pSchema==db->aDb[1].pSchema ); sqlite3DropTriggerPtr(pParse, pTrigger, 1); pTrigger = pTrigger->pNext; } #ifndef SQLITE_OMIT_AUTOINCREMENT @@ -1956,14 +2129,15 @@ int iTab = pParse->nTab; /* Btree cursor used for pTab */ int iIdx = pParse->nTab+1; /* Btree cursor used for pIndex */ int addr1; /* Address of top of loop */ int tnum; /* Root page of index */ Vdbe *v; /* Generate code into this virtual machine */ + int iDb = sqlite3SchemaToIndex(pParse->db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqlite3AuthCheck(pParse, SQLITE_REINDEX, pIndex->zName, 0, - pParse->db->aDb[pIndex->iDb].zName ) ){ + pParse->db->aDb[iDb].zName ) ){ return; } #endif /* Ensure all the required collation sequences are available. This @@ -1972,23 +2146,26 @@ */ if( sqlite3CheckIndexCollSeq(pParse, pIndex) ){ return; } + /* Require a write-lock on the table to perform this operation */ + sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); + v = sqlite3GetVdbe(pParse); if( v==0 ) return; if( memRootPage>=0 ){ sqlite3VdbeAddOp(v, OP_MemLoad, memRootPage, 0); tnum = 0; }else{ tnum = pIndex->tnum; - sqlite3VdbeAddOp(v, OP_Clear, tnum, pIndex->iDb); + sqlite3VdbeAddOp(v, OP_Clear, tnum, iDb); } - sqlite3VdbeAddOp(v, OP_Integer, pIndex->iDb, 0); + sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeOp3(v, OP_OpenWrite, iIdx, tnum, (char*)&pIndex->keyInfo, P3_KEYINFO); - sqlite3OpenTableForReading(v, iTab, pTab); + sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0); sqlite3GenerateIndexKey(v, pIndex, iTab); if( pIndex->onError!=OE_None ){ int curaddr = sqlite3VdbeCurrentAddr(v); int addr2 = curaddr+4; @@ -2025,24 +2202,31 @@ Token *pName2, /* Second part of index name. May be NULL */ SrcList *pTblName, /* Table to index. Use pParse->pNewTable if 0 */ ExprList *pList, /* A list of columns to be indexed */ int onError, /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ Token *pStart, /* The CREATE token that begins a CREATE TABLE statement */ - Token *pEnd /* The ")" that closes the CREATE INDEX statement */ + Token *pEnd, /* The ")" that closes the CREATE INDEX statement */ + int sortOrder, /* Sort order of primary key when pList==NULL */ + int ifNotExist /* Omit error if index already exists */ ){ - Table *pTab = 0; /* Table to be indexed */ - Index *pIndex = 0; /* The index to be created */ - char *zName = 0; + Table *pTab = 0; /* Table to be indexed */ + Index *pIndex = 0; /* The index to be created */ + char *zName = 0; /* Name of the index */ + int nName; /* Number of characters in zName */ int i, j; - Token nullId; /* Fake token for an empty ID list */ - DbFixer sFix; /* For assigning database names to pTable */ + Token nullId; /* Fake token for an empty ID list */ + DbFixer sFix; /* For assigning database names to pTable */ + int sortOrderMask; /* 1 to honor DESC in index. 0 to ignore. */ sqlite3 *db = pParse->db; - - int iDb; /* Index of the database that is being written */ - Token *pName = 0; /* Unqualified name of the index to create */ + Db *pDb; /* The specific table containing the indexed database */ + int iDb; /* Index of the database that is being written */ + Token *pName = 0; /* Unqualified name of the index to create */ + struct ExprList_item *pListItem; /* For looping over pList */ - if( pParse->nErr || sqlite3_malloc_failed ) goto exit_create_index; + if( pParse->nErr || sqlite3ThreadData()->mallocFailed ){ + goto exit_create_index; + } /* ** Find the table that is to be indexed. Return early if not found. */ if( pTblName!=0 ){ @@ -2058,11 +2242,11 @@ #ifndef SQLITE_OMIT_TEMPDB /* If the index name was unqualified, check if the the table ** is a temp table. If so, set the database to 1. */ pTab = sqlite3SrcListLookup(pParse, pTblName); - if( pName2 && pName2->n==0 && pTab && pTab->iDb==1 ){ + if( pName2 && pName2->n==0 && pTab && pTab->pSchema==db->aDb[1].pSchema ){ iDb = 1; } #endif if( sqlite3FixInit(&sFix, pParse, iDb, "index", pName) && @@ -2073,16 +2257,18 @@ assert(0); } pTab = sqlite3LocateTable(pParse, pTblName->a[0].zName, pTblName->a[0].zDatabase); if( !pTab ) goto exit_create_index; - assert( iDb==pTab->iDb ); + assert( db->aDb[iDb].pSchema==pTab->pSchema ); }else{ assert( pName==0 ); - pTab = pParse->pNewTable; - iDb = pTab->iDb; + pTab = pParse->pNewTable; + if( !pTab ) goto exit_create_index; + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); } + pDb = &db->aDb[iDb]; if( pTab==0 || pParse->nErr ) goto exit_create_index; if( pTab->readOnly ){ sqlite3ErrorMsg(pParse, "table %s may not be indexed", pTab->zName); goto exit_create_index; @@ -2114,12 +2300,14 @@ if( SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){ goto exit_create_index; } if( !db->init.busy ){ if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index; - if( sqlite3FindIndex(db, zName, db->aDb[iDb].zName)!=0 ){ - sqlite3ErrorMsg(pParse, "index %s already exists", zName); + if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){ + if( !ifNotExist ){ + sqlite3ErrorMsg(pParse, "index %s already exists", zName); + } goto exit_create_index; } if( sqlite3FindTable(db, zName, 0)!=0 ){ sqlite3ErrorMsg(pParse, "there is already a table named %s", zName); goto exit_create_index; @@ -2138,11 +2326,11 @@ /* Check for authorization to create an index. */ #ifndef SQLITE_OMIT_AUTHORIZATION { - const char *zDb = db->aDb[iDb].zName; + const char *zDb = pDb->zName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(iDb), 0, zDb) ){ goto exit_create_index; } i = SQLITE_CREATE_INDEX; if( !OMIT_TEMPDB && iDb==1 ) i = SQLITE_CREATE_TEMP_INDEX; @@ -2155,58 +2343,74 @@ /* If pList==0, it means this routine was called to make a primary ** key out of the last column added to the table under construction. ** So create a fake list to simulate this. */ if( pList==0 ){ - nullId.z = pTab->aCol[pTab->nCol-1].zName; - nullId.n = strlen(nullId.z); + nullId.z = (u8*)pTab->aCol[pTab->nCol-1].zName; + nullId.n = strlen((char*)nullId.z); pList = sqlite3ExprListAppend(0, 0, &nullId); if( pList==0 ) goto exit_create_index; + pList->a[0].sortOrder = sortOrder; } /* ** Allocate the index structure. */ - pIndex = sqliteMalloc( sizeof(Index) + strlen(zName) + 1 + sizeof(int) + - (sizeof(int)*2 + sizeof(CollSeq*))*pList->nExpr ); - if( sqlite3_malloc_failed ) goto exit_create_index; + nName = strlen(zName); + pIndex = sqliteMalloc( sizeof(Index) + nName + 2 + sizeof(int) + + (sizeof(int)*2 + sizeof(CollSeq*) + 1)*pList->nExpr ); + if( sqlite3ThreadData()->mallocFailed ) goto exit_create_index; pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr]; pIndex->aiRowEst = (unsigned*)&pIndex->aiColumn[pList->nExpr]; pIndex->zName = (char*)&pIndex->aiRowEst[pList->nExpr+1]; + pIndex->keyInfo.aSortOrder = &pIndex->zName[nName+1]; strcpy(pIndex->zName, zName); pIndex->pTable = pTab; pIndex->nColumn = pList->nExpr; pIndex->onError = onError; pIndex->autoIndex = pName==0; - pIndex->iDb = iDb; + pIndex->pSchema = db->aDb[iDb].pSchema; + + /* Check to see if we should honor DESC requests on index columns + */ + if( pDb->pSchema->file_format>=4 ){ + sortOrderMask = -1; /* Honor DESC */ + }else{ + sortOrderMask = 0; /* Ignore DESC */ + } /* Scan the names of the columns of the table to be indexed and ** load the column indices into the Index structure. Report an error ** if any column is not found. */ - for(i=0; inExpr; i++){ - for(j=0; jnCol; j++){ - if( sqlite3StrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break; + for(i=0, pListItem=pList->a; inExpr; i++, pListItem++){ + const char *zColName = pListItem->zName; + Column *pTabCol; + int requestedSortOrder; + for(j=0, pTabCol=pTab->aCol; jnCol; j++, pTabCol++){ + if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break; } if( j>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "table %s has no column named %s", - pTab->zName, pList->a[i].zName); + pTab->zName, zColName); goto exit_create_index; } pIndex->aiColumn[i] = j; - if( pList->a[i].pExpr ){ - assert( pList->a[i].pExpr->pColl ); - pIndex->keyInfo.aColl[i] = pList->a[i].pExpr->pColl; + if( pListItem->pExpr ){ + assert( pListItem->pExpr->pColl ); + pIndex->keyInfo.aColl[i] = pListItem->pExpr->pColl; }else{ pIndex->keyInfo.aColl[i] = pTab->aCol[j].pColl; } assert( pIndex->keyInfo.aColl[i] ); if( !db->init.busy && sqlite3CheckCollSeq(pParse, pIndex->keyInfo.aColl[i]) ){ goto exit_create_index; } + requestedSortOrder = pListItem->sortOrder & sortOrderMask; + pIndex->keyInfo.aSortOrder[i] = requestedSortOrder; } pIndex->keyInfo.nField = pList->nExpr; sqlite3DefaultRowEst(pIndex); if( pTab==pParse->pNewTable ){ @@ -2232,10 +2436,11 @@ if( pIdx->nColumn!=pIndex->nColumn ) continue; for(k=0; knColumn; k++){ if( pIdx->aiColumn[k]!=pIndex->aiColumn[k] ) break; if( pIdx->keyInfo.aColl[k]!=pIndex->keyInfo.aColl[k] ) break; + if( pIdx->keyInfo.aSortOrder[k]!=pIndex->keyInfo.aSortOrder[k] ) break; } if( k==pIdx->nColumn ){ if( pIdx->onError!=pIndex->onError ){ /* This constraint creates the same index as a previous ** constraint specified somewhere in the CREATE TABLE statement. @@ -2260,11 +2465,11 @@ /* Link the new Index structure to its table and to the other ** in-memory database structures. */ if( db->init.busy ){ Index *p; - p = sqlite3HashInsert(&db->aDb[pIndex->iDb].idxHash, + p = sqlite3HashInsert(&pIndex->pSchema->idxHash, pIndex->zName, strlen(pIndex->zName)+1, pIndex); if( p ){ assert( p==pIndex ); /* Malloc must have failed */ goto exit_create_index; } @@ -2294,10 +2499,11 @@ char *zStmt; int iMem = pParse->nMem++; v = sqlite3GetVdbe(pParse); if( v==0 ) goto exit_create_index; + /* Create the rootpage for the index */ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3VdbeAddOp(v, OP_CreateIndex, iDb, 0); @@ -2371,10 +2577,26 @@ sqlite3ExprListDelete(pList); sqlite3SrcListDelete(pTblName); sqliteFree(zName); return; } + +/* +** Generate code to make sure the file format number is at least minFormat. +** The generated code will increase the file format number if necessary. +*/ +void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){ + Vdbe *v; + v = sqlite3GetVdbe(pParse); + if( v ){ + sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 1); + sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0); + sqlite3VdbeAddOp(v, OP_Ge, 0, sqlite3VdbeCurrentAddr(v)+3); + sqlite3VdbeAddOp(v, OP_Integer, minFormat, 0); + sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 1); + } +} /* ** Fill the Index.aiRowEst[] array with default information - information ** to be used when we have not run the ANALYZE command. ** @@ -2407,53 +2629,56 @@ /* ** This routine will drop an existing named index. This routine ** implements the DROP INDEX statement. */ -void sqlite3DropIndex(Parse *pParse, SrcList *pName){ +void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ Index *pIndex; Vdbe *v; sqlite3 *db = pParse->db; + int iDb; - if( pParse->nErr || sqlite3_malloc_failed ){ + if( pParse->nErr || sqlite3ThreadData()->mallocFailed ){ goto exit_drop_index; } assert( pName->nSrc==1 ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_drop_index; } pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); if( pIndex==0 ){ - sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); + if( !ifExists ){ + sqlite3ErrorMsg(pParse, "no such index: %S", pName, 0); + } pParse->checkSchema = 1; goto exit_drop_index; } if( pIndex->autoIndex ){ sqlite3ErrorMsg(pParse, "index associated with UNIQUE " "or PRIMARY KEY constraint cannot be dropped", 0); goto exit_drop_index; } + iDb = sqlite3SchemaToIndex(db, pIndex->pSchema); #ifndef SQLITE_OMIT_AUTHORIZATION { int code = SQLITE_DROP_INDEX; Table *pTab = pIndex->pTable; - const char *zDb = db->aDb[pIndex->iDb].zName; - const char *zTab = SCHEMA_TABLE(pIndex->iDb); + const char *zDb = db->aDb[iDb].zName; + const char *zTab = SCHEMA_TABLE(iDb); if( sqlite3AuthCheck(pParse, SQLITE_DELETE, zTab, 0, zDb) ){ goto exit_drop_index; } - if( !OMIT_TEMPDB && pIndex->iDb ) code = SQLITE_DROP_TEMP_INDEX; + if( !OMIT_TEMPDB && iDb ) code = SQLITE_DROP_TEMP_INDEX; if( sqlite3AuthCheck(pParse, code, pIndex->zName, pTab->zName, zDb) ){ goto exit_drop_index; } } #endif /* Generate code to remove the index and from the master table */ v = sqlite3GetVdbe(pParse); if( v ){ - int iDb = pIndex->iDb; sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE name=%Q", db->aDb[iDb].zName, SCHEMA_TABLE(iDb), pIndex->zName ); @@ -2619,15 +2844,18 @@ ** Assign cursors to all tables in a SrcList */ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){ int i; struct SrcList_item *pItem; - for(i=0, pItem=pList->a; inSrc; i++, pItem++){ - if( pItem->iCursor>=0 ) break; - pItem->iCursor = pParse->nTab++; - if( pItem->pSelect ){ - sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); + assert(pList || sqlite3ThreadData()->mallocFailed); + if( pList ){ + for(i=0, pItem=pList->a; inSrc; i++, pItem++){ + if( pItem->iCursor>=0 ) break; + pItem->iCursor = pParse->nTab++; + if( pItem->pSelect ){ + sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); + } } } } /* @@ -2665,11 +2893,11 @@ sqlite3 *db; Vdbe *v; int i; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3_malloc_failed ) return; + if( pParse->nErr || sqlite3ThreadData()->mallocFailed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "BEGIN", 0, 0) ) return; v = sqlite3GetVdbe(pParse); if( !v ) return; if( type!=TK_DEFERRED ){ @@ -2686,11 +2914,11 @@ void sqlite3CommitTransaction(Parse *pParse){ sqlite3 *db; Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3_malloc_failed ) return; + if( pParse->nErr || sqlite3ThreadData()->mallocFailed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "COMMIT", 0, 0) ) return; v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 0); @@ -2703,11 +2931,11 @@ void sqlite3RollbackTransaction(Parse *pParse){ sqlite3 *db; Vdbe *v; if( pParse==0 || (db=pParse->db)==0 || db->aDb[0].pBt==0 ) return; - if( pParse->nErr || sqlite3_malloc_failed ) return; + if( pParse->nErr || sqlite3ThreadData()->mallocFailed ) return; if( sqlite3AuthCheck(pParse, SQLITE_TRANSACTION, "ROLLBACK", 0, 0) ) return; v = sqlite3GetVdbe(pParse); if( v ){ sqlite3VdbeAddOp(v, OP_AutoCommit, 1, 1); @@ -2735,10 +2963,11 @@ "the temporary database file"); pParse->rc = rc; return 1; } } + assert( db->aDb[1].pSchema ); } return 0; } /* @@ -2779,11 +3008,11 @@ assert( db->aDb[iDb].pBt!=0 || iDb==1 ); assert( iDb<32 ); mask = 1<cookieMask & mask)==0 ){ pParse->cookieMask |= mask; - pParse->cookieValue[iDb] = db->aDb[iDb].schema_cookie; + pParse->cookieValue[iDb] = db->aDb[iDb].pSchema->schema_cookie; if( !OMIT_TEMPDB && iDb==1 ){ sqlite3OpenTempDatabase(pParse); } } } @@ -2844,11 +3073,12 @@ static void reindexTable(Parse *pParse, Table *pTab, CollSeq *pColl){ Index *pIndex; /* An index associated with pTab */ for(pIndex=pTab->pIndex; pIndex; pIndex=pIndex->pNext){ if( pColl==0 || collationMatch(pColl,pIndex) ){ - sqlite3BeginWriteOperation(pParse, 0, pTab->iDb); + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3RefillIndex(pParse, pIndex, -1); } } } #endif @@ -2866,11 +3096,11 @@ HashElem *k; /* For looping over tables in pDb */ Table *pTab; /* A table in the database */ for(iDb=0, pDb=db->aDb; iDbnDb; iDb++, pDb++){ if( pDb==0 ) continue; - for(k=sqliteHashFirst(&pDb->tblHash); k; k=sqliteHashNext(k)){ + for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){ pTab = (Table*)sqliteHashData(k); reindexTable(pParse, pTab, pColl); } } } @@ -2908,11 +3138,11 @@ if( pName1==0 || pName1->z==0 ){ reindexDatabases(pParse, 0); return; }else if( pName2==0 || pName2->z==0 ){ - pColl = sqlite3FindCollSeq(db, db->enc, pName1->z, pName1->n, 0); + pColl = sqlite3FindCollSeq(db, ENC(db), (char*)pName1->z, pName1->n, 0); if( pColl ){ reindexDatabases(pParse, pColl); return; } } Index: SQLite.Interop/src/callback.c ================================================================== --- SQLite.Interop/src/callback.c +++ SQLite.Interop/src/callback.c @@ -11,11 +11,11 @@ ************************************************************************* ** ** This file contains functions used to access the internal hash tables ** of user defined functions and collation sequences. ** -** $Id: callback.c,v 1.6 2005/12/19 17:57:46 rmsimpson Exp $ +** $Id: callback.c,v 1.7 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" /* @@ -27,21 +27,23 @@ assert( !db->xCollNeeded || !db->xCollNeeded16 ); if( nName<0 ) nName = strlen(zName); if( db->xCollNeeded ){ char *zExternal = sqliteStrNDup(zName, nName); if( !zExternal ) return; - db->xCollNeeded(db->pCollNeededArg, db, (int)db->enc, zExternal); + db->xCollNeeded(db->pCollNeededArg, db, (int)ENC(db), zExternal); sqliteFree(zExternal); } #ifndef SQLITE_OMIT_UTF16 if( db->xCollNeeded16 ){ char const *zExternal; - sqlite3_value *pTmp = sqlite3GetTransientValue(db); - sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF8, SQLITE_STATIC); + sqlite3_value *pTmp = sqlite3ValueNew(); + sqlite3ValueSetStr(pTmp, nName, zName, SQLITE_UTF8, SQLITE_STATIC); zExternal = sqlite3ValueText(pTmp, SQLITE_UTF16NATIVE); - if( !zExternal ) return; - db->xCollNeeded16(db->pCollNeededArg, db, (int)db->enc, zExternal); + if( zExternal ){ + db->xCollNeeded16(db->pCollNeededArg, db, (int)ENC(db), zExternal); + } + sqlite3ValueFree(pTmp); } #endif } /* @@ -88,18 +90,18 @@ ){ CollSeq *p; p = pColl; if( !p ){ - p = sqlite3FindCollSeq(db, db->enc, zName, nName, 0); + p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0); } if( !p || !p->xCmp ){ /* No collation sequence of this type for this encoding is registered. ** Call the collation factory to see if it can supply us with one. */ callCollNeeded(db, zName, nName); - p = sqlite3FindCollSeq(db, db->enc, zName, nName, 0); + p = sqlite3FindCollSeq(db, ENC(db), zName, nName, 0); } if( p && !p->xCmp && synthCollSeq(db, p) ){ p = 0; } assert( !p || p->xCmp ); @@ -173,11 +175,11 @@ /* If a malloc() failure occured in sqlite3HashInsert(), it will ** return the pColl pointer to be deleted (because it wasn't added ** to the hash table). */ - assert( !pDel || (sqlite3_malloc_failed && pDel==pColl) ); + assert( !pDel || (sqlite3ThreadData()->mallocFailed && pDel==pColl) ); sqliteFree(pDel); } } return pColl; } @@ -284,11 +286,11 @@ /* If the createFlag parameter is true, and the seach did not reveal an ** exact match for the name, number of arguments and encoding, then add a ** new entry to the hash table and return it. */ if( createFlag && bestmatch<6 && - (pBest = sqliteMalloc(sizeof(*pBest)+nName)) ){ + (pBest = sqliteMalloc(sizeof(*pBest)+nName))!=0 ){ pBest->nArg = nArg; pBest->pNext = pFirst; pBest->iPrefEnc = enc; memcpy(pBest->zName, zName, nName); pBest->zName[nName] = 0; Index: SQLite.Interop/src/complete.c ================================================================== --- SQLite.Interop/src/complete.c +++ SQLite.Interop/src/complete.c @@ -14,11 +14,11 @@ ** This file contains C code that implements the sqlite3_complete() API. ** This code used to be part of the tokenizer.c source file. But by ** separating it out, the code will be automatically omitted from ** static links that do not use it. ** -** $Id: complete.c,v 1.4 2005/12/19 17:57:46 rmsimpson Exp $ +** $Id: complete.c,v 1.5 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_COMPLETE /* @@ -253,11 +253,14 @@ pVal = sqlite3ValueNew(); sqlite3ValueSetStr(pVal, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); zSql8 = sqlite3ValueText(pVal, SQLITE_UTF8); if( zSql8 ){ rc = sqlite3_complete(zSql8); + }else if( zSql ){ + rc = SQLITE_NOMEM; + sqlite3MallocClearFailed(); } sqlite3ValueFree(pVal); return rc; } #endif /* SQLITE_OMIT_UTF16 */ #endif /* SQLITE_OMIT_COMPLETE */ Index: SQLite.Interop/src/date.c ================================================================== --- SQLite.Interop/src/date.c +++ SQLite.Interop/src/date.c @@ -14,11 +14,11 @@ ** ** There is only one exported symbol in this file - the function ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: date.c,v 1.10 2005/12/19 17:57:46 rmsimpson Exp $ +** $Id: date.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ ** ** NOTES: ** ** SQLite processes all times and dates as Julian Day numbers. The ** dates and times are stored as the number of days since noon @@ -234,11 +234,11 @@ p->validJD = 1; p->validYMD = 0; if( p->validHMS ){ p->rJD += (p->h*3600.0 + p->m*60.0 + p->s)/86400.0; if( p->validTZ ){ - p->rJD += p->tz*60/86400.0; + p->rJD -= p->tz*60/86400.0; p->validHMS = 0; p->validTZ = 0; } } } @@ -637,14 +637,14 @@ */ static int isDate(int argc, sqlite3_value **argv, DateTime *p){ int i; if( argc==0 ) return 1; if( SQLITE_NULL==sqlite3_value_type(argv[0]) || - parseDateOrTime(sqlite3_value_text(argv[0]), p) ) return 1; + parseDateOrTime((char*)sqlite3_value_text(argv[0]), p) ) return 1; for(i=1; iiDb, 0); + Vdbe *v = sqlite3GetVdbe(p); + assert( opcode==OP_OpenWrite || opcode==OP_OpenRead ); + sqlite3TableLock(p, iDb, pTab->tnum, (opcode==OP_OpenWrite), pTab->zName); + sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); VdbeComment((v, "# %s", pTab->zName)); - sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); + sqlite3VdbeAddOp(v, opcode, iCur, pTab->tnum); sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } /* @@ -93,18 +98,19 @@ int iCur; /* VDBE Cursor number for pTab */ sqlite3 *db; /* Main database structure */ AuthContext sContext; /* Authorization context */ int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ NameContext sNC; /* Name context to resolve expressions in */ + int iDb; #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to delete from a view */ int triggers_exist = 0; /* True if any triggers exist */ #endif sContext.pParse = 0; - if( pParse->nErr || sqlite3_malloc_failed ){ + if( pParse->nErr || sqlite3ThreadData()->mallocFailed ){ goto delete_from_cleanup; } db = pParse->db; assert( pTabList->nSrc==1 ); @@ -132,12 +138,13 @@ #endif if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){ goto delete_from_cleanup; } - assert( pTab->iDbnDb ); - zDb = db->aDb[pTab->iDb].zName; + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iDbnDb ); + zDb = db->aDb[iDb].zName; if( sqlite3AuthCheck(pParse, SQLITE_DELETE, pTab->zName, 0, zDb) ){ goto delete_from_cleanup; } /* If pTab is really a view, make sure it has been initialized. @@ -174,11 +181,11 @@ v = sqlite3GetVdbe(pParse); if( v==0 ){ goto delete_from_cleanup; } if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); - sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb); + sqlite3BeginWriteOperation(pParse, triggers_exist, iDb); /* If we are trying to delete from a view, realize that view into ** a ephemeral table. */ if( isView ){ @@ -203,22 +210,26 @@ /* If counting rows deleted, just count the total number of ** entries in the table. */ int endOfLoop = sqlite3VdbeMakeLabel(v); int addr; if( !isView ){ - sqlite3OpenTableForReading(v, iCur, pTab); + sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); } sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2); addr = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); sqlite3VdbeAddOp(v, OP_Next, iCur, addr); sqlite3VdbeResolveLabel(v, endOfLoop); sqlite3VdbeAddOp(v, OP_Close, iCur, 0); } if( !isView ){ - sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, pTab->iDb); + sqlite3VdbeAddOp(v, OP_Clear, pTab->tnum, iDb); + if( !pParse->nested ){ + sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); + } for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ - sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, pIdx->iDb); + assert( pIdx->pSchema==pTab->pSchema ); + sqlite3VdbeAddOp(v, OP_Clear, pIdx->tnum, iDb); } } } /* The usual case: There is a WHERE clause so we have to scan through @@ -267,11 +278,11 @@ */ if( triggers_exist ){ addr = sqlite3VdbeAddOp(v, OP_FifoRead, 0, end); if( !isView ){ sqlite3VdbeAddOp(v, OP_Dup, 0, 0); - sqlite3OpenTableForReading(v, iCur, pTab); + sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead); } sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); sqlite3VdbeAddOp(v, OP_RowData, iCur, 0); sqlite3VdbeAddOp(v, OP_Insert, oldIdx, 0); @@ -378,10 +389,13 @@ ){ int addr; addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0); sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0); sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0)); + if( count ){ + sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); + } sqlite3VdbeJumpHere(v, addr); } /* ** This routine generates VDBE code that causes the deletion of all ADDED SQLite.Interop/src/experimental.c Index: SQLite.Interop/src/experimental.c ================================================================== --- /dev/null +++ SQLite.Interop/src/experimental.c @@ -0,0 +1,36 @@ +/* +** 2005 January 20 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** This file contains C code routines that are not a part of the official +** SQLite API. These routines are unsupported. +** +** $Id: experimental.c,v 1.1 2006/01/10 18:41:09 rmsimpson Exp $ +*/ +#include "sqliteInt.h" + +/* +** Set all the parameters in the compiled SQL statement to NULL. +*/ +int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ + int i; + int rc = SQLITE_OK; + for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){ + rc = sqlite3_bind_null(pStmt, i); + } + return rc; +} + +/* +** Sleep for a little while. Return the amount of time slept. +*/ +int sqlite3_sleep(int ms){ + return sqlite3OsSleep(ms); +} Index: SQLite.Interop/src/expr.c ================================================================== --- SQLite.Interop/src/expr.c +++ SQLite.Interop/src/expr.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.17 2005/12/19 17:57:46 rmsimpson Exp $ +** $Id: expr.c,v 1.18 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* @@ -73,25 +73,22 @@ ** type affinity that should be used for the comparison operator. */ char sqlite3CompareAffinity(Expr *pExpr, char aff2){ char aff1 = sqlite3ExprAffinity(pExpr); if( aff1 && aff2 ){ - /* Both sides of the comparison are columns. If one has numeric or - ** integer affinity, use that. Otherwise use no affinity. + /* Both sides of the comparison are columns. If one has numeric + ** affinity, use that. Otherwise use no affinity. */ - if( aff1==SQLITE_AFF_INTEGER || aff2==SQLITE_AFF_INTEGER ){ - return SQLITE_AFF_INTEGER; - }else if( aff1==SQLITE_AFF_NUMERIC || aff2==SQLITE_AFF_NUMERIC ){ + if( sqlite3IsNumericAffinity(aff1) || sqlite3IsNumericAffinity(aff2) ){ return SQLITE_AFF_NUMERIC; }else{ return SQLITE_AFF_NONE; } }else if( !aff1 && !aff2 ){ /* Neither side of the comparison is a column. Compare the ** results directly. */ - /* return SQLITE_AFF_NUMERIC; // Ticket #805 */ return SQLITE_AFF_NONE; }else{ /* One side is a column, the other is not. Use the columns affinity. */ assert( aff1==0 || aff2==0 ); return (aff1 + aff2); @@ -127,15 +124,18 @@ ** if the index with affinity idx_affinity may be used to implement ** the comparison in pExpr. */ int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity){ char aff = comparisonAffinity(pExpr); - return - (aff==SQLITE_AFF_NONE) || - (aff==SQLITE_AFF_NUMERIC && idx_affinity==SQLITE_AFF_INTEGER) || - (aff==SQLITE_AFF_INTEGER && idx_affinity==SQLITE_AFF_NUMERIC) || - (aff==idx_affinity); + switch( aff ){ + case SQLITE_AFF_NONE: + return 1; + case SQLITE_AFF_TEXT: + return idx_affinity==SQLITE_AFF_TEXT; + default: + return sqlite3IsNumericAffinity(idx_affinity); + } } /* ** Return the P1 value that should be used for a binary comparison ** opcode (OP_Eq, OP_Ge etc.) used to compare pExpr1 and pExpr2. @@ -233,11 +233,11 @@ if( v==0 ) return 0; p = sqlite3Expr(TK_REGISTER, 0, 0, pToken); if( p==0 ){ return 0; /* Malloc failed */ } - depth = atoi(&pToken->z[1]); + depth = atoi((char*)&pToken->z[1]); p->iTable = pParse->nMem++; sqlite3VdbeAddOp(v, OP_Dup, depth, 0); sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1); return p; } @@ -261,11 +261,11 @@ ** text between the two given tokens. */ void sqlite3ExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){ assert( pRight!=0 ); assert( pLeft!=0 ); - if( !sqlite3_malloc_failed && pRight->z && pLeft->z ){ + if( !sqlite3ThreadData()->mallocFailed && pRight->z && pLeft->z ){ assert( pLeft->dyn==0 || pLeft->z[pLeft->n]==0 ); if( pLeft->dyn==0 && pRight->dyn==0 ){ pExpr->span.z = pLeft->z; pExpr->span.n = pRight->n + (pRight->z - pLeft->z); }else{ @@ -325,11 +325,11 @@ pExpr->iTable = ++pParse->nVar; }else if( pToken->z[0]=='?' ){ /* Wildcard of the form "?nnn". Convert "nnn" to an integer and ** use it as the variable number */ int i; - pExpr->iTable = i = atoi(&pToken->z[1]); + pExpr->iTable = i = atoi((char*)&pToken->z[1]); if( i<1 || i>SQLITE_MAX_VARIABLE_NUMBER ){ sqlite3ErrorMsg(pParse, "variable number must be between ?1 and ?%d", SQLITE_MAX_VARIABLE_NUMBER); } if( i>pParse->nVar ){ @@ -356,11 +356,11 @@ if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){ pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10; sqlite3ReallocOrFree((void**)&pParse->apVarExpr, pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) ); } - if( !sqlite3_malloc_failed ){ + if( !sqlite3ThreadData()->mallocFailed ){ assert( pParse->apVarExpr!=0 ); pParse->apVarExpr[pParse->nVarExpr++] = pExpr; } } } @@ -413,11 +413,11 @@ if( p==0 ) return 0; pNew = sqliteMallocRaw( sizeof(*p) ); if( pNew==0 ) return 0; memcpy(pNew, p, sizeof(*pNew)); if( p->token.z!=0 ){ - pNew->token.z = sqliteStrNDup(p->token.z, p->token.n); + pNew->token.z = (u8*)sqliteStrNDup((char*)p->token.z, p->token.n); pNew->token.dyn = 1; }else{ assert( pNew->token.z==0 ); } pNew->span.z = 0; @@ -430,11 +430,11 @@ } void sqlite3TokenCopy(Token *pTo, Token *pFrom){ if( pTo->dyn ) sqliteFree((char*)pTo->z); if( pFrom->z ){ pTo->n = pFrom->n; - pTo->z = sqliteStrNDup(pFrom->z, pFrom->n); + pTo->z = (u8*)sqliteStrNDup((char*)pFrom->z, pFrom->n); pTo->dyn = 1; }else{ pTo->z = 0; } } @@ -460,11 +460,11 @@ ** expression list. The logic in SELECT processing that determines ** the names of columns in the result set needs this information */ sqlite3TokenCopy(&pNewExpr->span, &pOldExpr->span); } assert( pNewExpr==0 || pNewExpr->span.z!=0 - || pOldExpr->span.z==0 || sqlite3_malloc_failed ); + || pOldExpr->span.z==0 || sqlite3ThreadData()->mallocFailed ); pItem->zName = sqliteStrDup(pOldItem->zName); pItem->sortOrder = pOldItem->sortOrder; pItem->isAgg = pOldItem->isAgg; pItem->done = 0; } @@ -750,11 +750,11 @@ ** to fit in a signed 32-bit integer, return 0 and leave *pValue unchanged. */ int sqlite3ExprIsInteger(Expr *p, int *pValue){ switch( p->op ){ case TK_INTEGER: { - if( sqlite3GetInt32(p->token.z, pValue) ){ + if( sqlite3GetInt32((char*)p->token.z, pValue) ){ return 1; } break; } case TK_UPLUS: { @@ -807,11 +807,11 @@ ** ** If the name cannot be resolved unambiguously, leave an error message ** in pParse and return non-zero. Return zero on success. */ static int lookupName( - Parse *pParse, /* The parsing context */ + Parse *pParse, /* The parsing context */ Token *pDbToken, /* Name of the database containing table, or NULL */ Token *pTableToken, /* Name of table containing column, or NULL */ Token *pColumnToken, /* Name of the column. */ NameContext *pNC, /* The name context used to resolve the name */ Expr *pExpr /* Make this EXPR node point to the selected column */ @@ -829,23 +829,23 @@ assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */ zDb = sqlite3NameFromToken(pDbToken); zTab = sqlite3NameFromToken(pTableToken); zCol = sqlite3NameFromToken(pColumnToken); - if( sqlite3_malloc_failed ){ + if( sqlite3ThreadData()->mallocFailed ){ goto lookupname_end; } pExpr->iTable = -1; while( pNC && cnt==0 ){ + ExprList *pEList; SrcList *pSrcList = pNC->pSrcList; - ExprList *pEList = pNC->pEList; - /* assert( zTab==0 || pEList==0 ); */ if( pSrcList ){ for(i=0, pItem=pSrcList->a; inSrc; i++, pItem++){ Table *pTab = pItem->pTab; + int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); Column *pCol; if( pTab==0 ) continue; assert( pTab->nCol>0 ); if( zTab ){ @@ -853,27 +853,27 @@ char *zTabName = pItem->zAlias; if( sqlite3StrICmp(zTabName, zTab)!=0 ) continue; }else{ char *zTabName = pTab->zName; if( zTabName==0 || sqlite3StrICmp(zTabName, zTab)!=0 ) continue; - if( zDb!=0 && sqlite3StrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){ + if( zDb!=0 && sqlite3StrICmp(db->aDb[iDb].zName, zDb)!=0 ){ continue; } } } if( 0==(cntTab++) ){ pExpr->iTable = pItem->iCursor; - pExpr->iDb = pTab->iDb; + pExpr->pSchema = pTab->pSchema; pMatch = pItem; } for(j=0, pCol=pTab->aCol; jnCol; j++, pCol++){ if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ IdList *pUsing; cnt++; pExpr->iTable = pItem->iCursor; pMatch = pItem; - pExpr->iDb = pTab->iDb; + pExpr->pSchema = pTab->pSchema; /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */ pExpr->iColumn = j==pTab->iPKey ? -1 : j; pExpr->affinity = pTab->aCol[j].affinity; pExpr->pColl = pTab->aCol[j].pColl; if( pItem->jointype & JT_NATURAL ){ @@ -920,11 +920,11 @@ if( pTab ){ int j; Column *pCol = pTab->aCol; - pExpr->iDb = pTab->iDb; + pExpr->pSchema = pTab->pSchema; cntTab++; for(j=0; j < pTab->nCol; j++, pCol++) { if( sqlite3StrICmp(pCol->zName, zCol)==0 ){ cnt++; pExpr->iColumn = j==pTab->iPKey ? -1 : j; @@ -957,11 +957,11 @@ ** In cases like this, replace pExpr with a copy of the expression that ** forms the result set entry ("a+b" in the example) and return immediately. ** Note that the expression in the result set should have already been ** resolved by the time the WHERE clause is resolved. */ - if( cnt==0 && pEList!=0 && zTab==0 ){ + if( cnt==0 && (pEList = pNC->pEList)!=0 && zTab==0 ){ for(j=0; jnExpr; j++){ char *zAs = pEList->a[j].zName; if( zAs!=0 && sqlite3StrICmp(zAs, zCol)==0 ){ assert( pExpr->pLeft==0 && pExpr->pRight==0 ); pExpr->op = TK_AS; @@ -1004,13 +1004,13 @@ if( cnt!=1 ){ char *z = 0; char *zErr; zErr = cnt==0 ? "no such column: %s" : "ambiguous column name: %s"; if( zDb ){ - sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, 0); + sqlite3SetString(&z, zDb, ".", zTab, ".", zCol, (char*)0); }else if( zTab ){ - sqlite3SetString(&z, zTab, ".", zCol, 0); + sqlite3SetString(&z, zTab, ".", zCol, (char*)0); }else{ z = sqliteStrDup(zCol); } sqlite3ErrorMsg(pParse, zErr, z); sqliteFree(z); @@ -1086,11 +1086,11 @@ pParse = pNC->pParse; if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return 1; ExprSetProperty(pExpr, EP_Resolved); #ifndef NDEBUG - if( pSrcList ){ + if( pSrcList && pSrcList->nAlloc>0 ){ int i; for(i=0; inSrc; i++){ assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursornTab); } } @@ -1147,13 +1147,13 @@ int is_agg = 0; /* True if is an aggregate function */ int i; int nId; /* Number of characters in function name */ const char *zId; /* The function name. */ FuncDef *pDef; /* Information about the function */ - int enc = pParse->db->enc; /* The database encoding */ + int enc = ENC(pParse->db); /* The database encoding */ - zId = pExpr->token.z; + zId = (char*)pExpr->token.z; nId = pExpr->token.n; pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); if( pDef==0 ){ pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0); if( pDef==0 ){ @@ -1195,17 +1195,31 @@ case TK_EXISTS: #endif case TK_IN: { if( pExpr->pSelect ){ int nRef = pNC->nRef; +#ifndef SQLITE_OMIT_CHECK + if( pNC->isCheck ){ + sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints"); + } +#endif sqlite3SelectResolve(pParse, pExpr->pSelect, pNC); assert( pNC->nRef>=nRef ); if( nRef!=pNC->nRef ){ ExprSetProperty(pExpr, EP_VarSelect); } } + break; + } +#ifndef SQLITE_OMIT_CHECK + case TK_VARIABLE: { + if( pNC->isCheck ){ + sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints"); + } + break; } +#endif } return 0; } /* @@ -1259,21 +1273,20 @@ NameContext *pNC; /* Namespace of first enclosing query */ }; /* -** Generate code for subqueries and IN operators. -** -** IN operators comes in two forms: -** -** expr IN (exprlist) -** and -** expr IN (SELECT ...) -** -** The first form is handled by creating a set holding the list -** of allowed values. The second form causes the SELECT to generate -** a temporary table. +** Generate code for scalar subqueries used as an expression +** and IN operators. Examples: +** +** (SELECT a FROM b) -- subquery +** EXISTS (SELECT a FROM b) -- EXISTS subquery +** x IN (4,5,11) -- IN operator with list on right-hand side +** x IN (SELECT a FROM b) -- IN operator with subquery on the right +** +** The pExpr parameter describes the expression that contains the IN +** operator or subquery. */ #ifndef SQLITE_OMIT_SUBQUERY void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ int testAddr = 0; /* One-time test address */ Vdbe *v = sqlite3GetVdbe(pParse); @@ -1291,11 +1304,11 @@ */ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){ int mem = pParse->nMem++; sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0); testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0); - assert( testAddr>0 || sqlite3_malloc_failed ); + assert( testAddr>0 || sqlite3ThreadData()->mallocFailed ); sqlite3VdbeAddOp(v, OP_MemInt, 1, mem); } switch( pExpr->op ){ case TK_IN: { @@ -1388,25 +1401,29 @@ case TK_SELECT: { /* This has to be a scalar SELECT. Generate code to put the ** value of this select in a memory cell and record the number ** of the memory cell in iColumn. */ - int sop; + static const Token one = { (u8*)"1", 0, 1 }; Select *pSel; + int iMem; + int sop; - pExpr->iColumn = pParse->nMem++; + pExpr->iColumn = iMem = pParse->nMem++; pSel = pExpr->pSelect; if( pExpr->op==TK_SELECT ){ sop = SRT_Mem; + sqlite3VdbeAddOp(v, OP_MemNull, iMem, 0); + VdbeComment((v, "# Init subquery result")); }else{ - static const Token one = { "1", 0, 1 }; sop = SRT_Exists; - sqlite3ExprListDelete(pSel->pEList); - pSel->pEList = sqlite3ExprListAppend(0, - sqlite3Expr(TK_INTEGER, 0, 0, &one), 0); + sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem); + VdbeComment((v, "# Init EXISTS result")); } - sqlite3Select(pParse, pSel, sop, pExpr->iColumn, 0, 0, 0, 0); + sqlite3ExprDelete(pSel->pLimit); + pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one); + sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0); break; } } if( testAddr ){ @@ -1442,10 +1459,12 @@ ** below verify that the numbers are aligned correctly. */ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ Vdbe *v = pParse->pVdbe; int op; + int stackChng = 1; /* Amount of change to stack depth */ + if( v==0 ) return; if( pExpr==0 ){ sqlite3VdbeAddOp(v, OP_Null, 0, 0); return; } @@ -1463,28 +1482,39 @@ break; } /* Otherwise, fall thru into the TK_COLUMN case */ } case TK_COLUMN: { - if( pExpr->iColumn>=0 ){ - sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn); - sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn); + if( pExpr->iTable<0 ){ + /* This only happens when coding check constraints */ + assert( pParse->ckOffset>0 ); + sqlite3VdbeAddOp(v, OP_Dup, pParse->ckOffset-pExpr->iColumn-1, 1); + }else if( pExpr->iColumn>=0 ){ + Table *pTab = pExpr->pTab; + int iCol = pExpr->iColumn; + sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, iCol); + sqlite3ColumnDefault(v, pTab, iCol); +#ifndef SQLITE_OMIT_FLOATING_POINT + if( pTab && pTab->aCol[iCol].affinity==SQLITE_AFF_REAL ){ + sqlite3VdbeAddOp(v, OP_RealAffinity, 0, 0); + } +#endif }else{ sqlite3VdbeAddOp(v, OP_Rowid, pExpr->iTable, 0); } break; } case TK_INTEGER: { - codeInteger(v, pExpr->token.z, pExpr->token.n); + codeInteger(v, (char*)pExpr->token.z, pExpr->token.n); break; } case TK_FLOAT: case TK_STRING: { assert( TK_FLOAT==OP_Real ); assert( TK_STRING==OP_String8 ); sqlite3DequoteExpr(pExpr); - sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z, pExpr->token.n); + sqlite3VdbeOp3(v, op, 0, 0, (char*)pExpr->token.z, pExpr->token.n); break; } case TK_NULL: { sqlite3VdbeAddOp(v, OP_Null, 0, 0); break; @@ -1493,11 +1523,11 @@ case TK_BLOB: { int n; const char *z; assert( TK_BLOB==OP_HexBlob ); n = pExpr->token.n - 3; - z = pExpr->token.z + 2; + z = (char*)pExpr->token.z + 2; assert( n>=0 ); if( n==0 ){ z = ""; } sqlite3VdbeOp3(v, op, 0, 0, z, n); @@ -1505,11 +1535,11 @@ } #endif case TK_VARIABLE: { sqlite3VdbeAddOp(v, OP_Variable, pExpr->iTable, 0); if( pExpr->token.n>1 ){ - sqlite3VdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n); + sqlite3VdbeChangeP3(v, -1, (char*)pExpr->token.z, pExpr->token.n); } break; } case TK_REGISTER: { sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iTable, 0); @@ -1519,17 +1549,18 @@ case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ int aff, op; sqlite3ExprCode(pParse, pExpr->pLeft); aff = sqlite3AffinityType(&pExpr->token); - switch( aff ){ - case SQLITE_AFF_INTEGER: op = OP_ToInt; break; - case SQLITE_AFF_NUMERIC: op = OP_ToNumeric; break; - case SQLITE_AFF_TEXT: op = OP_ToText; break; - case SQLITE_AFF_NONE: op = OP_ToBlob; break; - } + op = aff - SQLITE_AFF_TEXT + OP_ToText; + assert( op==OP_ToText || aff!=SQLITE_AFF_TEXT ); + assert( op==OP_ToBlob || aff!=SQLITE_AFF_NONE ); + assert( op==OP_ToNumeric || aff!=SQLITE_AFF_NUMERIC ); + assert( op==OP_ToInt || aff!=SQLITE_AFF_INTEGER ); + assert( op==OP_ToReal || aff!=SQLITE_AFF_REAL ); sqlite3VdbeAddOp(v, op, 0, 0); + stackChng = 0; break; } #endif /* SQLITE_OMIT_CAST */ case TK_LT: case TK_LE: @@ -1544,10 +1575,11 @@ assert( TK_EQ==OP_Eq ); assert( TK_NE==OP_Ne ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pRight); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0); + stackChng = -1; break; } case TK_AND: case TK_OR: case TK_PLUS: @@ -1572,19 +1604,19 @@ assert( TK_RSHIFT==OP_ShiftRight ); assert( TK_CONCAT==OP_Concat ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pRight); sqlite3VdbeAddOp(v, op, 0, 0); + stackChng = -1; break; } case TK_UMINUS: { Expr *pLeft = pExpr->pLeft; assert( pLeft ); if( pLeft->op==TK_FLOAT || pLeft->op==TK_INTEGER ){ Token *p = &pLeft->token; - char *z = sqliteMalloc( p->n + 2 ); - sprintf(z, "-%.*s", p->n, p->z); + char *z = sqlite3MPrintf("-%.*s", p->n, p->z); if( pLeft->op==TK_FLOAT ){ sqlite3VdbeOp3(v, OP_Real, 0, 0, z, p->n+1); }else{ codeInteger(v, z, p->n+1); } @@ -1597,10 +1629,11 @@ case TK_NOT: { assert( TK_BITNOT==OP_BitNot ); assert( TK_NOT==OP_Not ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3VdbeAddOp(v, op, 0, 0); + stackChng = 0; break; } case TK_ISNULL: case TK_NOTNULL: { int dest; @@ -1609,15 +1642,21 @@ sqlite3VdbeAddOp(v, OP_Integer, 1, 0); sqlite3ExprCode(pParse, pExpr->pLeft); dest = sqlite3VdbeCurrentAddr(v) + 2; sqlite3VdbeAddOp(v, op, 1, dest); sqlite3VdbeAddOp(v, OP_AddImm, -1, 0); + stackChng = 0; break; } case TK_AGG_FUNCTION: { AggInfo *pInfo = pExpr->pAggInfo; - sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0); + if( pInfo==0 ){ + sqlite3ErrorMsg(pParse, "misuse of aggregate: %T", + &pExpr->span); + }else{ + sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0); + } break; } case TK_CONST_FUNC: case TK_FUNCTION: { ExprList *pList = pExpr->pList; @@ -1625,13 +1664,13 @@ FuncDef *pDef; int nId; const char *zId; int constMask = 0; int i; - u8 enc = pParse->db->enc; + u8 enc = ENC(pParse->db); CollSeq *pColl = 0; - zId = pExpr->token.z; + zId = (char*)pExpr->token.z; nId = pExpr->token.n; pDef = sqlite3FindFunction(pParse->db, zId, nId, nExpr, enc, 0); assert( pDef!=0 ); nExpr = sqlite3ExprCodeExprList(pParse, pList); for(i=0; ineedCollSeq ){ if( !pColl ) pColl = pParse->db->pDfltColl; sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ); } sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF); + stackChng = 1-nExpr; break; } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { @@ -1703,10 +1743,11 @@ break; } case TK_UPLUS: case TK_AS: { sqlite3ExprCode(pParse, pExpr->pLeft); + stackChng = 0; break; } case TK_CASE: { int expr_end_label; int jumpInst; @@ -1761,20 +1802,26 @@ assert( pExpr->iColumn==OE_Rollback || pExpr->iColumn == OE_Abort || pExpr->iColumn == OE_Fail ); sqlite3DequoteExpr(pExpr); sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn, - pExpr->token.z, pExpr->token.n); + (char*)pExpr->token.z, pExpr->token.n); } else { assert( pExpr->iColumn == OE_Ignore ); sqlite3VdbeAddOp(v, OP_ContextPop, 0, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->trigStack->ignoreJump); VdbeComment((v, "# raise(IGNORE)")); } + stackChng = 0; + break; } #endif - break; + } + + if( pParse->ckOffset ){ + pParse->ckOffset += stackChng; + assert( pParse->ckOffset ); } } #ifndef SQLITE_OMIT_TRIGGER /* @@ -1838,10 +1885,11 @@ ** below verify that the numbers are aligned correctly. */ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; + int ckOffset = pParse->ckOffset; if( v==0 || pExpr==0 ) return; op = pExpr->op; switch( op ){ case TK_AND: { int d2 = sqlite3VdbeMakeLabel(v); @@ -1912,10 +1960,11 @@ sqlite3ExprCode(pParse, pExpr); sqlite3VdbeAddOp(v, OP_If, jumpIfNull, dest); break; } } + pParse->ckOffset = ckOffset; } /* ** Generate code for a boolean expression such that a jump is made ** to the label "dest" if the expression is false but execution @@ -1925,10 +1974,11 @@ ** jump if jumpIfNull is true or fall through if jumpIfNull is false. */ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; + int ckOffset = pParse->ckOffset; if( v==0 || pExpr==0 ) return; /* The value of pExpr->op and op are related as follows: ** ** pExpr->op op @@ -2021,10 +2071,11 @@ sqlite3ExprCode(pParse, pExpr); sqlite3VdbeAddOp(v, OP_IfNot, jumpIfNull, dest); break; } } + pParse->ckOffset = ckOffset; } /* ** Do a deep comparison of two expression trees. Return TRUE (non-zero) ** if they are identical and return FALSE if they differ in any way. @@ -2054,11 +2105,13 @@ if( pA->pSelect || pB->pSelect ) return 0; if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0; if( pA->token.z ){ if( pB->token.z==0 ) return 0; if( pB->token.n!=pA->token.n ) return 0; - if( sqlite3StrNICmp(pA->token.z, pB->token.z, pB->token.n)!=0 ) return 0; + if( sqlite3StrNICmp((char*)pA->token.z,(char*)pB->token.z,pB->token.n)!=0 ){ + return 0; + } } return 1; } @@ -2178,18 +2231,18 @@ } } if( i>=pAggInfo->nFunc ){ /* pExpr is original. Make a new entry in pAggInfo->aFunc[] */ - u8 enc = pParse->db->enc; + u8 enc = ENC(pParse->db); i = addAggInfoFunc(pAggInfo); if( i>=0 ){ pItem = &pAggInfo->aFunc[i]; pItem->pExpr = pExpr; pItem->iMem = pParse->nMem++; pItem->pFunc = sqlite3FindFunction(pParse->db, - pExpr->token.z, pExpr->token.n, + (char*)pExpr->token.z, pExpr->token.n, pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0); if( pExpr->flags & EP_Distinct ){ pItem->iDistinct = pParse->nTab++; }else{ pItem->iDistinct = -1; Index: SQLite.Interop/src/func.c ================================================================== --- SQLite.Interop/src/func.c +++ SQLite.Interop/src/func.c @@ -14,15 +14,15 @@ ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: func.c,v 1.11 2005/12/19 17:57:46 rmsimpson Exp $ +** $Id: func.c,v 1.12 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" #include -#include +/* #include */ #include #include #include "vdbeInt.h" #include "os.h" @@ -99,11 +99,11 @@ case SQLITE_FLOAT: { sqlite3_result_int(context, sqlite3_value_bytes(argv[0])); break; } case SQLITE_TEXT: { - const char *z = sqlite3_value_text(argv[0]); + const unsigned char *z = sqlite3_value_text(argv[0]); for(len=0; *z; z++){ if( (0xc0&*z)!=0x80 ) len++; } sqlite3_result_int(context, len); break; } default: { @@ -144,12 +144,12 @@ static void substrFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ - const char *z; - const char *z2; + const unsigned char *z; + const unsigned char *z2; int i; int p1, p2, len; assert( argc==3 ); z = sqlite3_value_text(argv[0]); @@ -176,11 +176,11 @@ for(; ienc); + len = sqlite3ValueBytes(argv[0], ENC(db)); zVal = sqliteMalloc(len+3); zVal[len] = 0; zVal[len-1] = 0; assert( zVal ); zVal++; - memcpy(zVal, sqlite3ValueText(argv[0], db->enc), len); - if( db->enc==SQLITE_UTF8 ){ + memcpy(zVal, sqlite3ValueText(argv[0], ENC(db)), len); + if( ENC(db)==SQLITE_UTF8 ){ sqlite3_result_text(pCtx, zVal, -1, destructor); #ifndef SQLITE_OMIT_UTF16 - }else if( db->enc==SQLITE_UTF16LE ){ + }else if( ENC(db)==SQLITE_UTF16LE ){ sqlite3_result_text16le(pCtx, zVal, -1, destructor); }else{ sqlite3_result_text16be(pCtx, zVal, -1, destructor); #endif /* SQLITE_OMIT_UTF16 */ } @@ -774,11 +774,11 @@ ){ int i; char *zRet = sqliteMalloc(nArg*2); if( !zRet ) return; for(i=0; ipList->nExpr!=2 ){ return 0; } - pDef = sqlite3FindFunction(db, pExpr->token.z, pExpr->token.n, 2, + pDef = sqlite3FindFunction(db, (char*)pExpr->token.z, pExpr->token.n, 2, SQLITE_UTF8, 0); if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){ return 0; } Index: SQLite.Interop/src/hash.c ================================================================== --- SQLite.Interop/src/hash.c +++ SQLite.Interop/src/hash.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This is the implementation of generic hash-tables ** used in SQLite. ** -** $Id: hash.c,v 1.10 2005/12/19 17:57:47 rmsimpson Exp $ +** $Id: hash.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" #include /* Turn bulk memory into a hash table object by initializing the @@ -292,10 +292,15 @@ if( pH->copyKey && elem->pKey ){ sqliteFree(elem->pKey); } sqliteFree( elem ); pH->count--; + if( pH->count<=0 ){ + assert( pH->first==0 ); + assert( pH->count==0 ); + sqlite3HashClear(pH); + } } /* Attempt to locate an element of the hash table pH with a key ** that matches pKey,nKey. Return the data for this element if it is ** found, or NULL if there is no match. Index: SQLite.Interop/src/hash.h ================================================================== --- SQLite.Interop/src/hash.h +++ SQLite.Interop/src/hash.h @@ -10,11 +10,11 @@ ** ************************************************************************* ** This is the header file for the generic hash-table implemenation ** used in SQLite. ** -** $Id: hash.h,v 1.10 2005/12/19 17:57:47 rmsimpson Exp $ +** $Id: hash.h,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #ifndef _SQLITE_HASH_H_ #define _SQLITE_HASH_H_ /* Forward declarations of structures. */ Index: SQLite.Interop/src/insert.c ================================================================== --- SQLite.Interop/src/insert.c +++ SQLite.Interop/src/insert.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.10 2005/12/19 17:57:47 rmsimpson Exp $ +** $Id: insert.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" /* ** Set P3 of the most recently inserted opcode to a column affinity @@ -21,14 +21,15 @@ ** string for index pIdx. A column affinity string has one character ** for each column in the table, according to the affinity of the column: ** ** Character Column affinity ** ------------------------------ -** 'n' NUMERIC -** 'i' INTEGER -** 't' TEXT -** 'o' NONE +** 'a' TEXT +** 'b' NONE +** 'c' NUMERIC +** 'd' INTEGER +** 'e' REAL */ void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){ if( !pIdx->zColAff ){ /* The first time a column affinity string for a particular index is ** required, it is allocated and populated here. It is then stored as @@ -59,14 +60,15 @@ ** for each column indexed by the index, according to the affinity of the ** column: ** ** Character Column affinity ** ------------------------------ -** 'n' NUMERIC -** 'i' INTEGER -** 't' TEXT -** 'o' NONE +** 'a' TEXT +** 'b' NONE +** 'c' NUMERIC +** 'd' INTEGER +** 'e' REAL */ void sqlite3TableAffinityStr(Vdbe *v, Table *pTab){ /* The first time a column affinity string for a particular table ** is required, it is allocated and populated here. It is then ** stored as a member of the Table structure for subsequent use. @@ -100,19 +102,19 @@ ** "INSERT INTO SELECT ..." can run without using temporary ** table for the results of the SELECT. ** ** No checking is done for sub-selects that are part of expressions. */ -static int selectReadsTable(Select *p, int iDb, int iTab){ +static int selectReadsTable(Select *p, Schema *pSchema, int iTab){ int i; struct SrcList_item *pItem; if( p->pSrc==0 ) return 0; for(i=0, pItem=p->pSrc->a; ipSrc->nSrc; i++, pItem++){ if( pItem->pSelect ){ - if( selectReadsTable(pItem->pSelect, iDb, iTab) ) return 1; + if( selectReadsTable(pItem->pSelect, pSchema, iTab) ) return 1; }else{ - if( pItem->pTab->iDb==iDb && pItem->pTab->tnum==iTab ) return 1; + if( pItem->pTab->pSchema==pSchema && pItem->pTab->tnum==iTab ) return 1; } } return 0; } @@ -210,10 +212,11 @@ int iInsertBlock = 0; /* Address of the subroutine used to insert data */ int iCntMem = 0; /* Memory cell used for the row counter */ int newIdx = -1; /* Cursor for the NEW table */ Db *pDb; /* The database containing table being inserted into */ int counterMem = 0; /* Memory cell holding AUTOINCREMENT counter */ + int iDb; #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to insert into a view */ int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */ #endif @@ -220,11 +223,11 @@ #ifndef SQLITE_OMIT_AUTOINCREMENT int counterRowid; /* Memory cell holding rowid of autoinc counter */ #endif - if( pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup; + if( pParse->nErr || sqlite3ThreadData()->mallocFailed ) goto insert_cleanup; db = pParse->db; /* Locate the table into which we will be inserting new information. */ assert( pTabList->nSrc==1 ); @@ -232,12 +235,13 @@ if( zTab==0 ) goto insert_cleanup; pTab = sqlite3SrcListLookup(pParse, pTabList); if( pTab==0 ){ goto insert_cleanup; } - assert( pTab->iDbnDb ); - pDb = &db->aDb[pTab->iDb]; + iDb = sqlite3SchemaToIndex(db, pTab->pSchema); + assert( iDbnDb ); + pDb = &db->aDb[iDb]; zDb = pDb->zName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){ goto insert_cleanup; } @@ -281,11 +285,11 @@ /* Allocate a VDBE */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto insert_cleanup; if( pParse->nested==0 ) sqlite3VdbeCountChanges(v); - sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, pTab->iDb); + sqlite3BeginWriteOperation(pParse, pSelect || triggers_exist, iDb); /* if there are row triggers, allocate a temp table for new.* references. */ if( triggers_exist ){ newIdx = pParse->nTab++; } @@ -299,17 +303,15 @@ if( pTab->autoInc ){ int iCur = pParse->nTab; int base = sqlite3VdbeCurrentAddr(v); counterRowid = pParse->nMem++; counterMem = pParse->nMem++; - sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); - sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pDb->pSeqTab->tnum); - sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2); + sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead); sqlite3VdbeAddOp(v, OP_Rewind, iCur, base+13); sqlite3VdbeAddOp(v, OP_Column, iCur, 0); sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0); - sqlite3VdbeAddOp(v, OP_Ne, 28417, base+12); + sqlite3VdbeAddOp(v, OP_Ne, 0x100, base+12); sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0); sqlite3VdbeAddOp(v, OP_MemStore, counterRowid, 1); sqlite3VdbeAddOp(v, OP_Column, iCur, 1); sqlite3VdbeAddOp(v, OP_MemStore, counterMem, 1); sqlite3VdbeAddOp(v, OP_Goto, 0, base+13); @@ -334,11 +336,11 @@ iSelectLoop = sqlite3VdbeCurrentAddr(v); iInsertBlock = sqlite3VdbeMakeLabel(v); /* Resolve the expressions in the SELECT statement and execute it. */ rc = sqlite3Select(pParse, pSelect, SRT_Subroutine, iInsertBlock,0,0,0,0); - if( rc || pParse->nErr || sqlite3_malloc_failed ) goto insert_cleanup; + if( rc || pParse->nErr || sqlite3ThreadData()->mallocFailed ) goto insert_cleanup; iCleanup = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp(v, OP_Goto, 0, iCleanup); assert( pSelect->pEList ); nColumn = pSelect->pEList->nExpr; @@ -349,11 +351,11 @@ ** ** A temp table must be used if the table being updated is also one ** of the tables being read by the SELECT statement. Also use a ** temp table in the case of row triggers. */ - if( triggers_exist || selectReadsTable(pSelect, pTab->iDb, pTab->tnum) ){ + if( triggers_exist || selectReadsTable(pSelect,pTab->pSchema,pTab->tnum) ){ useTempTable = 1; } if( useTempTable ){ /* Generate the subroutine that SELECT calls to process each row of @@ -360,11 +362,10 @@ ** the result. Store the result in a temporary table */ srcTab = pParse->nTab++; sqlite3VdbeResolveLabel(v, iInsertBlock); sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); - sqlite3TableAffinityStr(v, pTab); sqlite3VdbeAddOp(v, OP_NewRowid, srcTab, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Insert, srcTab, 0); sqlite3VdbeAddOp(v, OP_Return, 0, 0); @@ -633,11 +634,11 @@ } /* Update the count of rows that are inserted */ if( (db->flags & SQLITE_CountRows)!=0 ){ - sqlite3VdbeAddOp(v, OP_MemIncr, iCntMem, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, 1, iCntMem); } if( triggers_exist ){ /* Close all tables opened */ if( !isView ){ @@ -681,13 +682,11 @@ ** table. */ if( pTab->autoInc ){ int iCur = pParse->nTab; int base = sqlite3VdbeCurrentAddr(v); - sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); - sqlite3VdbeAddOp(v, OP_OpenWrite, iCur, pDb->pSeqTab->tnum); - sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, 2); + sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); sqlite3VdbeAddOp(v, OP_MemLoad, counterRowid, 0); sqlite3VdbeAddOp(v, OP_NotNull, -1, base+7); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); sqlite3VdbeAddOp(v, OP_NewRowid, iCur, 0); sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0); @@ -868,11 +867,22 @@ sqlite3VdbeJumpHere(v, addr); } /* Test all CHECK constraints */ - /**** TBD ****/ +#ifndef SQLITE_OMIT_CHECK + if( pTab->pCheck && (pParse->db->flags & SQLITE_IgnoreChecks)==0 ){ + int allOk = sqlite3VdbeMakeLabel(v); + assert( pParse->ckOffset==0 ); + pParse->ckOffset = nCol; + sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1); + assert( pParse->ckOffset==nCol ); + pParse->ckOffset = 0; + sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort); + sqlite3VdbeResolveLabel(v, allOk); + } +#endif /* !defined(SQLITE_OMIT_CHECK) */ /* If we have an INTEGER PRIMARY KEY, make sure the primary key ** of the new record does not previously exist. Except, if this ** is an UPDATE and the primary key is not changing, that is OK. */ @@ -1065,13 +1075,17 @@ } #endif if( pParse->nested ){ pik_flags = 0; }else{ - pik_flags = (OPFLAG_NCHANGE|(isUpdate?0:OPFLAG_LASTROWID)); + pik_flags = OPFLAG_NCHANGE; + pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID); } sqlite3VdbeAddOp(v, OP_Insert, base, pik_flags); + if( !pParse->nested ){ + sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC); + } if( isUpdate && rowidChng ){ sqlite3VdbeAddOp(v, OP_Pop, 1, 0); } } @@ -1086,22 +1100,21 @@ Table *pTab, /* Table to be opened */ int base, /* Cursor number assigned to the table */ int op /* OP_OpenRead or OP_OpenWrite */ ){ int i; + int iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); Index *pIdx; Vdbe *v = sqlite3GetVdbe(pParse); assert( v!=0 ); - sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); - VdbeComment((v, "# %s", pTab->zName)); - sqlite3VdbeAddOp(v, op, base, pTab->tnum); - sqlite3VdbeAddOp(v, OP_SetNumColumns, base, pTab->nCol); + sqlite3OpenTable(pParse, base, iDb, pTab, op); for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ - sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + assert( pIdx->pSchema==pTab->pSchema ); + sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); VdbeComment((v, "# %s", pIdx->zName)); sqlite3VdbeOp3(v, op, i+base, pIdx->tnum, (char*)&pIdx->keyInfo, P3_KEYINFO); } if( pParse->nTab<=base+i ){ pParse->nTab = base+i; } } Index: SQLite.Interop/src/keywordhash.h ================================================================== --- SQLite.Interop/src/keywordhash.h +++ SQLite.Interop/src/keywordhash.h @@ -1,86 +1,87 @@ -/* Hash score: 158 */ +/* Hash score: 159 */ static int keywordCode(const char *z, int n){ - static const char zText[535] = + static const char zText[537] = "ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER" "AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE" "XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX" "AUTOINCREMENTBEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETE" "CASECASTCOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSS" "CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH" - "FAILIMITFROMFULLGROUPDATEIMMEDIATEINSERTINSTEADINTOFFSETISNULL" + "FAILIMITFROMFULLGROUPDATEIFIMMEDIATEINSERTINSTEADINTOFFSETISNULL" "JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION" "UNIQUEUSINGVACUUMVALUESVIEWHERE"; static const unsigned char aHash[127] = { - 91, 80, 106, 90, 0, 4, 0, 0, 113, 0, 83, 0, 0, - 94, 44, 76, 92, 0, 105, 108, 96, 0, 0, 10, 0, 0, - 112, 0, 109, 102, 0, 28, 48, 0, 41, 0, 0, 65, 71, - 0, 63, 19, 0, 104, 36, 103, 0, 107, 74, 0, 0, 33, - 0, 61, 37, 0, 8, 0, 114, 38, 12, 0, 77, 40, 25, + 92, 80, 107, 91, 0, 4, 0, 0, 114, 0, 83, 0, 0, + 96, 44, 76, 93, 0, 106, 109, 97, 90, 0, 10, 0, 0, + 113, 0, 110, 103, 0, 28, 48, 0, 41, 0, 0, 65, 71, + 0, 63, 19, 0, 105, 36, 104, 0, 108, 75, 0, 0, 33, + 0, 61, 37, 0, 8, 0, 115, 38, 12, 0, 77, 40, 25, 66, 0, 0, 31, 81, 53, 30, 50, 20, 88, 0, 34, 0, - 75, 26, 0, 72, 0, 0, 0, 64, 47, 67, 22, 87, 29, - 69, 86, 0, 1, 0, 9, 100, 58, 18, 0, 111, 82, 98, - 54, 6, 85, 0, 0, 49, 93, 0, 101, 0, 70, 0, 0, - 15, 0, 115, 51, 56, 0, 2, 55, 0, 110, + 74, 26, 0, 72, 0, 0, 0, 64, 47, 67, 22, 87, 29, + 69, 86, 0, 1, 0, 9, 101, 58, 18, 0, 112, 82, 99, + 55, 6, 85, 0, 0, 49, 94, 0, 102, 0, 70, 0, 0, + 15, 0, 116, 51, 56, 0, 2, 54, 0, 111, }; - static const unsigned char aNext[115] = { + static const unsigned char aNext[116] = { 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 5, 13, 0, 7, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, - 0, 0, 16, 0, 23, 52, 0, 0, 0, 0, 45, 0, 59, - 0, 0, 0, 0, 0, 0, 0, 0, 73, 42, 0, 24, 60, + 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, + 0, 16, 0, 0, 23, 52, 0, 0, 0, 0, 45, 0, 59, + 0, 0, 0, 0, 0, 0, 0, 0, 43, 73, 0, 24, 60, 21, 0, 79, 0, 0, 68, 0, 0, 84, 46, 0, 0, 0, - 0, 0, 0, 0, 39, 95, 97, 0, 0, 99, 0, 32, 0, - 14, 27, 78, 0, 57, 89, 0, 35, 0, 62, 0, + 0, 0, 0, 0, 0, 39, 95, 98, 0, 0, 100, 0, 32, + 0, 14, 27, 78, 0, 57, 89, 0, 35, 0, 62, 0, }; - static const unsigned char aLen[115] = { + static const unsigned char aLen[116] = { 5, 5, 4, 4, 9, 2, 3, 8, 2, 6, 4, 3, 7, 11, 2, 7, 5, 5, 4, 5, 3, 5, 10, 6, 4, 6, 7, 6, 7, 9, 3, 7, 9, 6, 9, 3, 10, 6, 6, - 4, 6, 3, 7, 6, 7, 5, 13, 2, 2, 5, 5, 6, - 7, 3, 7, 4, 4, 2, 7, 3, 8, 6, 4, 4, 7, - 6, 6, 8, 10, 9, 6, 5, 12, 12, 17, 4, 4, 6, - 8, 2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 9, 6, - 7, 4, 2, 6, 3, 6, 4, 5, 7, 5, 8, 7, 5, - 5, 8, 3, 4, 5, 6, 5, 6, 6, 4, 5, + 4, 6, 7, 3, 6, 7, 5, 13, 2, 2, 5, 5, 6, + 7, 7, 3, 4, 4, 2, 7, 3, 8, 6, 4, 4, 7, + 6, 6, 8, 10, 9, 6, 5, 12, 17, 12, 4, 4, 6, + 8, 2, 4, 6, 5, 4, 5, 4, 4, 5, 6, 2, 9, + 6, 7, 4, 6, 2, 3, 6, 4, 5, 7, 5, 8, 7, + 5, 5, 8, 3, 4, 5, 6, 5, 6, 6, 4, 5, }; - static const unsigned short int aOffset[115] = { + static const unsigned short int aOffset[116] = { 0, 4, 7, 10, 10, 14, 19, 21, 26, 27, 32, 34, 36, 42, 51, 52, 57, 61, 65, 67, 71, 74, 78, 86, 91, 94, 99, 105, 108, 113, 118, 122, 128, 136, 141, 150, 152, 162, 167, 172, 175, 177, 177, 181, 185, 187, 192, 194, 196, 205, 208, 212, 218, 224, 224, 227, 230, 234, 236, 237, 241, 248, 254, 258, 262, 269, 275, 281, 289, 296, 305, 311, 316, 328, 328, 344, 348, 352, - 358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 412, - 418, 425, 428, 428, 431, 434, 440, 444, 448, 455, 459, 467, 474, - 479, 484, 492, 494, 498, 503, 509, 514, 520, 526, 529, + 358, 359, 366, 369, 373, 378, 381, 386, 390, 394, 397, 403, 405, + 414, 420, 427, 430, 430, 433, 436, 442, 446, 450, 457, 461, 469, + 476, 481, 486, 494, 496, 500, 505, 511, 516, 522, 528, 531, }; - static const unsigned char aCode[115] = { + static const unsigned char aCode[116] = { TK_ABORT, TK_TABLE, TK_JOIN_KW, TK_TEMP, TK_TEMP, TK_OR, TK_ADD, TK_DATABASE, TK_AS, TK_SELECT, TK_THEN, TK_END, TK_DEFAULT, TK_TRANSACTION,TK_ON, TK_JOIN_KW, TK_ALTER, TK_RAISE, TK_EACH, TK_CHECK, TK_KEY, TK_AFTER, TK_REFERENCES, TK_ESCAPE, TK_ELSE, TK_EXCEPT, TK_TRIGGER, TK_LIKE_KW, TK_EXPLAIN, TK_INITIALLY, TK_ALL, TK_ANALYZE, TK_EXCLUSIVE, TK_EXISTS, TK_STATEMENT, TK_AND, TK_DEFERRABLE, TK_ATTACH, TK_HAVING, TK_LIKE_KW, - TK_BEFORE, TK_FOR, TK_FOREIGN, TK_IGNORE, TK_REINDEX, + TK_BEFORE, TK_FOREIGN, TK_FOR, TK_IGNORE, TK_REINDEX, TK_INDEX, TK_AUTOINCR, TK_TO, TK_IN, TK_BEGIN, - TK_JOIN_KW, TK_RENAME, TK_BETWEEN, TK_NOT, TK_NOTNULL, + TK_JOIN_KW, TK_RENAME, TK_BETWEEN, TK_NOTNULL, TK_NOT, TK_NULL, TK_LIKE_KW, TK_BY, TK_CASCADE, TK_ASC, TK_DEFERRED, TK_DELETE, TK_CASE, TK_CAST, TK_COLLATE, TK_COLUMNKW, TK_COMMIT, TK_CONFLICT, TK_CONSTRAINT, TK_INTERSECT, TK_CREATE, TK_JOIN_KW, TK_CTIME_KW, TK_CTIME_KW, TK_CTIME_KW, TK_PLAN, TK_DESC, TK_DETACH, TK_DISTINCT, TK_IS, TK_DROP, TK_PRAGMA, TK_MATCH, TK_FAIL, TK_LIMIT, - TK_FROM, TK_JOIN_KW, TK_GROUP, TK_UPDATE, TK_IMMEDIATE, - TK_INSERT, TK_INSTEAD, TK_INTO, TK_OF, TK_OFFSET, - TK_SET, TK_ISNULL, TK_JOIN, TK_ORDER, TK_REPLACE, - TK_JOIN_KW, TK_RESTRICT, TK_PRIMARY, TK_QUERY, TK_JOIN_KW, - TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION, TK_UNIQUE, - TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW, TK_WHERE, + TK_FROM, TK_JOIN_KW, TK_GROUP, TK_UPDATE, TK_IF, + TK_IMMEDIATE, TK_INSERT, TK_INSTEAD, TK_INTO, TK_OFFSET, + TK_OF, TK_SET, TK_ISNULL, TK_JOIN, TK_ORDER, + TK_REPLACE, TK_JOIN_KW, TK_RESTRICT, TK_PRIMARY, TK_QUERY, + TK_JOIN_KW, TK_ROLLBACK, TK_ROW, TK_WHEN, TK_UNION, + TK_UNIQUE, TK_USING, TK_VACUUM, TK_VALUES, TK_VIEW, + TK_WHERE, }; int h, i; if( n<2 ) return TK_ID; h = ((sqlite3UpperToLower[((unsigned char*)z)[0]]*4) ^ (sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3) ^ @@ -90,8 +91,8 @@ return aCode[i]; } } return TK_ID; } -int sqlite3KeywordCode(const char *z, int n){ - return keywordCode(z, n); +int sqlite3KeywordCode(const unsigned char *z, int n){ + return keywordCode((char*)z, n); } Index: SQLite.Interop/src/legacy.c ================================================================== --- SQLite.Interop/src/legacy.c +++ SQLite.Interop/src/legacy.c @@ -12,11 +12,11 @@ ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: legacy.c,v 1.10 2005/12/19 17:57:47 rmsimpson Exp $ +** $Id: legacy.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include @@ -68,11 +68,10 @@ nCallback = 0; nCol = sqlite3_column_count(pStmt); azCols = sqliteMalloc(2*nCol*sizeof(const char *)); if( nCol && !azCols ){ - rc = SQLITE_NOMEM; goto exec_out; } while( 1 ){ int i; @@ -120,13 +119,15 @@ exec_out: if( pStmt ) sqlite3_finalize(pStmt); if( azCols ) sqliteFree(azCols); - if( sqlite3_malloc_failed ){ + if( sqlite3ThreadData()->mallocFailed ){ rc = SQLITE_NOMEM; + sqlite3MallocClearFailed(); } + if( rc!=SQLITE_OK && rc==sqlite3_errcode(db) && pzErrMsg ){ *pzErrMsg = malloc(1+strlen(sqlite3_errmsg(db))); if( *pzErrMsg ){ strcpy(*pzErrMsg, sqlite3_errmsg(db)); } Index: SQLite.Interop/src/main.c ================================================================== --- SQLite.Interop/src/main.c +++ SQLite.Interop/src/main.c @@ -12,11 +12,11 @@ ** Main file for the SQLite library. The routines in this file ** implement the programmer interface to the library. Routines in ** other files are for internal use by SQLite and should not be ** accessed by users of the library. ** -** $Id: main.c,v 1.10 2005/12/19 17:57:47 rmsimpson Exp $ +** $Id: main.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include @@ -24,32 +24,10 @@ ** The following constant value is used by the SQLITE_BIGENDIAN and ** SQLITE_LITTLEENDIAN macros. */ const int sqlite3one = 1; -#ifndef SQLITE_OMIT_GLOBALRECOVER -/* -** Linked list of all open database handles. This is used by the -** sqlite3_global_recover() function. Entries are added to the list -** by openDatabase() and removed by sqlite3_close(). -*/ -static sqlite3 *pDbList = 0; -#endif - -#ifndef SQLITE_OMIT_UTF16 -/* -** Return the transient sqlite3_value object used for encoding conversions -** during SQL compilation. -*/ -sqlite3_value *sqlite3GetTransientValue(sqlite3 *db){ - if( !db->pValue ){ - db->pValue = sqlite3ValueNew(); - } - return db->pValue; -} -#endif - /* ** The version of the library */ const char rcsid3[] = "@(#) \044Id: SQLite version " SQLITE_VERSION " $"; const char sqlite3_version[] = SQLITE_VERSION; @@ -150,16 +128,22 @@ */ if( db->magic!=SQLITE_MAGIC_CLOSED && sqlite3SafetyOn(db) ){ /* printf("DID NOT CLOSE\n"); fflush(stdout); */ return SQLITE_ERROR; } + + /* sqlite3_close() may not invoke sqliteMalloc(). */ + sqlite3MallocDisallow(); for(j=0; jnDb; j++){ struct Db *pDb = &db->aDb[j]; if( pDb->pBt ){ sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; + if( j!=1 ){ + pDb->pSchema = 0; + } } } sqlite3ResetInternalSchema(db, 0); assert( db->nDb<=2 ); assert( db->aDb==db->aDbStatic ); @@ -177,52 +161,52 @@ } sqlite3HashClear(&db->aCollSeq); sqlite3HashClear(&db->aFunc); sqlite3Error(db, SQLITE_OK, 0); /* Deallocates any cached error strings. */ - if( db->pValue ){ - sqlite3ValueFree(db->pValue); - } if( db->pErr ){ sqlite3ValueFree(db->pErr); } -#ifndef SQLITE_OMIT_GLOBALRECOVER - { - sqlite3 *pPrev; - sqlite3OsEnterMutex(); - pPrev = pDbList; - while( pPrev && pPrev->pNext!=db ){ - pPrev = pPrev->pNext; - } - if( pPrev ){ - pPrev->pNext = db->pNext; - }else{ - assert( pDbList==db ); - pDbList = db->pNext; - } - sqlite3OsLeaveMutex(); - } -#endif - db->magic = SQLITE_MAGIC_ERROR; + + /* The temp-database schema is allocated differently from the other schema + ** objects (using sqliteMalloc() directly, instead of sqlite3BtreeSchema()). + ** So it needs to be freed here. Todo: Why not roll the temp schema into + ** the same sqliteMalloc() as the one that allocates the database + ** structure? + */ + sqliteFree(db->aDb[1].pSchema); + sqliteFree(db); + sqlite3MallocAllow(); return SQLITE_OK; } /* ** Rollback all database files. */ void sqlite3RollbackAll(sqlite3 *db){ int i; + int inTrans = 0; for(i=0; inDb; i++){ if( db->aDb[i].pBt ){ + if( sqlite3BtreeIsInTrans(db->aDb[i].pBt) ){ + inTrans = 1; + } sqlite3BtreeRollback(db->aDb[i].pBt); db->aDb[i].inTrans = 0; } } - sqlite3ResetInternalSchema(db, 0); + if( db->flags&SQLITE_InternChanges ){ + sqlite3ResetInternalSchema(db, 0); + } + + /* If one has been configured, invoke the rollback-hook callback */ + if( db->xRollbackCallback && (inTrans || !db->autoCommit) ){ + db->xRollbackCallback(db->pRollbackArg); + } } /* ** Return a static string that describes the kind of error specified in the ** argument. @@ -488,25 +472,22 @@ void (*xFunc)(sqlite3_context*,int,sqlite3_value**), void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*) ){ int rc; - char const *zFunc8; - sqlite3_value *pTmp; + char *zFunc8; if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } - pTmp = sqlite3GetTransientValue(db); - sqlite3ValueSetStr(pTmp, -1, zFunctionName, SQLITE_UTF16NATIVE,SQLITE_STATIC); - zFunc8 = sqlite3ValueText(pTmp, SQLITE_UTF8); - + zFunc8 = sqlite3utf16to8(zFunctionName, -1); if( !zFunc8 ){ return SQLITE_NOMEM; } rc = sqlite3_create_function(db, zFunc8, nArg, eTextRep, pUserData, xFunc, xStep, xFinal); + sqliteFree(zFunc8); return rc; } #endif #ifndef SQLITE_OMIT_TRACE @@ -545,11 +526,11 @@ #endif /* SQLITE_OMIT_TRACE */ /*** EXPERIMENTAL *** ** ** Register a function to be invoked when a transaction comments. -** If either function returns non-zero, then the commit becomes a +** If the invoked function returns non-zero, then the commit becomes a ** rollback. */ void *sqlite3_commit_hook( sqlite3 *db, /* Attach the hook to this database */ int (*xCallback)(void*), /* Function to invoke on each commit */ @@ -559,10 +540,39 @@ db->xCommitCallback = xCallback; db->pCommitArg = pArg; return pOld; } +/* +** Register a callback to be invoked each time a row is updated, +** inserted or deleted using this database connection. +*/ +void *sqlite3_update_hook( + sqlite3 *db, /* Attach the hook to this database */ + void (*xCallback)(void*,int,char const *,char const *,sqlite_int64), + void *pArg /* Argument to the function */ +){ + void *pRet = db->pUpdateArg; + db->xUpdateCallback = xCallback; + db->pUpdateArg = pArg; + return pRet; +} + +/* +** Register a callback to be invoked each time a transaction is rolled +** back by this database connection. +*/ +void *sqlite3_rollback_hook( + sqlite3 *db, /* Attach the hook to this database */ + void (*xCallback)(void*), /* Callback function */ + void *pArg /* Argument to the function */ +){ + void *pRet = db->pRollbackArg; + db->xRollbackCallback = xCallback; + db->pRollbackArg = pArg; + return pRet; +} /* ** This routine is called to create a connection to a database BTree ** driver. If zFilename is the name of a file, then that file is ** opened and used. If zFilename is the magic name ":memory:" then @@ -619,11 +629,11 @@ zFilename = ":memory:"; #endif #endif /* SQLITE_OMIT_MEMORYDB */ } - rc = sqlite3BtreeOpen(zFilename, ppBtree, btree_flags); + rc = sqlite3BtreeOpen(zFilename, (sqlite3 *)db, ppBtree, btree_flags); if( rc==SQLITE_OK ){ sqlite3BtreeSetBusyHandler(*ppBtree, (void*)&db->busyHandler); sqlite3BtreeSetCacheSize(*ppBtree, nCache); } return rc; @@ -633,17 +643,17 @@ ** Return UTF-8 encoded English language explanation of the most recent ** error. */ const char *sqlite3_errmsg(sqlite3 *db){ const char *z; - if( sqlite3_malloc_failed ){ + if( sqlite3ThreadData()->mallocFailed ){ return sqlite3ErrStr(SQLITE_NOMEM); } if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){ return sqlite3ErrStr(SQLITE_MISUSE); } - z = sqlite3_value_text(db->pErr); + z = (char*)sqlite3_value_text(db->pErr); if( z==0 ){ z = sqlite3ErrStr(db->errCode); } return z; } @@ -672,11 +682,11 @@ 0, 'o', 0, 'f', 0, ' ', 0, 's', 0, 'e', 0, 'q', 0, 'u', 0, 'e', 0, 'n', 0, 'c', 0, 'e', 0, 0, 0 }; const void *z; - if( sqlite3_malloc_failed ){ + if( sqlite3ThreadData()->mallocFailed ){ return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]); } if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){ return (void *)(&misuseBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]); } @@ -689,14 +699,15 @@ return z; } #endif /* SQLITE_OMIT_UTF16 */ /* -** Return the most recent error code generated by an SQLite routine. +** Return the most recent error code generated by an SQLite routine. If NULL is +** passed to this function, we assume a malloc() failed during sqlite3_open(). */ int sqlite3_errcode(sqlite3 *db){ - if( sqlite3_malloc_failed ){ + if( !db || sqlite3ThreadData()->mallocFailed ){ return SQLITE_NOMEM; } if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } @@ -711,41 +722,48 @@ static int openDatabase( const char *zFilename, /* Database filename UTF-8 encoded */ sqlite3 **ppDb /* OUT: Returned database handle */ ){ sqlite3 *db; - int rc, i; + int rc; CollSeq *pColl; + + assert( !sqlite3ThreadData()->mallocFailed ); /* Allocate the sqlite data structure */ db = sqliteMalloc( sizeof(sqlite3) ); if( db==0 ) goto opendb_out; db->priorNewRowid = 0; db->magic = SQLITE_MAGIC_BUSY; db->nDb = 2; db->aDb = db->aDbStatic; - db->enc = SQLITE_UTF8; db->autoCommit = 1; db->flags |= SQLITE_ShortColNames; sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0); + +#if 0 for(i=0; inDb; i++){ sqlite3HashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0); sqlite3HashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1); } - +#endif + /* Add the default collation sequence BINARY. BINARY works for both UTF-8 ** and UTF-16, so add a version for each to avoid any unnecessary ** conversions. The only error that can occur here is a malloc() failure. */ if( sqlite3_create_collation(db, "BINARY", SQLITE_UTF8, 0,binCollFunc) || sqlite3_create_collation(db, "BINARY", SQLITE_UTF16, 0,binCollFunc) || - !(db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0)) ){ - rc = db->errCode; - assert( rc!=SQLITE_OK ); + (db->pDfltColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "BINARY", 6, 0))==0 + ){ + /* sqlite3_create_collation() is an external API. So the mallocFailed flag + ** will have been cleared before returning. So set it explicitly here. + */ + sqlite3ThreadData()->mallocFailed = 1; db->magic = SQLITE_MAGIC_CLOSED; goto opendb_out; } /* Also add a UTF-8 case-insensitive collation sequence. */ @@ -763,10 +781,18 @@ if( rc!=SQLITE_OK ){ sqlite3Error(db, rc, 0); db->magic = SQLITE_MAGIC_CLOSED; goto opendb_out; } +#ifndef SQLITE_OMIT_PARSER + db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt); + db->aDb[1].pSchema = sqlite3SchemaGet(0); +#endif + + if( db->aDb[0].pSchema ){ + ENC(db) = SQLITE_UTF8; + } /* The default safety_level for the main database is 'full'; for the temp ** database it is 'NONE'. This matches the pager layer defaults. */ db->aDb[0].zName = "main"; @@ -774,33 +800,26 @@ #ifndef SQLITE_OMIT_TEMPDB db->aDb[1].zName = "temp"; db->aDb[1].safety_level = 1; #endif - /* Register all built-in functions, but do not attempt to read the ** database schema yet. This is delayed until the first time the database ** is accessed. */ sqlite3RegisterBuiltinFunctions(db); sqlite3Error(db, SQLITE_OK, 0); db->magic = SQLITE_MAGIC_OPEN; opendb_out: - if( sqlite3_errcode(db)==SQLITE_OK && sqlite3_malloc_failed ){ - sqlite3Error(db, SQLITE_NOMEM, 0); + if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){ + sqlite3_close(db); + db = 0; } *ppDb = db; -#ifndef SQLITE_OMIT_GLOBALRECOVER - if( db ){ - sqlite3OsEnterMutex(); - db->pNext = pDbList; - pDbList = db; - sqlite3OsLeaveMutex(); - } -#endif - return sqlite3_errcode(db); + sqlite3MallocClearFailed(); + return rc; } /* ** Open a new database handle. */ @@ -821,24 +840,26 @@ ){ char const *zFilename8; /* zFilename encoded in UTF-8 instead of UTF-16 */ int rc = SQLITE_NOMEM; sqlite3_value *pVal; + assert( zFilename ); assert( ppDb ); *ppDb = 0; pVal = sqlite3ValueNew(); sqlite3ValueSetStr(pVal, -1, zFilename, SQLITE_UTF16NATIVE, SQLITE_STATIC); zFilename8 = sqlite3ValueText(pVal, SQLITE_UTF8); if( zFilename8 ){ rc = openDatabase(zFilename8, ppDb); if( rc==SQLITE_OK && *ppDb ){ - sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); + rc = sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); } - } - if( pVal ){ - sqlite3ValueFree(pVal); + }else{ + assert( sqlite3ThreadData()->mallocFailed ); + sqlite3MallocClearFailed(); } + sqlite3ValueFree(pVal); return rc; } #endif /* SQLITE_OMIT_UTF16 */ @@ -948,19 +969,19 @@ const char *zName, int enc, void* pCtx, int(*xCompare)(void*,int,const void*,int,const void*) ){ - char const *zName8; - sqlite3_value *pTmp; + char *zName8; + int rc; if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } - pTmp = sqlite3GetTransientValue(db); - sqlite3ValueSetStr(pTmp, -1, zName, SQLITE_UTF16NATIVE, SQLITE_STATIC); - zName8 = sqlite3ValueText(pTmp, SQLITE_UTF8); - return sqlite3_create_collation(db, zName8, enc, pCtx, xCompare); + zName8 = sqlite3utf16to8(zName, -1); + rc = sqlite3_create_collation(db, zName8, enc, pCtx, xCompare); + sqliteFree(zName8); + return rc; } #endif /* SQLITE_OMIT_UTF16 */ /* ** Register a collation sequence factory callback with the database handle @@ -1000,41 +1021,15 @@ } #endif /* SQLITE_OMIT_UTF16 */ #ifndef SQLITE_OMIT_GLOBALRECOVER /* -** This function is called to recover from a malloc failure that occured -** within SQLite. -** -** This function is *not* threadsafe. Calling this from within a threaded -** application when threads other than the caller have used SQLite is -** dangerous and will almost certainly result in malfunctions. +** This function is now an anachronism. It used to be used to recover from a +** malloc() failure, but SQLite now does this automatically. */ int sqlite3_global_recover(){ - int rc = SQLITE_OK; - - if( sqlite3_malloc_failed ){ - sqlite3 *db; - int i; - sqlite3_malloc_failed = 0; - for(db=pDbList; db; db=db->pNext ){ - sqlite3ExpirePreparedStatements(db); - for(i=0; inDb; i++){ - Btree *pBt = db->aDb[i].pBt; - if( pBt && (rc=sqlite3BtreeReset(pBt)) ){ - goto recover_out; - } - } - db->autoCommit = 1; - } - } - -recover_out: - if( rc!=SQLITE_OK ){ - sqlite3_malloc_failed = 1; - } - return rc; + return SQLITE_OK; } #endif /* ** Test to see whether or not the database connection is in autocommit @@ -1056,5 +1051,32 @@ */ int sqlite3Corrupt(void){ return SQLITE_CORRUPT; } #endif + + +#ifndef SQLITE_OMIT_SHARED_CACHE +/* +** Enable or disable the shared pager and schema features for the +** current thread. +** +** This routine should only be called when there are no open +** database connections. +*/ +int sqlite3_enable_shared_cache(int enable){ + ThreadData *pTd = sqlite3ThreadData(); + + /* It is only legal to call sqlite3_enable_shared_cache() when there + ** are no currently open b-trees that were opened by the calling thread. + ** This condition is only easy to detect if the shared-cache were + ** previously enabled (and is being disabled). + */ + if( pTd->pBtree && !enable ){ + assert( pTd->useSharedData ); + return SQLITE_MISUSE; + } + + pTd->useSharedData = enable; + return SQLITE_OK; +} +#endif ADDED SQLite.Interop/src/md5.c Index: SQLite.Interop/src/md5.c ================================================================== --- /dev/null +++ SQLite.Interop/src/md5.c @@ -0,0 +1,387 @@ +/* +** SQLite uses this code for testing only. It is not a part of +** the SQLite library. This file implements two new TCL commands +** "md5" and "md5file" that compute md5 checksums on arbitrary text +** and on complete files. These commands are used by the "testfixture" +** program to help verify the correct operation of the SQLite library. +** +** The original use of these TCL commands was to test the ROLLBACK +** feature of SQLite. First compute the MD5-checksum of the database. +** Then make some changes but rollback the changes rather than commit +** them. Compute a second MD5-checksum of the file and verify that the +** two checksums are the same. Such is the original use of this code. +** New uses may have been added since this comment was written. +*/ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ +#include +#include +#include "sqlite3.h" + +/* + * If compiled on a machine that doesn't have a 32-bit integer, + * you just set "uint32" to the appropriate datatype for an + * unsigned 32-bit integer. For example: + * + * cc -Duint32='unsigned long' md5.c + * + */ +#ifndef uint32 +# define uint32 unsigned int +#endif + +struct Context { + uint32 buf[4]; + uint32 bits[2]; + unsigned char in[64]; +}; +typedef char MD5Context[88]; + +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse (unsigned char *buf, unsigned longs){ + uint32 t; + do { + t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | + ((unsigned)buf[1]<<8 | buf[0]); + *(uint32 *)buf = t; + buf += 4; + } while (--longs); +} +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(uint32 buf[4], const uint32 in[16]){ + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +static void MD5Init(MD5Context *pCtx){ + struct Context *ctx = (struct Context *)pCtx; + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +static +void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){ + struct Context *ctx = (struct Context *)pCtx; + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if ( t ) { + unsigned char *p = (unsigned char *)ctx->in + t; + + t = 64-t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + buf += t; + len -= t; + } + + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +static void MD5Final(unsigned char digest[16], MD5Context *pCtx){ + struct Context *ctx = (struct Context *)pCtx; + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *)ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count-8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; + ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32 *)ctx->in); + byteReverse((unsigned char *)ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* +** Convert a digest into base-16. digest should be declared as +** "unsigned char digest[16]" in the calling function. The MD5 +** digest is stored in the first 16 bytes. zBuf should +** be "char zBuf[33]". +*/ +static void DigestToBase16(unsigned char *digest, char *zBuf){ + static char const zEncode[] = "0123456789abcdef"; + int i, j; + + for(j=i=0; i<16; i++){ + int a = digest[i]; + zBuf[j++] = zEncode[(a>>4)&0xf]; + zBuf[j++] = zEncode[a & 0xf]; + } + zBuf[j] = 0; +} + +/* +** A TCL command for md5. The argument is the text to be hashed. The +** Result is the hash in base64. +*/ +static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){ + MD5Context ctx; + unsigned char digest[16]; + + if( argc!=2 ){ + Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], + " TEXT\"", 0); + return TCL_ERROR; + } + MD5Init(&ctx); + MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1])); + MD5Final(digest, &ctx); + DigestToBase16(digest, interp->result); + return TCL_OK; +} + +/* +** A TCL command to take the md5 hash of a file. The argument is the +** name of the file. +*/ +static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){ + FILE *in; + MD5Context ctx; + unsigned char digest[16]; + char zBuf[10240]; + + if( argc!=2 ){ + Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], + " FILENAME\"", 0); + return TCL_ERROR; + } + in = fopen(argv[1],"rb"); + if( in==0 ){ + Tcl_AppendResult(interp,"unable to open file \"", argv[1], + "\" for reading", 0); + return TCL_ERROR; + } + MD5Init(&ctx); + for(;;){ + int n; + n = fread(zBuf, 1, sizeof(zBuf), in); + if( n<=0 ) break; + MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n); + } + fclose(in); + MD5Final(digest, &ctx); + DigestToBase16(digest, interp->result); + return TCL_OK; +} + +/* +** Register the two TCL commands above with the TCL interpreter. +*/ +int Md5_Init(Tcl_Interp *interp){ + Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd, 0, 0); + Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd, 0, 0); + return TCL_OK; +} + +/* +** During testing, the special md5sum() aggregate function is available. +** inside SQLite. The following routines implement that function. +*/ +static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){ + MD5Context *p; + int i; + if( argc<1 ) return; + p = sqlite3_aggregate_context(context, sizeof(*p)); + if( p==0 ) return; + if( sqlite3_aggregate_count(context)==1 ){ + MD5Init(p); + } + for(i=0; ipMethod->xClose(pId); + }else{ + return SQLITE_OK; + } +} +int sqlite3OsOpenDirectory(OsFile *id, const char *zName){ + return id->pMethod->xOpenDirectory(id, zName); +} +int sqlite3OsRead(OsFile *id, void *pBuf, int amt){ + return id->pMethod->xRead(id, pBuf, amt); +} +int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ + return id->pMethod->xWrite(id, pBuf, amt); +} +int sqlite3OsSeek(OsFile *id, i64 offset){ + return id->pMethod->xSeek(id, offset); +} +int sqlite3OsTruncate(OsFile *id, i64 size){ + return id->pMethod->xTruncate(id, size); +} +int sqlite3OsSync(OsFile *id, int fullsync){ + return id->pMethod->xSync(id, fullsync); +} +void sqlite3OsSetFullSync(OsFile *id, int value){ + id->pMethod->xSetFullSync(id, value); +} +int sqlite3OsFileHandle(OsFile *id){ + return id->pMethod->xFileHandle(id); +} +int sqlite3OsFileSize(OsFile *id, i64 *pSize){ + return id->pMethod->xFileSize(id, pSize); +} +int sqlite3OsLock(OsFile *id, int lockType){ + return id->pMethod->xLock(id, lockType); +} +int sqlite3OsUnlock(OsFile *id, int lockType){ + return id->pMethod->xUnlock(id, lockType); +} +int sqlite3OsLockState(OsFile *id){ + return id->pMethod->xLockState(id); +} +int sqlite3OsCheckReservedLock(OsFile *id){ + return id->pMethod->xCheckReservedLock(id); +} + +#ifdef SQLITE_ENABLE_REDEF_IO +/* +** A function to return a pointer to the virtual function table. +** This routine really does not accomplish very much since the +** virtual function table is a global variable and anybody who +** can call this function can just as easily access the variable +** for themselves. Nevertheless, we include this routine for +** backwards compatibility with an earlier redefinable I/O +** interface design. +*/ +struct sqlite3OsVtbl *sqlite3_os_switch(void){ + return &sqlite3Os; +} +#endif Index: SQLite.Interop/src/os.h ================================================================== --- SQLite.Interop/src/os.h +++ SQLite.Interop/src/os.h @@ -16,16 +16,14 @@ */ #ifndef _SQLITE_OS_H_ #define _SQLITE_OS_H_ /* -** Figure out if we are dealing with Unix, Windows or MacOS. -** -** N.B. MacOS means Mac Classic (or Carbon). Treat Darwin (OS X) as Unix. -** The MacOS build is designed to use CodeWarrior (tested with v8) +** Figure out if we are dealing with Unix, Windows, or some other +** operating system. */ -#if !defined(OS_UNIX) && !defined(OS_TEST) && !defined(OS_OTHER) +#if !defined(OS_UNIX) && !defined(OS_OTHER) # define OS_OTHER 0 # ifndef OS_WIN # if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__) # define OS_WIN 1 # define OS_UNIX 0 @@ -39,30 +37,20 @@ #else # ifndef OS_WIN # define OS_WIN 0 # endif #endif + /* -** Invoke the appropriate operating-system specific header file. +** Define the maximum size of a temporary filename */ -#if OS_TEST -# include "os_test.h" -#endif -#if OS_UNIX -# include "os_unix.h" -#endif #if OS_WIN -# include "os_win.h" -#endif - -/* os_other.c and os_other.h are not delivered with SQLite. These files -** are place-holders that can be filled in by third-party developers to -** implement backends to their on proprietary operating systems. -*/ -#if OS_OTHER -# include "os_other.h" +# include +# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) +#else +# define SQLITE_TEMPNAME_SIZE 200 #endif /* If the SET_FULLSYNC macro is not defined above, then make it ** a no-op */ @@ -80,10 +68,108 @@ ** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line. */ #ifndef TEMP_FILE_PREFIX # define TEMP_FILE_PREFIX "sqlite_" #endif + +/* +** Define the interfaces for Unix and for Windows. +*/ +#if OS_UNIX +#define sqlite3OsOpenReadWrite sqlite3UnixOpenReadWrite +#define sqlite3OsOpenExclusive sqlite3UnixOpenExclusive +#define sqlite3OsOpenReadOnly sqlite3UnixOpenReadOnly +#define sqlite3OsDelete sqlite3UnixDelete +#define sqlite3OsFileExists sqlite3UnixFileExists +#define sqlite3OsFullPathname sqlite3UnixFullPathname +#define sqlite3OsIsDirWritable sqlite3UnixIsDirWritable +#define sqlite3OsSyncDirectory sqlite3UnixSyncDirectory +#define sqlite3OsTempFileName sqlite3UnixTempFileName +#define sqlite3OsRandomSeed sqlite3UnixRandomSeed +#define sqlite3OsSleep sqlite3UnixSleep +#define sqlite3OsCurrentTime sqlite3UnixCurrentTime +#define sqlite3OsEnterMutex sqlite3UnixEnterMutex +#define sqlite3OsLeaveMutex sqlite3UnixLeaveMutex +#define sqlite3OsInMutex sqlite3UnixInMutex +#define sqlite3OsThreadSpecificData sqlite3UnixThreadSpecificData +#define sqlite3OsMalloc sqlite3GenericMalloc +#define sqlite3OsRealloc sqlite3GenericRealloc +#define sqlite3OsFree sqlite3GenericFree +#define sqlite3OsAllocationSize sqlite3GenericAllocationSize +#endif +#if OS_WIN +#define sqlite3OsOpenReadWrite sqlite3WinOpenReadWrite +#define sqlite3OsOpenExclusive sqlite3WinOpenExclusive +#define sqlite3OsOpenReadOnly sqlite3WinOpenReadOnly +#define sqlite3OsDelete sqlite3WinDelete +#define sqlite3OsFileExists sqlite3WinFileExists +#define sqlite3OsFullPathname sqlite3WinFullPathname +#define sqlite3OsIsDirWritable sqlite3WinIsDirWritable +#define sqlite3OsSyncDirectory sqlite3WinSyncDirectory +#define sqlite3OsTempFileName sqlite3WinTempFileName +#define sqlite3OsRandomSeed sqlite3WinRandomSeed +#define sqlite3OsSleep sqlite3WinSleep +#define sqlite3OsCurrentTime sqlite3WinCurrentTime +#define sqlite3OsEnterMutex sqlite3WinEnterMutex +#define sqlite3OsLeaveMutex sqlite3WinLeaveMutex +#define sqlite3OsInMutex sqlite3WinInMutex +#define sqlite3OsThreadSpecificData sqlite3WinThreadSpecificData +#define sqlite3OsMalloc sqlite3GenericMalloc +#define sqlite3OsRealloc sqlite3GenericRealloc +#define sqlite3OsFree sqlite3GenericFree +#define sqlite3OsAllocationSize sqlite3GenericAllocationSize +#endif + +/* +** If using an alternative OS interface, then we must have an "os_other.h" +** header file available for that interface. Presumably the "os_other.h" +** header file contains #defines similar to those above. +*/ +#if OS_OTHER +# include "os_other.h" +#endif + + + +/* +** Forward declarations +*/ +typedef struct OsFile OsFile; +typedef struct IoMethod IoMethod; + +/* +** An instance of the following structure contains pointers to all +** methods on an OsFile object. +*/ +struct IoMethod { + int (*xClose)(OsFile**); + int (*xOpenDirectory)(OsFile*, const char*); + int (*xRead)(OsFile*, void*, int amt); + int (*xWrite)(OsFile*, const void*, int amt); + int (*xSeek)(OsFile*, i64 offset); + int (*xTruncate)(OsFile*, i64 size); + int (*xSync)(OsFile*, int); + void (*xSetFullSync)(OsFile *id, int setting); + int (*xFileHandle)(OsFile *id); + int (*xFileSize)(OsFile*, i64 *pSize); + int (*xLock)(OsFile*, int); + int (*xUnlock)(OsFile*, int); + int (*xLockState)(OsFile *id); + int (*xCheckReservedLock)(OsFile *id); +}; + +/* +** The OsFile object describes an open disk file in an OS-dependent way. +** The version of OsFile defined here is a generic version. Each OS +** implementation defines its own subclass of this structure that contains +** additional information needed to handle file I/O. But the pMethod +** entry (pointing to the virtual function table) always occurs first +** so that we can always find the appropriate methods. +*/ +struct OsFile { + IoMethod const *pMethod; +}; /* ** The following values may be passed as the second argument to ** sqlite3OsLock(). The various locks exhibit the following semantics: ** @@ -135,12 +221,14 @@ ** The following #defines specify the range of bytes used for locking. ** SHARED_SIZE is the number of bytes available in the pool from which ** a random byte is selected for a shared lock. The pool of bytes for ** shared locks begins at SHARED_FIRST. ** -** These #defines are available in os.h so that Unix can use the same -** byte ranges for locking. This leaves open the possiblity of having +** These #defines are available in sqlite_aux.h so that adaptors for +** connecting SQLite to other operating systems can use the same byte +** ranges for locking. In particular, the same locking strategy and +** byte ranges are used for Unix. This leaves open the possiblity of having ** clients on win95, winNT, and unix all talking to the same shared file ** and all locking correctly. To do so would require that samba (or whatever ** tool is being used for file sharing) implements locks correctly between ** windows and unix. I'm guessing that isn't likely to happen, but by ** using the same locking range we are at least open to the possibility. @@ -170,38 +258,183 @@ #define RESERVED_BYTE (PENDING_BYTE+1) #define SHARED_FIRST (PENDING_BYTE+2) #define SHARED_SIZE 510 - -int sqlite3OsDelete(const char*); -int sqlite3OsFileExists(const char*); -int sqlite3OsOpenReadWrite(const char*, OsFile*, int*); -int sqlite3OsOpenExclusive(const char*, OsFile*, int); -int sqlite3OsOpenReadOnly(const char*, OsFile*); -int sqlite3OsOpenDirectory(const char*, OsFile*); -int sqlite3OsSyncDirectory(const char*); -int sqlite3OsTempFileName(char*); -int sqlite3OsIsDirWritable(char*); -int sqlite3OsClose(OsFile*); +/* +** Prototypes for operating system interface routines. +*/ +int sqlite3OsClose(OsFile**); +int sqlite3OsOpenDirectory(OsFile*, const char*); int sqlite3OsRead(OsFile*, void*, int amt); int sqlite3OsWrite(OsFile*, const void*, int amt); int sqlite3OsSeek(OsFile*, i64 offset); -int sqlite3OsSync(OsFile*, int); int sqlite3OsTruncate(OsFile*, i64 size); +int sqlite3OsSync(OsFile*, int); +void sqlite3OsSetFullSync(OsFile *id, int setting); +int sqlite3OsFileHandle(OsFile *id); int sqlite3OsFileSize(OsFile*, i64 *pSize); -char *sqlite3OsFullPathname(const char*); int sqlite3OsLock(OsFile*, int); int sqlite3OsUnlock(OsFile*, int); +int sqlite3OsLockState(OsFile *id); int sqlite3OsCheckReservedLock(OsFile *id); - - -/* The interface for file I/O is above. Other miscellaneous functions -** are below */ - +int sqlite3OsOpenReadWrite(const char*, OsFile**, int*); +int sqlite3OsOpenExclusive(const char*, OsFile**, int); +int sqlite3OsOpenReadOnly(const char*, OsFile**); +int sqlite3OsDelete(const char*); +int sqlite3OsFileExists(const char*); +char *sqlite3OsFullPathname(const char*); +int sqlite3OsIsDirWritable(char*); +int sqlite3OsSyncDirectory(const char*); +int sqlite3OsTempFileName(char*); int sqlite3OsRandomSeed(char*); int sqlite3OsSleep(int ms); int sqlite3OsCurrentTime(double*); void sqlite3OsEnterMutex(void); void sqlite3OsLeaveMutex(void); +int sqlite3OsInMutex(void); +void *sqlite3OsThreadSpecificData(int); +void *sqlite3OsMalloc(int); +void *sqlite3OsRealloc(void *, int); +void sqlite3OsFree(void *); +int sqlite3OsAllocationSize(void *); + +/* +** If the SQLITE_ENABLE_REDEF_IO macro is defined, then the OS-layer +** interface routines are not called directly but are invoked using +** pointers to functions. This allows the implementation of various +** OS-layer interface routines to be modified at run-time. There are +** obscure but legitimate reasons for wanting to do this. But for +** most users, a direct call to the underlying interface is preferable +** so the the redefinable I/O interface is turned off by default. +*/ +#ifdef SQLITE_ENABLE_REDEF_IO + +/* +** When redefinable I/O is enabled, a single global instance of the +** following structure holds pointers to the routines that SQLite +** uses to talk with the underlying operating system. Modify this +** structure (before using any SQLite API!) to accomodate perculiar +** operating system interfaces or behaviors. +*/ +struct sqlite3OsVtbl { + int (*xOpenReadWrite)(const char*, OsFile**, int*); + int (*xOpenExclusive)(const char*, OsFile**, int); + int (*xOpenReadOnly)(const char*, OsFile**); + + int (*xDelete)(const char*); + int (*xFileExists)(const char*); + char *(*xFullPathname)(const char*); + int (*xIsDirWritable)(char*); + int (*xSyncDirectory)(const char*); + int (*xTempFileName)(char*); + + int (*xRandomSeed)(char*); + int (*xSleep)(int ms); + int (*xCurrentTime)(double*); + + void (*xEnterMutex)(void); + void (*xLeaveMutex)(void); + int (*xInMutex)(void); + void *(*xThreadSpecificData)(int); + + void *(*xMalloc)(int); + void *(*xRealloc)(void *, int); + void (*xFree)(void *); + int (*xAllocationSize)(void *); +}; + +/* Macro used to comment out routines that do not exists when there is +** no disk I/O +*/ +#ifdef SQLITE_OMIT_DISKIO +# define IF_DISKIO(X) 0 +#else +# define IF_DISKIO(X) X +#endif + +#ifdef _SQLITE_OS_C_ + /* + ** The os.c file implements the global virtual function table. + */ + struct sqlite3OsVtbl sqlite3Os = { + IF_DISKIO( sqlite3OsOpenReadWrite ), + IF_DISKIO( sqlite3OsOpenExclusive ), + IF_DISKIO( sqlite3OsOpenReadOnly ), + IF_DISKIO( sqlite3OsDelete ), + IF_DISKIO( sqlite3OsFileExists ), + IF_DISKIO( sqlite3OsFullPathname ), + IF_DISKIO( sqlite3OsIsDirWritable ), + IF_DISKIO( sqlite3OsSyncDirectory ), + IF_DISKIO( sqlite3OsTempFileName ), + sqlite3OsRandomSeed, + sqlite3OsSleep, + sqlite3OsCurrentTime, + sqlite3OsEnterMutex, + sqlite3OsLeaveMutex, + sqlite3OsInMutex, + sqlite3OsThreadSpecificData, + sqlite3OsMalloc, + sqlite3OsRealloc, + sqlite3OsFree, + sqlite3OsAllocationSize + }; +#else + /* + ** Files other than os.c just reference the global virtual function table. + */ + extern struct sqlite3OsVtbl sqlite3Os; +#endif /* _SQLITE_OS_C_ */ + + +/* This additional API routine is available with redefinable I/O */ +struct sqlite3OsVtbl *sqlite3_os_switch(void); + + +/* +** Redefine the OS interface to go through the virtual function table +** rather than calling routines directly. +*/ +#undef sqlite3OsOpenReadWrite +#undef sqlite3OsOpenExclusive +#undef sqlite3OsOpenReadOnly +#undef sqlite3OsDelete +#undef sqlite3OsFileExists +#undef sqlite3OsFullPathname +#undef sqlite3OsIsDirWritable +#undef sqlite3OsSyncDirectory +#undef sqlite3OsTempFileName +#undef sqlite3OsRandomSeed +#undef sqlite3OsSleep +#undef sqlite3OsCurrentTime +#undef sqlite3OsEnterMutex +#undef sqlite3OsLeaveMutex +#undef sqlite3OsInMutex +#undef sqlite3OsThreadSpecificData +#undef sqlite3OsMalloc +#undef sqlite3OsRealloc +#undef sqlite3OsFree +#undef sqlite3OsAllocationSize +#define sqlite3OsOpenReadWrite sqlite3Os.xOpenReadWrite +#define sqlite3OsOpenExclusive sqlite3Os.xOpenExclusive +#define sqlite3OsOpenReadOnly sqlite3Os.xOpenReadOnly +#define sqlite3OsDelete sqlite3Os.xDelete +#define sqlite3OsFileExists sqlite3Os.xFileExists +#define sqlite3OsFullPathname sqlite3Os.xFullPathname +#define sqlite3OsIsDirWritable sqlite3Os.xIsDirWritable +#define sqlite3OsSyncDirectory sqlite3Os.xSyncDirectory +#define sqlite3OsTempFileName sqlite3Os.xTempFileName +#define sqlite3OsRandomSeed sqlite3Os.xRandomSeed +#define sqlite3OsSleep sqlite3Os.xSleep +#define sqlite3OsCurrentTime sqlite3Os.xCurrentTime +#define sqlite3OsEnterMutex sqlite3Os.xEnterMutex +#define sqlite3OsLeaveMutex sqlite3Os.xLeaveMutex +#define sqlite3OsInMutex sqlite3Os.xInMutex +#define sqlite3OsThreadSpecificData sqlite3Os.xThreadSpecificData +#define sqlite3OsMalloc sqlite3Os.xMalloc +#define sqlite3OsRealloc sqlite3Os.xRealloc +#define sqlite3OsFree sqlite3Os.xFree +#define sqlite3OsAllocationSize sqlite3Os.xAllocationSize + +#endif /* SQLITE_ENABLE_REDEF_IO */ #endif /* _SQLITE_OS_H_ */ Index: SQLite.Interop/src/os_common.h ================================================================== --- SQLite.Interop/src/os_common.h +++ SQLite.Interop/src/os_common.h @@ -34,12 +34,12 @@ */ #ifdef SQLITE_TEST unsigned int sqlite3_pending_byte = 0x40000000; #endif -#ifdef SQLITE_DEBUG int sqlite3_os_trace = 0; +#ifdef SQLITE_DEBUG static int last_page = 0; #define SEEK(X) last_page=(X) #define TRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X) #define TRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y) #define TRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z) @@ -86,18 +86,19 @@ ** If we compile with the SQLITE_TEST macro set, then the following block ** of code will give us the ability to simulate a disk I/O error. This ** is used for testing the I/O recovery logic. */ #ifdef SQLITE_TEST +int sqlite3_io_error_hit = 0; int sqlite3_io_error_pending = 0; int sqlite3_diskfull_pending = 0; int sqlite3_diskfull = 0; #define SimulateIOError(A) \ if( sqlite3_io_error_pending ) \ if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; } static void local_ioerr(){ - sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */ + sqlite3_io_error_hit = 1; /* Really just a place to set a breakpoint */ } #define SimulateDiskfullError \ if( sqlite3_diskfull_pending ){ \ if( sqlite3_diskfull_pending == 1 ){ \ local_ioerr(); \ @@ -119,5 +120,41 @@ int sqlite3_open_file_count = 0; #define OpenCounter(X) sqlite3_open_file_count+=(X) #else #define OpenCounter(X) #endif + +/* +** sqlite3GenericMalloc +** sqlite3GenericRealloc +** sqlite3GenericOsFree +** sqlite3GenericAllocationSize +** +** Implementation of the os level dynamic memory allocation interface in terms +** of the standard malloc(), realloc() and free() found in many operating +** systems. No rocket science here. +*/ +void *sqlite3GenericMalloc(int n){ + char *p = (char *)malloc(n+8); + assert(n>0); + assert(sizeof(int)<=8); + if( p ){ + *(int *)p = n; + } + return (void *)(p + 8); +} +void *sqlite3GenericRealloc(void *p, int n){ + char *p2 = ((char *)p - 8); + assert(n>0); + p2 = realloc(p2, n+8); + if( p2 ){ + *(int *)p2 = n; + } + return (void *)((char *)p2 + 8); +} +void sqlite3GenericFree(void *p){ + assert(p); + free((void *)((char *)p - 8)); +} +int sqlite3GenericAllocationSize(void *p){ + return p ? *(int *)((char *)p - 8) : 0; +} Index: SQLite.Interop/src/os_unix.c ================================================================== --- SQLite.Interop/src/os_unix.c +++ SQLite.Interop/src/os_unix.c @@ -14,15 +14,104 @@ */ #include "sqliteInt.h" #include "os.h" #if OS_UNIX /* This file is used on unix only */ +/* +** These #defines should enable >2GB file support on Posix if the +** underlying operating system supports it. If the OS lacks +** large file support, or if the OS is windows, these should be no-ops. +** +** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch +** on the compiler command line. This is necessary if you are compiling +** on a recent machine (ex: RedHat 7.2) but you want your code to work +** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2 +** without this option, LFS is enable. But LFS does not exist in the kernel +** in RedHat 6.0, so the code won't work. Hence, for maximum binary +** portability you should omit LFS. +** +** Similar is true for MacOS. LFS is only supported on MacOS 9 and later. +*/ +#ifndef SQLITE_DISABLE_LFS +# define _LARGE_FILE 1 +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# define _LARGEFILE_SOURCE 1 +#endif +/* +** standard include files. +*/ +#include +#include +#include +#include #include #include #include -#include + +/* +** Macros used to determine whether or not to use threads. The +** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for +** Posix threads and SQLITE_W32_THREADS is defined if we are +** synchronizing using Win32 threads. +*/ +#if defined(THREADSAFE) && THREADSAFE +# include +# define SQLITE_UNIX_THREADS 1 +#endif + +/* +** Default permissions when creating a new file +*/ +#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS +# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 +#endif + + + +/* +** The unixFile structure is subclass of OsFile specific for the unix +** protability layer. +*/ +typedef struct unixFile unixFile; +struct unixFile { + IoMethod const *pMethod; /* Always the first entry */ + struct openCnt *pOpen; /* Info about all open fd's on this inode */ + struct lockInfo *pLock; /* Info about locks on this inode */ + int h; /* The file descriptor */ + unsigned char locktype; /* The type of lock held on this fd */ + unsigned char isOpen; /* True if needs to be closed */ + unsigned char fullSync; /* Use F_FULLSYNC if available */ + int dirfd; /* File descriptor for the directory */ +#ifdef SQLITE_UNIX_THREADS + pthread_t tid; /* The thread authorized to use this OsFile */ +#endif +}; + +/* +** Provide the ability to override some OS-layer functions during +** testing. This is used to simulate OS crashes to verify that +** commits are atomic even in the event of an OS crash. +*/ +#ifdef SQLITE_CRASH_TEST + extern int sqlite3CrashTestEnable; + extern int sqlite3CrashOpenReadWrite(const char*, OsFile**, int*); + extern int sqlite3CrashOpenExclusive(const char*, OsFile**, int); + extern int sqlite3CrashOpenReadOnly(const char*, OsFile**, int); +# define CRASH_TEST_OVERRIDE(X,A,B,C) \ + if(sqlite3CrashTestEnable){ return X(A,B,C); } +#else +# define CRASH_TEST_OVERRIDE(X,A,B,C) /* no-op */ +#endif + + +/* +** Include code that is common to all os_*.c files +*/ +#include "os_common.h" /* ** Do not include any of the File I/O interface procedures if the ** SQLITE_OMIT_DISKIO macro is defined (indicating that there database ** will be in-memory only) @@ -49,21 +138,16 @@ /* ** The DJGPP compiler environment looks mostly like Unix, but it ** lacks the fcntl() system call. So redefine fcntl() to be something ** that always succeeds. This means that locking does not occur under -** DJGPP. But its DOS - what did you expect? +** DJGPP. But it's DOS - what did you expect? */ #ifdef __DJGPP__ # define fcntl(A,B,C) 0 #endif -/* -** Include code that is common to all os_*.c files -*/ -#include "os_common.h" - /* ** The threadid macro resolves to the thread-id or to 0. Used for ** testing and debugging only. */ #ifdef SQLITE_UNIX_THREADS @@ -79,13 +163,13 @@ ** not allow locks to be overridden by other threads and that restriction ** means that sqlite3* database handles cannot be moved from one thread ** to another. This logic makes sure a user does not try to do that ** by mistake. */ -#ifdef SQLITE_UNIX_THREADS -# define SET_THREADID(X) X->tid = pthread_self() -# define CHECK_THREADID(X) (!pthread_equal(X->tid, pthread_self())) +#if defined(SQLITE_UNIX_THREADS) && !defined(SQLITE_ALLOW_XTHREAD_CONNECTIONS) +# define SET_THREADID(X) (X)->tid = pthread_self() +# define CHECK_THREADID(X) (!pthread_equal((X)->tid, pthread_self())) #else # define SET_THREADID(X) # define CHECK_THREADID(X) 0 #endif @@ -200,11 +284,11 @@ */ struct lockKey { dev_t dev; /* Device number */ ino_t ino; /* Inode number */ #ifdef SQLITE_UNIX_THREADS - pthread_t tid; /* Thread ID or zero if threads cannot override each other */ + pthread_t tid; /* Thread ID or zero if threads can override each other */ #endif }; /* ** An instance of the following structure is allocated for each open @@ -418,10 +502,11 @@ struct stat statbuf; struct lockInfo *pLock; struct openCnt *pOpen; rc = fstat(fd, &statbuf); if( rc!=0 ) return 1; + memset(&key1, 0, sizeof(key1)); key1.dev = statbuf.st_dev; key1.ino = statbuf.st_ino; #ifdef SQLITE_UNIX_THREADS if( threadsOverrideEachOthersLocks<0 ){ @@ -434,20 +519,24 @@ key2.ino = statbuf.st_ino; pLock = (struct lockInfo*)sqlite3HashFind(&lockHash, &key1, sizeof(key1)); if( pLock==0 ){ struct lockInfo *pOld; pLock = sqliteMallocRaw( sizeof(*pLock) ); - if( pLock==0 ) return 1; + if( pLock==0 ){ + rc = 1; + goto exit_findlockinfo; + } pLock->key = key1; pLock->nRef = 1; pLock->cnt = 0; pLock->locktype = 0; pOld = sqlite3HashInsert(&lockHash, &pLock->key, sizeof(key1), pLock); if( pOld!=0 ){ assert( pOld==pLock ); sqliteFree(pLock); - return 1; + rc = 1; + goto exit_findlockinfo; } }else{ pLock->nRef++; } *ppLock = pLock; @@ -455,11 +544,12 @@ if( pOpen==0 ){ struct openCnt *pOld; pOpen = sqliteMallocRaw( sizeof(*pOpen) ); if( pOpen==0 ){ releaseLockInfo(pLock); - return 1; + rc = 1; + goto exit_findlockinfo; } pOpen->key = key2; pOpen->nRef = 1; pOpen->nLock = 0; pOpen->nPending = 0; @@ -467,34 +557,40 @@ pOld = sqlite3HashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen); if( pOld!=0 ){ assert( pOld==pOpen ); sqliteFree(pOpen); releaseLockInfo(pLock); - return 1; + rc = 1; + goto exit_findlockinfo; } }else{ pOpen->nRef++; } *ppOpen = pOpen; - return 0; + +exit_findlockinfo: + return rc; } /* ** Delete the named file */ -int sqlite3OsDelete(const char *zFilename){ +int sqlite3UnixDelete(const char *zFilename){ unlink(zFilename); return SQLITE_OK; } /* ** Return TRUE if the named file exists. */ -int sqlite3OsFileExists(const char *zFilename){ +int sqlite3UnixFileExists(const char *zFilename){ return access(zFilename, 0)==0; } +/* Forward declaration */ +static int allocateUnixFile(unixFile *pInit, OsFile **pId); + /* ** Attempt to open a file for both reading and writing. If that ** fails, try opening it read-only. If the file does not exist, ** try to create it. ** @@ -504,47 +600,48 @@ ** SQLITE_OK. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id and *pReadonly unchanged. */ -int sqlite3OsOpenReadWrite( +int sqlite3UnixOpenReadWrite( const char *zFilename, - OsFile *id, + OsFile **pId, int *pReadonly ){ int rc; - assert( !id->isOpen ); - id->dirfd = -1; - SET_THREADID(id); - id->h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, + unixFile f; + + CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadWrite, zFilename, pId, pReadonly); + assert( 0==*pId ); + f.dirfd = -1; + SET_THREADID(&f); + f.h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, SQLITE_DEFAULT_FILE_PERMISSIONS); - if( id->h<0 ){ + if( f.h<0 ){ #ifdef EISDIR if( errno==EISDIR ){ return SQLITE_CANTOPEN; } #endif - id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); - if( id->h<0 ){ + f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); + if( f.h<0 ){ return SQLITE_CANTOPEN; } *pReadonly = 1; }else{ *pReadonly = 0; } sqlite3OsEnterMutex(); - rc = findLockInfo(id->h, &id->pLock, &id->pOpen); + rc = findLockInfo(f.h, &f.pLock, &f.pOpen); sqlite3OsLeaveMutex(); if( rc ){ - close(id->h); + close(f.h); return SQLITE_NOMEM; } - id->locktype = 0; - id->isOpen = 1; - TRACE3("OPEN %-3d %s\n", id->h, zFilename); - OpenCounter(+1); - return SQLITE_OK; + f.locktype = 0; + TRACE3("OPEN %-3d %s\n", f.h, zFilename); + return allocateUnixFile(&f, pId); } /* ** Attempt to open a new file for exclusive access by this process. @@ -558,70 +655,73 @@ ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ -int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ +int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ int rc; - assert( !id->isOpen ); + unixFile f; + + CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag); + assert( 0==*pId ); if( access(zFilename, 0)==0 ){ return SQLITE_CANTOPEN; } - SET_THREADID(id); - id->dirfd = -1; - id->h = open(zFilename, + SET_THREADID(&f); + f.dirfd = -1; + f.h = open(zFilename, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY, SQLITE_DEFAULT_FILE_PERMISSIONS); - if( id->h<0 ){ + if( f.h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); - rc = findLockInfo(id->h, &id->pLock, &id->pOpen); + rc = findLockInfo(f.h, &f.pLock, &f.pOpen); sqlite3OsLeaveMutex(); if( rc ){ - close(id->h); + close(f.h); unlink(zFilename); return SQLITE_NOMEM; } - id->locktype = 0; - id->isOpen = 1; + f.locktype = 0; if( delFlag ){ unlink(zFilename); } - TRACE3("OPEN-EX %-3d %s\n", id->h, zFilename); - OpenCounter(+1); - return SQLITE_OK; + TRACE3("OPEN-EX %-3d %s\n", f.h, zFilename); + return allocateUnixFile(&f, pId); } /* ** Attempt to open a new file for read-only access. ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ -int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){ +int sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){ int rc; - assert( !id->isOpen ); - SET_THREADID(id); - id->dirfd = -1; - id->h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); - if( id->h<0 ){ + unixFile f; + + CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadOnly, zFilename, pId, 0); + assert( 0==*pId ); + SET_THREADID(&f); + f.dirfd = -1; + f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); + if( f.h<0 ){ return SQLITE_CANTOPEN; } sqlite3OsEnterMutex(); - rc = findLockInfo(id->h, &id->pLock, &id->pOpen); + rc = findLockInfo(f.h, &f.pLock, &f.pOpen); sqlite3OsLeaveMutex(); if( rc ){ - close(id->h); + close(f.h); return SQLITE_NOMEM; } - id->locktype = 0; - id->isOpen = 1; - TRACE3("OPEN-RO %-3d %s\n", id->h, zFilename); - OpenCounter(+1); - return SQLITE_OK; + f.locktype = 0; + TRACE3("OPEN-RO %-3d %s\n", f.h, zFilename); + + return allocateUnixFile(&f, pId); } /* ** Attempt to open a file descriptor for the directory that contains a ** file. This file descriptor can be used to fsync() the directory @@ -629,33 +729,34 @@ ** to disk. ** ** This routine is only meaningful for Unix. It is a no-op under ** windows since windows does not support hard links. ** -** On success, a handle for a previously open file is at *id is +** On success, a handle for a previously open file at *id is ** updated with the new directory file descriptor and SQLITE_OK is ** returned. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id unchanged. */ -int sqlite3OsOpenDirectory( - const char *zDirname, - OsFile *id +static int unixOpenDirectory( + OsFile *id, + const char *zDirname ){ - if( !id->isOpen ){ + unixFile *pFile = (unixFile*)id; + if( pFile==0 ){ /* Do not open the directory if the corresponding file is not already ** open. */ return SQLITE_CANTOPEN; } - SET_THREADID(id); - assert( id->dirfd<0 ); - id->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0); - if( id->dirfd<0 ){ + SET_THREADID(pFile); + assert( pFile->dirfd<0 ); + pFile->dirfd = open(zDirname, O_RDONLY|O_BINARY, 0); + if( pFile->dirfd<0 ){ return SQLITE_CANTOPEN; } - TRACE3("OPENDIR %-3d %s\n", id->dirfd, zDirname); + TRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname); return SQLITE_OK; } /* ** If the following global variable points to a string which is the @@ -666,11 +767,11 @@ /* ** Create a temporary file name in zBuf. zBuf must be big enough to ** hold at least SQLITE_TEMPNAME_SIZE characters. */ -int sqlite3OsTempFileName(char *zBuf){ +int sqlite3UnixTempFileName(char *zBuf){ static const char *azDirs[] = { 0, "/var/tmp", "/usr/tmp", "/tmp", @@ -702,39 +803,40 @@ zBuf[j] = 0; }while( access(zBuf,0)==0 ); return SQLITE_OK; } -#ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** Check that a given pathname is a directory and is writable ** */ -int sqlite3OsIsDirWritable(char *zBuf){ +int sqlite3UnixIsDirWritable(char *zBuf){ +#ifndef SQLITE_OMIT_PAGER_PRAGMAS struct stat buf; if( zBuf==0 ) return 0; if( zBuf[0]==0 ) return 0; if( stat(zBuf, &buf) ) return 0; if( !S_ISDIR(buf.st_mode) ) return 0; if( access(zBuf, 07) ) return 0; +#endif /* SQLITE_OMIT_PAGER_PRAGMAS */ return 1; } -#endif /* SQLITE_OMIT_PAGER_PRAGMAS */ /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ -int sqlite3OsRead(OsFile *id, void *pBuf, int amt){ +static int unixRead(OsFile *id, void *pBuf, int amt){ int got; - assert( id->isOpen ); + assert( id ); SimulateIOError(SQLITE_IOERR); TIMER_START; - got = read(id->h, pBuf, amt); + got = read(((unixFile*)id)->h, pBuf, amt); TIMER_END; - TRACE5("READ %-3d %5d %7d %d\n", id->h, got, last_page, TIMER_ELAPSED); + TRACE5("READ %-3d %5d %7d %d\n", ((unixFile*)id)->h, got, + last_page, TIMER_ELAPSED); SEEK(0); /* if( got<0 ) got = 0; */ if( got==amt ){ return SQLITE_OK; }else{ @@ -744,23 +846,24 @@ /* ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ -int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ +static int unixWrite(OsFile *id, const void *pBuf, int amt){ int wrote = 0; - assert( id->isOpen ); + assert( id ); assert( amt>0 ); SimulateIOError(SQLITE_IOERR); SimulateDiskfullError; TIMER_START; - while( amt>0 && (wrote = write(id->h, pBuf, amt))>0 ){ + while( amt>0 && (wrote = write(((unixFile*)id)->h, pBuf, amt))>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } TIMER_END; - TRACE5("WRITE %-3d %5d %7d %d\n", id->h, wrote, last_page, TIMER_ELAPSED); + TRACE5("WRITE %-3d %5d %7d %d\n", ((unixFile*)id)->h, wrote, + last_page, TIMER_ELAPSED); SEEK(0); if( amt>0 ){ return SQLITE_FULL; } return SQLITE_OK; @@ -767,17 +870,17 @@ } /* ** Move the read/write pointer in a file. */ -int sqlite3OsSeek(OsFile *id, i64 offset){ - assert( id->isOpen ); +static int unixSeek(OsFile *id, i64 offset){ + assert( id ); SEEK(offset/1024 + 1); #ifdef SQLITE_TEST if( offset ) SimulateDiskfullError #endif - lseek(id->h, offset, SEEK_SET); + lseek(((unixFile*)id)->h, offset, SEEK_SET); return SQLITE_OK; } #ifdef SQLITE_TEST /* @@ -786,10 +889,18 @@ */ int sqlite3_sync_count = 0; int sqlite3_fullsync_count = 0; #endif +/* +** Use the fdatasync() API only if the HAVE_FDATASYNC macro is defined. +** Otherwise use fsync() in its place. +*/ +#ifndef HAVE_FDATASYNC +# define fdatasync fsync +#endif + /* ** The fsync() system call does not work as advertised on many ** unix systems. The following procedure is an attempt to make ** it work better. @@ -827,16 +938,13 @@ } /* If the FULLSYNC failed, try to do a normal fsync() */ if( rc ) rc = fsync(fd); #else /* if !defined(F_FULLSYNC) */ -#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO>0 if( dataOnly ){ rc = fdatasync(fd); - }else -#endif /* _POSIX_SYNCHRONIZED_IO > 0 */ - { + }else{ rc = fsync(fd); } #endif /* defined(F_FULLFSYNC) */ #endif /* defined(SQLITE_NO_SYNC) */ @@ -856,22 +964,27 @@ ** entry for the journal might not exist after we reboot. The next ** SQLite to access the file will not know that the journal exists (because ** the directory entry for the journal was never created) and the transaction ** will not roll back - possibly leading to database corruption. */ -int sqlite3OsSync(OsFile *id, int dataOnly){ - assert( id->isOpen ); +static int unixSync(OsFile *id, int dataOnly){ + unixFile *pFile = (unixFile*)id; + assert( pFile ); SimulateIOError(SQLITE_IOERR); - TRACE2("SYNC %-3d\n", id->h); - if( full_fsync(id->h, id->fullSync, dataOnly) ){ + TRACE2("SYNC %-3d\n", pFile->h); + if( full_fsync(pFile->h, pFile->fullSync, dataOnly) ){ return SQLITE_IOERR; } - if( id->dirfd>=0 ){ - TRACE2("DIRSYNC %-3d\n", id->dirfd); - full_fsync(id->dirfd, id->fullSync, 0); - close(id->dirfd); /* Only need to sync once, so close the directory */ - id->dirfd = -1; /* when we are done. */ + if( pFile->dirfd>=0 ){ + TRACE2("DIRSYNC %-3d\n", pFile->dirfd); +#ifndef SQLITE_DISABLE_DIRSYNC + if( full_fsync(pFile->dirfd, pFile->fullSync, 0) ){ + return SQLITE_IOERR; + } +#endif + close(pFile->dirfd); /* Only need to sync once, so close the directory */ + pFile->dirfd = -1; /* when we are done. */ } return SQLITE_OK; } /* @@ -880,11 +993,14 @@ ** ** This is used to make sure the master journal file has truely been deleted ** before making changes to individual journals on a multi-database commit. ** The F_FULLFSYNC option is not needed here. */ -int sqlite3OsSyncDirectory(const char *zDirname){ +int sqlite3UnixSyncDirectory(const char *zDirname){ +#ifdef SQLITE_DISABLE_DIRSYNC + return SQLITE_OK; +#else int fd; int r; SimulateIOError(SQLITE_IOERR); fd = open(zDirname, O_RDONLY|O_BINARY, 0); TRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname); @@ -892,29 +1008,30 @@ return SQLITE_CANTOPEN; } r = fsync(fd); close(fd); return ((r==0)?SQLITE_OK:SQLITE_IOERR); +#endif } /* ** Truncate an open file to a specified size */ -int sqlite3OsTruncate(OsFile *id, i64 nByte){ - assert( id->isOpen ); +static int unixTruncate(OsFile *id, i64 nByte){ + assert( id ); SimulateIOError(SQLITE_IOERR); - return ftruncate(id->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR; + return ftruncate(((unixFile*)id)->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR; } /* ** Determine the current size of a file in bytes */ -int sqlite3OsFileSize(OsFile *id, i64 *pSize){ +static int unixFileSize(OsFile *id, i64 *pSize){ struct stat buf; - assert( id->isOpen ); + assert( id ); SimulateIOError(SQLITE_IOERR); - if( fstat(id->h, &buf)!=0 ){ + if( fstat(((unixFile*)id)->h, &buf)!=0 ){ return SQLITE_IOERR; } *pSize = buf.st_size; return SQLITE_OK; } @@ -923,19 +1040,20 @@ ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, return ** non-zero. If the file is unlocked or holds only SHARED locks, then ** return zero. */ -int sqlite3OsCheckReservedLock(OsFile *id){ +static int unixCheckReservedLock(OsFile *id){ int r = 0; + unixFile *pFile = (unixFile*)id; - assert( id->isOpen ); - if( CHECK_THREADID(id) ) return SQLITE_MISUSE; - sqlite3OsEnterMutex(); /* Needed because id->pLock is shared across threads */ + assert( pFile ); + if( CHECK_THREADID(pFile) ) return SQLITE_MISUSE; + sqlite3OsEnterMutex(); /* Because pFile->pLock is shared across threads */ /* Check if a thread in this process holds such a lock */ - if( id->pLock->locktype>SHARED_LOCK ){ + if( pFile->pLock->locktype>SHARED_LOCK ){ r = 1; } /* Otherwise see if some other process holds it. */ @@ -943,18 +1061,18 @@ struct flock lock; lock.l_whence = SEEK_SET; lock.l_start = RESERVED_BYTE; lock.l_len = 1; lock.l_type = F_WRLCK; - fcntl(id->h, F_GETLK, &lock); + fcntl(pFile->h, F_GETLK, &lock); if( lock.l_type!=F_UNLCK ){ r = 1; } } sqlite3OsLeaveMutex(); - TRACE3("TEST WR-LOCK %d %d\n", id->h, r); + TRACE3("TEST WR-LOCK %d %d\n", pFile->h, r); return r; } #ifdef SQLITE_DEBUG @@ -961,11 +1079,11 @@ /* ** Helper function for printing out trace information from debugging ** binaries. This returns the string represetation of the supplied ** integer lock-type. */ -static const char * locktypeName(int locktype){ +static const char *locktypeName(int locktype){ switch( locktype ){ case NO_LOCK: return "NONE"; case SHARED_LOCK: return "SHARED"; case RESERVED_LOCK: return "RESERVED"; case PENDING_LOCK: return "PENDING"; @@ -997,11 +1115,11 @@ ** PENDING -> EXCLUSIVE ** ** This routine will only increase a lock. Use the sqlite3OsUnlock() ** routine to lower a locking level. */ -int sqlite3OsLock(OsFile *id, int locktype){ +static int unixLock(OsFile *id, int locktype){ /* The following describes the implementation of the various locks and ** lock transitions in terms of the POSIX advisory shared and exclusive ** lock primitives (called read-locks and write-locks below, to avoid ** confusion with SQLite lock names). The algorithms are complicated ** slightly in order to be compatible with windows systems simultaneously @@ -1037,43 +1155,45 @@ ** range' is that some versions of windows do not support read-locks. By ** locking a random byte from a range, concurrent SHARED locks may exist ** even if the locking primitive used is always a write-lock. */ int rc = SQLITE_OK; - struct lockInfo *pLock = id->pLock; + unixFile *pFile = (unixFile*)id; + struct lockInfo *pLock = pFile->pLock; struct flock lock; int s; - assert( id->isOpen ); - TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", id->h, locktypeName(locktype), - locktypeName(id->locktype), locktypeName(pLock->locktype), pLock->cnt - ,getpid() ); - if( CHECK_THREADID(id) ) return SQLITE_MISUSE; + assert( pFile ); + TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h, + locktypeName(locktype), locktypeName(pFile->locktype), + locktypeName(pLock->locktype), pLock->cnt , getpid()); + if( CHECK_THREADID(pFile) ) return SQLITE_MISUSE; /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ - if( id->locktype>=locktype ){ - TRACE3("LOCK %d %s ok (already held)\n", id->h, locktypeName(locktype)); + if( pFile->locktype>=locktype ){ + TRACE3("LOCK %d %s ok (already held)\n", pFile->h, + locktypeName(locktype)); return SQLITE_OK; } /* Make sure the locking sequence is correct */ - assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK ); + assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); - assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK ); + assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); - /* This mutex is needed because id->pLock is shared across threads + /* This mutex is needed because pFile->pLock is shared across threads */ sqlite3OsEnterMutex(); /* If some thread using this PID has a lock via a different OsFile* ** handle that precludes the requested lock, return BUSY. */ - if( (id->locktype!=pLock->locktype && + if( (pFile->locktype!=pLock->locktype && (pLock->locktype>=PENDING_LOCK || locktype>SHARED_LOCK)) ){ rc = SQLITE_BUSY; goto end_lock; } @@ -1083,15 +1203,15 @@ ** return SQLITE_OK. */ if( locktype==SHARED_LOCK && (pLock->locktype==SHARED_LOCK || pLock->locktype==RESERVED_LOCK) ){ assert( locktype==SHARED_LOCK ); - assert( id->locktype==0 ); + assert( pFile->locktype==0 ); assert( pLock->cnt>0 ); - id->locktype = SHARED_LOCK; + pFile->locktype = SHARED_LOCK; pLock->cnt++; - id->pOpen->nLock++; + pFile->pOpen->nLock++; goto end_lock; } lock.l_len = 1L; @@ -1100,15 +1220,15 @@ /* A PENDING lock is needed before acquiring a SHARED lock and before ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will ** be released. */ if( locktype==SHARED_LOCK - || (locktype==EXCLUSIVE_LOCK && id->locktypelocktypeh, F_SETLK, &lock); + s = fcntl(pFile->h, F_SETLK, &lock); if( s ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; goto end_lock; } } @@ -1122,25 +1242,25 @@ assert( pLock->locktype==0 ); /* Now get the read-lock */ lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; - s = fcntl(id->h, F_SETLK, &lock); + s = fcntl(pFile->h, F_SETLK, &lock); /* Drop the temporary PENDING lock */ lock.l_start = PENDING_BYTE; lock.l_len = 1L; lock.l_type = F_UNLCK; - if( fcntl(id->h, F_SETLK, &lock)!=0 ){ + if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){ rc = SQLITE_IOERR; /* This should never happen */ goto end_lock; } if( s ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; }else{ - id->locktype = SHARED_LOCK; - id->pOpen->nLock++; + pFile->locktype = SHARED_LOCK; + pFile->pOpen->nLock++; pLock->cnt = 1; } }else if( locktype==EXCLUSIVE_LOCK && pLock->cnt>1 ){ /* We are trying for an exclusive lock but another thread in this ** same process is still holding a shared lock. */ @@ -1148,11 +1268,11 @@ }else{ /* The request was for a RESERVED or EXCLUSIVE lock. It is ** assumed that there is a SHARED or greater lock on the file ** already. */ - assert( 0!=id->locktype ); + assert( 0!=pFile->locktype ); lock.l_type = F_WRLCK; switch( locktype ){ case RESERVED_LOCK: lock.l_start = RESERVED_BYTE; break; @@ -1161,76 +1281,77 @@ lock.l_len = SHARED_SIZE; break; default: assert(0); } - s = fcntl(id->h, F_SETLK, &lock); + s = fcntl(pFile->h, F_SETLK, &lock); if( s ){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; } } if( rc==SQLITE_OK ){ - id->locktype = locktype; + pFile->locktype = locktype; pLock->locktype = locktype; }else if( locktype==EXCLUSIVE_LOCK ){ - id->locktype = PENDING_LOCK; + pFile->locktype = PENDING_LOCK; pLock->locktype = PENDING_LOCK; } end_lock: sqlite3OsLeaveMutex(); - TRACE4("LOCK %d %s %s\n", id->h, locktypeName(locktype), + TRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype), rc==SQLITE_OK ? "ok" : "failed"); return rc; } /* -** Lower the locking level on file descriptor id to locktype. locktype +** Lower the locking level on file descriptor pFile to locktype. locktype ** must be either NO_LOCK or SHARED_LOCK. ** ** If the locking level of the file descriptor is already at or below ** the requested locking level, this routine is a no-op. ** ** It is not possible for this routine to fail if the second argument ** is NO_LOCK. If the second argument is SHARED_LOCK, this routine ** might return SQLITE_IOERR instead of SQLITE_OK. */ -int sqlite3OsUnlock(OsFile *id, int locktype){ +static int unixUnlock(OsFile *id, int locktype){ struct lockInfo *pLock; struct flock lock; int rc = SQLITE_OK; + unixFile *pFile = (unixFile*)id; - assert( id->isOpen ); - TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", id->h, locktype, id->locktype, - id->pLock->locktype, id->pLock->cnt, getpid()); - if( CHECK_THREADID(id) ) return SQLITE_MISUSE; + assert( pFile ); + TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype, + pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid()); + if( CHECK_THREADID(pFile) ) return SQLITE_MISUSE; assert( locktype<=SHARED_LOCK ); - if( id->locktype<=locktype ){ + if( pFile->locktype<=locktype ){ return SQLITE_OK; } sqlite3OsEnterMutex(); - pLock = id->pLock; + pLock = pFile->pLock; assert( pLock->cnt!=0 ); - if( id->locktype>SHARED_LOCK ){ - assert( pLock->locktype==id->locktype ); + if( pFile->locktype>SHARED_LOCK ){ + assert( pLock->locktype==pFile->locktype ); if( locktype==SHARED_LOCK ){ lock.l_type = F_RDLCK; lock.l_whence = SEEK_SET; lock.l_start = SHARED_FIRST; lock.l_len = SHARED_SIZE; - if( fcntl(id->h, F_SETLK, &lock)!=0 ){ + if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){ /* This should never happen */ rc = SQLITE_IOERR; } } lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = PENDING_BYTE; lock.l_len = 2L; assert( PENDING_BYTE+1==RESERVED_BYTE ); - if( fcntl(id->h, F_SETLK, &lock)==0 ){ + if( fcntl(pFile->h, F_SETLK, &lock)==0 ){ pLock->locktype = SHARED_LOCK; }else{ rc = SQLITE_IOERR; /* This should never happen */ } } @@ -1244,11 +1365,11 @@ pLock->cnt--; if( pLock->cnt==0 ){ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = lock.l_len = 0L; - if( fcntl(id->h, F_SETLK, &lock)==0 ){ + if( fcntl(pFile->h, F_SETLK, &lock)==0 ){ pLock->locktype = NO_LOCK; }else{ rc = SQLITE_IOERR; /* This should never happen */ } } @@ -1255,11 +1376,11 @@ /* Decrement the count of locks against this same file. When the ** count reaches zero, close any other file descriptors whose close ** was deferred because of outstanding locks. */ - pOpen = id->pOpen; + pOpen = pFile->pOpen; pOpen->nLock--; assert( pOpen->nLock>=0 ); if( pOpen->nLock==0 && pOpen->nPending>0 ){ int i; for(i=0; inPending; i++){ @@ -1269,24 +1390,26 @@ pOpen->nPending = 0; pOpen->aPending = 0; } } sqlite3OsLeaveMutex(); - id->locktype = locktype; + pFile->locktype = locktype; return rc; } /* ** Close a file. */ -int sqlite3OsClose(OsFile *id){ - if( !id->isOpen ) return SQLITE_OK; +static int unixClose(OsFile **pId){ + unixFile *id = (unixFile*)*pId; + if( !id ) return SQLITE_OK; if( CHECK_THREADID(id) ) return SQLITE_MISUSE; - sqlite3OsUnlock(id, NO_LOCK); + unixUnlock(*pId, NO_LOCK); if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1; sqlite3OsEnterMutex(); + if( id->pOpen->nLock ){ /* If there are outstanding locks, do not actually close the file just ** yet because that would clear those locks. Instead, add the file ** descriptor to pOpen->aPending. It will be automatically closed when ** the last lock is cleared. @@ -1305,24 +1428,27 @@ /* There are no outstanding locks so we can close the file immediately */ close(id->h); } releaseLockInfo(id->pLock); releaseOpenCnt(id->pOpen); + sqlite3OsLeaveMutex(); id->isOpen = 0; TRACE2("CLOSE %-3d\n", id->h); OpenCounter(-1); + sqliteFree(id); + *pId = 0; return SQLITE_OK; } /* ** Turn a relative pathname into a full pathname. Return a pointer ** to the full pathname stored in space obtained from sqliteMalloc(). ** The calling function is responsible for freeing this space once it ** is no longer needed. */ -char *sqlite3OsFullPathname(const char *zRelative){ +char *sqlite3UnixFullPathname(const char *zRelative){ char *zFull = 0; if( zRelative[0]=='/' ){ sqlite3SetString(&zFull, zRelative, (char*)0); }else{ char *zBuf = sqliteMalloc(5000); @@ -1335,10 +1461,76 @@ sqliteFree(zBuf); } return zFull; } +/* +** Change the value of the fullsync flag in the given file descriptor. +*/ +static void unixSetFullSync(OsFile *id, int v){ + ((unixFile*)id)->fullSync = v; +} + +/* +** Return the underlying file handle for an OsFile +*/ +static int unixFileHandle(OsFile *id){ + return ((unixFile*)id)->h; +} + +/* +** Return an integer that indices the type of lock currently held +** by this handle. (Used for testing and analysis only.) +*/ +static int unixLockState(OsFile *id){ + return ((unixFile*)id)->locktype; +} + +/* +** This vector defines all the methods that can operate on an OsFile +** for unix. +*/ +static const IoMethod sqlite3UnixIoMethod = { + unixClose, + unixOpenDirectory, + unixRead, + unixWrite, + unixSeek, + unixTruncate, + unixSync, + unixSetFullSync, + unixFileHandle, + unixFileSize, + unixLock, + unixUnlock, + unixLockState, + unixCheckReservedLock, +}; + +/* +** Allocate memory for a unixFile. Initialize the new unixFile +** to the value given in pInit and return a pointer to the new +** OsFile. If we run out of memory, close the file and return NULL. +*/ +static int allocateUnixFile(unixFile *pInit, OsFile **pId){ + unixFile *pNew; + pNew = sqliteMalloc( sizeof(unixFile) ); + if( pNew==0 ){ + close(pInit->h); + releaseLockInfo(pInit->pLock); + releaseOpenCnt(pInit->pOpen); + *pId = 0; + return SQLITE_NOMEM; + }else{ + *pNew = *pInit; + pNew->pMethod = &sqlite3UnixIoMethod; + *pId = (OsFile*)pNew; + OpenCounter(+1); + return SQLITE_OK; + } +} + #endif /* SQLITE_OMIT_DISKIO */ /*************************************************************************** ** Everything above deals with file I/O. Everything that follows deals ** with other miscellanous aspects of the operating system interface @@ -1348,11 +1540,11 @@ /* ** Get information to seed the random number generator. The seed ** is written into the buffer zBuf[256]. The calling function must ** supply a sufficiently large buffer. */ -int sqlite3OsRandomSeed(char *zBuf){ +int sqlite3UnixRandomSeed(char *zBuf){ /* We have to initialize zBuf to prevent valgrind from reporting ** errors. The reports issued by valgrind are incorrect - we would ** prefer that the randomness be increased by making use of the ** uninitialized space in zBuf - but valgrind errors tend to worry ** some users. Rather than argue, it seems easier just to initialize @@ -1367,11 +1559,13 @@ #if !defined(SQLITE_TEST) { int pid, fd; fd = open("/dev/urandom", O_RDONLY); if( fd<0 ){ - time((time_t*)zBuf); + time_t t; + time(&t); + memcpy(zBuf, &t, sizeof(t)); pid = getpid(); memcpy(&zBuf[sizeof(time_t)], &pid, sizeof(pid)); }else{ read(fd, zBuf, 256); close(fd); @@ -1382,11 +1576,11 @@ } /* ** Sleep for a little while. Return the amount of time slept. */ -int sqlite3OsSleep(int ms){ +int sqlite3UnixSleep(int ms){ #if defined(HAVE_USLEEP) && HAVE_USLEEP usleep(ms*1000); return ms; #else sleep((ms+999)/1000); @@ -1408,24 +1602,94 @@ ** executed code that is surrounded by EnterMutex() and LeaveMutex(). ** ** SQLite uses only a single Mutex. There is not much critical ** code and what little there is executes quickly and without blocking. */ -void sqlite3OsEnterMutex(){ +void sqlite3UnixEnterMutex(){ #ifdef SQLITE_UNIX_THREADS pthread_mutex_lock(&mutex); #endif assert( !inMutex ); inMutex = 1; } -void sqlite3OsLeaveMutex(){ +void sqlite3UnixLeaveMutex(){ assert( inMutex ); inMutex = 0; #ifdef SQLITE_UNIX_THREADS pthread_mutex_unlock(&mutex); #endif } + +/* +** Return TRUE if we are currently within the mutex and FALSE if not. +*/ +int sqlite3UnixInMutex(){ + return inMutex; +} + +/* +** This function is called automatically when a thread exists to delete +** the threads ThreadData structure. +** +** Because the ThreadData structure is required by higher level routines +** such as sqliteMalloc() we use OsFree() and OsMalloc() directly to +** allocate the thread specific data. +*/ +#ifdef SQLITE_UNIX_THREADS +static void deleteTsd(void *pTsd){ + sqlite3OsFree(pTsd); +} +#endif + +/* +** The first time this function is called from a specific thread, nByte +** bytes of data area are allocated and zeroed. A pointer to the new +** allocation is returned to the caller. +** +** Each subsequent call to this function from the thread returns the same +** pointer. The argument is ignored in this case. +*/ +void *sqlite3UnixThreadSpecificData(int nByte){ +#ifdef SQLITE_UNIX_THREADS + static pthread_key_t key; + static int keyInit = 0; + void *pTsd; + + if( !keyInit ){ + sqlite3OsEnterMutex(); + if( !keyInit ){ + int rc; + rc = pthread_key_create(&key, deleteTsd); + if( rc ){ + sqlite3OsLeaveMutex(); + return 0; + } + keyInit = 1; + } + sqlite3OsLeaveMutex(); + } + + pTsd = pthread_getspecific(key); + if( !pTsd ){ + pTsd = sqlite3OsMalloc(nByte); + if( pTsd ){ + memset(pTsd, 0, nByte); + pthread_setspecific(key, pTsd); + } + } + return pTsd; +#else + static void *pTsd = 0; + if( !pTsd ){ + pTsd = sqlite3OsMalloc(nByte); + if( pTsd ){ + memset(pTsd, 0, nByte); + } + } + return pTsd; +#endif +} /* ** The following variable, if set to a non-zero value, becomes the result ** returned from sqlite3OsCurrentTime(). This is used for testing. */ @@ -1436,11 +1700,11 @@ /* ** Find the current time (in Universal Coordinated Time). Write the ** current time and date as a Julian Day number into *prNow and ** return 0. Return 1 if the time and date cannot be found. */ -int sqlite3OsCurrentTime(double *prNow){ +int sqlite3UnixCurrentTime(double *prNow){ #ifdef NO_GETTOD time_t t; time(&t); *prNow = t/86400.0 + 2440587.5; #else DELETED SQLite.Interop/src/os_unix.h Index: SQLite.Interop/src/os_unix.h ================================================================== --- SQLite.Interop/src/os_unix.h +++ /dev/null @@ -1,116 +0,0 @@ -/* -** 2004 May 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This header file defined OS-specific features for Unix. -*/ -#ifndef _SQLITE_OS_UNIX_H_ -#define _SQLITE_OS_UNIX_H_ - -/* -** Helpful hint: To get this to compile on HP/UX, add -D_INCLUDE_POSIX_SOURCE -** to the compiler command line. -*/ - -/* -** These #defines should enable >2GB file support on Posix if the -** underlying operating system supports it. If the OS lacks -** large file support, or if the OS is windows, these should be no-ops. -** -** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch -** on the compiler command line. This is necessary if you are compiling -** on a recent machine (ex: RedHat 7.2) but you want your code to work -** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2 -** without this option, LFS is enable. But LFS does not exist in the kernel -** in RedHat 6.0, so the code won't work. Hence, for maximum binary -** portability you should omit LFS. -** -** Similar is true for MacOS. LFS is only supported on MacOS 9 and later. -*/ -#ifndef SQLITE_DISABLE_LFS -# define _LARGE_FILE 1 -# ifndef _FILE_OFFSET_BITS -# define _FILE_OFFSET_BITS 64 -# endif -# define _LARGEFILE_SOURCE 1 -#endif - -/* -** standard include files. -*/ -#include -#include -#include -#include - -/* -** Macros used to determine whether or not to use threads. The -** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for -** Posix threads and SQLITE_W32_THREADS is defined if we are -** synchronizing using Win32 threads. -*/ -#if defined(THREADSAFE) && THREADSAFE -# include -# define SQLITE_UNIX_THREADS 1 -#endif - -/* -** The OsFile structure is a operating-system independing representation -** of an open file handle. It is defined differently for each architecture. -** -** This is the definition for Unix. -** -** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK, -** PENDING_LOCK or EXCLUSIVE_LOCK. -*/ -typedef struct OsFile OsFile; -struct OsFile { - struct Pager *pPager; /* The pager that owns this OsFile. Might be 0 */ - struct openCnt *pOpen; /* Info about all open fd's on this inode */ - struct lockInfo *pLock; /* Info about locks on this inode */ - int h; /* The file descriptor */ - unsigned char locktype; /* The type of lock held on this fd */ - unsigned char isOpen; /* True if needs to be closed */ - unsigned char fullSync; /* Use F_FULLSYNC if available */ - int dirfd; /* File descriptor for the directory */ -#ifdef SQLITE_UNIX_THREADS - pthread_t tid; /* The thread authorized to use this OsFile */ -#endif -}; - -/* -** A macro to set the OsFile.fullSync flag, if it exists. -*/ -#define SET_FULLSYNC(x,y) ((x).fullSync = (y)) - -/* -** Maximum number of characters in a temporary file name -*/ -#define SQLITE_TEMPNAME_SIZE 200 - -/* -** Minimum interval supported by sqlite3OsSleep(). -*/ -#if defined(HAVE_USLEEP) && HAVE_USLEEP -# define SQLITE_MIN_SLEEP_MS 1 -#else -# define SQLITE_MIN_SLEEP_MS 1000 -#endif - -/* -** Default permissions when creating a new file -*/ -#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS -# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 -#endif - - -#endif /* _SQLITE_OS_UNIX_H_ */ Index: SQLite.Interop/src/os_win.c ================================================================== --- SQLite.Interop/src/os_win.c +++ SQLite.Interop/src/os_win.c @@ -31,10 +31,54 @@ /* ** Include code that is common to all os_*.c files */ #include "os_common.h" + +/* +** Determine if we are dealing with WindowsCE - which has a much +** reduced API. +*/ +#if defined(_WIN32_WCE) +# define OS_WINCE 1 +#else +# define OS_WINCE 0 +#endif + +#if OS_WINCE +typedef struct _LOCKDATA +{ + long nReaders; + long nPending; + long nReserved; + long nExclusive; +} LOCKDATA; +#endif + +/* +** The winFile structure is a subclass of OsFile specific to the win32 +** portability layer. +*/ +typedef struct winFile winFile; +struct winFile { + IoMethod const *pMethod;/* Must be first */ + HANDLE h; /* Handle for accessing the file */ + unsigned char locktype; /* Type of lock currently held on this file */ + short sharedLockByte; /* Randomly chosen byte used as a shared lock */ +#if OS_WINCE + WCHAR *zDeleteOnClose; /* Name of file to delete when closing */ + +#ifndef SQLITE_OMIT_WIN_LOCKS + HANDLE hMutex; + HANDLE hShared; + LOCKDATA local; + LOCKDATA *shared; +#endif + +#endif +}; + /* ** Do not include any of the File I/O interface procedures if the ** SQLITE_OMIT_DISKIO macro is defined (indicating that there database ** will be in-memory only) @@ -54,29 +98,81 @@ ** can manually set this value to 1 to emulate Win98 behavior. */ int sqlite3_os_type = 0; /* -** Return true (non-zero) if we are running under WinNT, Win2K or WinXP. -** Return false (zero) for Win95, Win98, or WinME. +** Return true (non-zero) if we are running under WinNT, Win2K, WinXP, +** or WinCE. Return false (zero) for Win95, Win98, or WinME. ** ** Here is an interesting observation: Win95, Win98, and WinME lack ** the LockFileEx() API. But we can still statically link against that ** API as long as we don't call it win running Win95/98/ME. A call to ** this routine is used to determine if the host is Win95/98/ME or ** WinNT/2K/XP so that we will know whether or not we can safely call ** the LockFileEx() API. */ -static int isNT(void){ - if( sqlite3_os_type==0 ){ - OSVERSIONINFO sInfo; - sInfo.dwOSVersionInfoSize = sizeof(sInfo); - GetVersionEx(&sInfo); - sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; - } - return sqlite3_os_type==2; -} +#if OS_WINCE +# define isNT() (1) +#else + static int isNT(void){ + if( sqlite3_os_type==0 ){ + OSVERSIONINFO sInfo; + sInfo.dwOSVersionInfoSize = sizeof(sInfo); + GetVersionEx(&sInfo); + sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1; + } + return sqlite3_os_type==2; + } +#endif /* OS_WINCE */ + +#if OS_WINCE +/* +** WindowsCE does not have a localtime() function. So create a +** substitute. +*/ +#include +struct tm *__cdecl localtime(const time_t *t) +{ + static struct tm y; + FILETIME uTm, lTm; + SYSTEMTIME pTm; + i64 t64; + t64 = *t; + t64 = (t64 + 11644473600)*10000000; + uTm.dwLowDateTime = t64 & 0xFFFFFFFF; + uTm.dwHighDateTime= t64 >> 32; + FileTimeToLocalFileTime(&uTm,&lTm); + FileTimeToSystemTime(&lTm,&pTm); + y.tm_year = pTm.wYear - 1900; + y.tm_mon = pTm.wMonth - 1; + y.tm_wday = pTm.wDayOfWeek; + y.tm_mday = pTm.wDay; + y.tm_hour = pTm.wHour; + y.tm_min = pTm.wMinute; + y.tm_sec = pTm.wSecond; + return &y; +} + +/* This will never be called, but defined to make the code compile */ +#define GetTempPathA(a,b) + +#endif + +/* +** Compile with -DSQLITE_OMIT_WIN_LOCKS to disable file locking on +** windows. If you do this and two or more connections attempt to +** write the database at the same time, the database file will be +** corrupted. But some versions of WindowsCE do not support locking, +** in which case compiling with this option is required just to get +** it to work at all. +*/ +#ifdef SQLITE_OMIT_WIN_LOCKS +# define LockFile(a,b,c,d,e) (1) +# define LockFileEx(a,b,c,d,e,f) (1) +# define UnlockFile(a,b,c,d,e) (1) +# define UnlockFileEx(a,b,c,d,e) (1) +#endif /* ** Convert a UTF-8 string to UTF-32. Space to hold the returned string ** is obtained from sqliteMalloc. */ @@ -120,42 +216,305 @@ zFilename = 0; } return zFilename; } +#if OS_WINCE && !SQLITE_OMIT_WIN_LOCKS +#define LockFile(a, b, c, d, e) pseudoLockFile(&a, b, c, d, e) +#define UnlockFile(a, b, c, d, e) pseudoUnlockFile(&a, b, c, d, e) +#define LockFileEx(a, b, c, d, e, f) pseudoLockFileEx(&a, b, c, d, e, f) + +#define LOCKSTRUCT winFile + +#ifndef PtrToInt +#define PtrToInt( p ) ((INT)(INT_PTR) (p) ) +#endif + +#define HANDLE_TO_LOCKSTRUCT(a) (LOCKSTRUCT *)&((LPBYTE)a)[-PtrToInt((&((LOCKSTRUCT *)0)->h))] + +#define MUTEX_ACQUIRE(h) { DWORD dwErr; do { dwErr = WaitForSingleObject(h, INFINITE); } while (dwErr != WAIT_OBJECT_0 && dwErr != WAIT_ABANDONED); } +#define MUTEX_RELEASE(h) ReleaseMutex(h) + +static BOOL CreateLockStruct(const char *pszFilename, LOCKSTRUCT *pLocks) +{ + WCHAR *pszTok; + WCHAR *pszName = utf8ToUnicode(pszFilename); + BOOL bInit = TRUE; + + /* Initialize the local lockdata */ + ZeroMemory(&pLocks->local, sizeof(LOCKDATA)); + + /* Create a unique global name for the mutex and subsequently the shared memory */ + _wcslwr(pszName); + while (pszTok = wcschr(pszName, '\\')) + { + *pszTok = '_'; + } + + /* Create/open the named mutex */ + pLocks->hMutex = CreateMutexW(NULL, FALSE, pszName); + if (!pLocks->hMutex) + { + sqliteFree(pszName); + return FALSE; + } + + /* Acquire the mutex before continuing */ + MUTEX_ACQUIRE(pLocks->hMutex); + + /* Create/open the shared memory */ + _wcsupr(pszName); + pLocks->hShared = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(LOCKDATA), pszName); + + /* Set a flag that indicates we're the first to create the memory so it must be zero-initialized */ + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + bInit = FALSE; + } + + sqliteFree(pszName); + + /* If we succeeded in making the shared memory handle, map it. */ + if (pLocks->hShared) + { + pLocks->shared = (LOCKDATA *)MapViewOfFile(pLocks->hShared, FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(LOCKDATA)); + /* If mapping failed, close the shared memory handle and erase it */ + if (!pLocks->shared) + { + CloseHandle(pLocks->hShared); + pLocks->hShared = NULL; + } + } + + /* If shared memory could not be created, then close the mutex and fail */ + if (pLocks->hShared == NULL) + { + MUTEX_RELEASE(pLocks->hMutex); + CloseHandle(pLocks->hMutex); + pLocks->hMutex = NULL; + return FALSE; + } + + /* Initialize the shared memory if we're supposed to */ + if (bInit) + { + ZeroMemory(pLocks->shared, sizeof(LOCKDATA)); + } + + MUTEX_RELEASE(pLocks->hMutex); + + return TRUE; +} + +static void DestroyLockStruct(LOCKSTRUCT *pLocks) +{ + if (pLocks->hMutex) + { + /* Acquire the mutex */ + MUTEX_ACQUIRE(pLocks->hMutex); + + /* The following blocks should probably assert in debug mode, but they + are to cleanup in case any locks remained open */ + if (pLocks->local.nReaders) + { + pLocks->shared->nReaders --; + } + + if (pLocks->local.nReserved) + { + pLocks->shared->nReserved = 0; + } + + if (pLocks->local.nPending) + { + pLocks->shared->nPending = 0; + } + + if (pLocks->local.nExclusive) + { + pLocks->shared->nExclusive = 0; + } + + /* De-reference and close our copy of the shared memory handle */ + UnmapViewOfFile(pLocks->shared); + CloseHandle(pLocks->hShared); + + /* Done with the mutex */ + MUTEX_RELEASE(pLocks->hMutex); + CloseHandle(pLocks->hMutex); + pLocks->hMutex = NULL; + } +} + +/* Custom pseudo file locking support specifically for SQLite */ +BOOL pseudoLockFile(HANDLE *phFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh) +{ + LOCKSTRUCT *pls = HANDLE_TO_LOCKSTRUCT(phFile); + BOOL bReturn = FALSE; + + if (!pls->hMutex) return TRUE; + + MUTEX_ACQUIRE(pls->hMutex); + + /* Wanting an exclusive lock? */ + if (dwFileOffsetLow == SHARED_FIRST && nNumberOfBytesToLockLow == SHARED_SIZE) + { + if (pls->shared->nReaders == 0 && pls->shared->nExclusive == 0) + { + pls->shared->nExclusive = 1; + pls->local.nExclusive = 1; + bReturn = TRUE; + } + } + /* Want a read-only lock? */ + else if ((dwFileOffsetLow >= SHARED_FIRST && dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE) && nNumberOfBytesToLockLow == 1) + { + if (pls->shared->nExclusive == 0) + { + pls->local.nReaders ++; + if (pls->local.nReaders == 1) + { + pls->shared->nReaders ++; + } + bReturn = TRUE; + } + } + /* Want a pending lock? */ + else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToLockLow == 1) + { + /* If no pending lock has been acquired, then acquire it */ + if (pls->shared->nPending == 0) + { + pls->shared->nPending = 1; + pls->local.nPending = 1; + bReturn = TRUE; + } + } + /* Want a reserved lock? */ + else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToLockLow == 1) + { + if (pls->shared->nReserved == 0) + { + pls->shared->nReserved = 1; + pls->local.nReserved = 1; + bReturn = TRUE; + } + } + + MUTEX_RELEASE(pls->hMutex); + + return bReturn; +} + +BOOL pseudoUnlockFile(HANDLE *phFile, DWORD dwFileOffsetLow, DWORD dwFileOffsetHigh, DWORD nNumberOfBytesToUnlockLow, DWORD nNumberOfBytesToUnlockHigh) +{ + LOCKSTRUCT *pls = HANDLE_TO_LOCKSTRUCT(phFile); + BOOL bReturn = FALSE; + + if (!pls->hMutex) return TRUE; + + MUTEX_ACQUIRE(pls->hMutex); + + /* Releasing a reader lock or an exclusive lock */ + if (dwFileOffsetLow >= SHARED_FIRST && dwFileOffsetLow < SHARED_FIRST + SHARED_SIZE) + { + /* Did we have an exclusive lock? */ + if (pls->local.nExclusive) + { + pls->local.nExclusive = 0; + pls->shared->nExclusive = 0; + bReturn = TRUE; + } + /* Did we just have a reader lock? */ + else if (pls->local.nReaders) + { + pls->local.nReaders --; + if (pls->local.nReaders == 0) + { + pls->shared->nReaders --; + } + bReturn = TRUE; + } + } + /* Releasing a pending lock */ + else if (dwFileOffsetLow == PENDING_BYTE && nNumberOfBytesToUnlockLow == 1) + { + if (pls->local.nPending) + { + pls->local.nPending = 0; + pls->shared->nPending = 0; + bReturn = TRUE; + } + } + /* Releasing a reserved lock */ + else if (dwFileOffsetLow == RESERVED_BYTE && nNumberOfBytesToUnlockLow == 1) + { + if (pls->local.nReserved) + { + pls->local.nReserved = 0; + pls->shared->nReserved = 0; + bReturn = TRUE; + } + } + + MUTEX_RELEASE(pls->hMutex); + + return bReturn; +} + +BOOL pseudoLockFileEx(HANDLE *phFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped) +{ + /* If the caller wants a shared read lock, forward this call to pseudoLockFile */ + if (lpOverlapped->Offset == SHARED_FIRST && dwFlags == 1 && nNumberOfBytesToLockLow == SHARED_SIZE) + return pseudoLockFile(phFile, SHARED_FIRST, 0, 1, 0); + + return FALSE; +} + +#endif /* OS_WINCE && !SQLITE_OMIT_WIN_LOCKS */ /* ** Delete the named file */ -int sqlite3OsDelete(const char *zFilename){ +int sqlite3WinDelete(const char *zFilename){ WCHAR *zWide = utf8ToUnicode(zFilename); if( zWide ){ DeleteFileW(zWide); sqliteFree(zWide); }else{ +#if OS_WINCE + return SQLITE_NOMEM; +#else DeleteFileA(zFilename); +#endif } TRACE2("DELETE \"%s\"\n", zFilename); return SQLITE_OK; } /* ** Return TRUE if the named file exists. */ -int sqlite3OsFileExists(const char *zFilename){ +int sqlite3WinFileExists(const char *zFilename){ int exists = 0; WCHAR *zWide = utf8ToUnicode(zFilename); if( zWide ){ exists = GetFileAttributesW(zWide) != 0xffffffff; sqliteFree(zWide); }else{ +#if OS_WINCE + return SQLITE_NOMEM; +#else exists = GetFileAttributesA(zFilename) != 0xffffffff; +#endif } return exists; } -#ifndef _WIN32_WCE +/* Forward declaration */ +int allocateWinFile(winFile *pInit, OsFile **pId); + /* ** Attempt to open a file for both reading and writing. If that ** fails, try opening it read-only. If the file does not exist, ** try to create it. ** @@ -165,18 +524,19 @@ ** SQLITE_OK. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id and *pReadonly unchanged. */ -int sqlite3OsOpenReadWrite( +int sqlite3WinOpenReadWrite( const char *zFilename, - OsFile *id, + OsFile **pId, int *pReadonly ){ + winFile f; HANDLE h; WCHAR *zWide = utf8ToUnicode(zFilename); - assert( !id->isOpen ); + assert( *pId==0 ); if( zWide ){ h = CreateFileW(zWide, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, @@ -199,12 +559,22 @@ } *pReadonly = 1; }else{ *pReadonly = 0; } +#if OS_WINCE && !SQLITE_OMIT_WIN_LOCKS + if (!CreateLockStruct(zFilename, &f)){ + CloseHandle(h); + sqliteFree(zWide); + return SQLITE_CANTOPEN; + } +#endif sqliteFree(zWide); }else{ +#if OS_WINCE + return SQLITE_NOMEM; +#else h = CreateFileA(zFilename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, @@ -225,18 +595,20 @@ } *pReadonly = 1; }else{ *pReadonly = 0; } +#endif /* OS_WINCE */ } - id->h = h; - id->locktype = NO_LOCK; - id->sharedLockByte = 0; - id->isOpen = 1; - OpenCounter(+1); + f.h = h; + f.locktype = NO_LOCK; + f.sharedLockByte = 0; +#if OS_WINCE + f.zDeleteOnClose = 0; +#endif TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename); - return SQLITE_OK; + return allocateWinFile(&f, pId); } /* ** Attempt to open a new file for exclusive access by this process. @@ -250,21 +622,22 @@ ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ -int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ +int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){ + winFile f; HANDLE h; int fileflags; WCHAR *zWide = utf8ToUnicode(zFilename); - assert( !id->isOpen ); + assert( *pId == 0 ); + fileflags = FILE_FLAG_RANDOM_ACCESS; +#if !OS_WINCE if( delFlag ){ - fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS - | FILE_FLAG_DELETE_ON_CLOSE; - }else{ - fileflags = FILE_FLAG_RANDOM_ACCESS; + fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE; } +#endif if( zWide ){ h = CreateFileW(zWide, GENERIC_READ | GENERIC_WRITE, 0, NULL, @@ -272,42 +645,51 @@ fileflags, NULL ); sqliteFree(zWide); }else{ +#if OS_WINCE + return SQLITE_NOMEM; +#else h = CreateFileA(zFilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, fileflags, NULL ); +#endif /* OS_WINCE */ } if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } - id->h = h; - id->locktype = NO_LOCK; - id->sharedLockByte = 0; - id->isOpen = 1; - OpenCounter(+1); + f.h = h; + f.locktype = NO_LOCK; + f.sharedLockByte = 0; +#if OS_WINCE + f.zDeleteOnClose = delFlag ? utf8ToUnicode(zFilename) : 0; +#ifndef SQLITE_OMIT_WIN_LOCKS + f.hMutex = NULL; +#endif +#endif TRACE3("OPEN EX %d \"%s\"\n", h, zFilename); - return SQLITE_OK; + return allocateWinFile(&f, pId); } /* ** Attempt to open a new file for read-only access. ** ** On success, write the file handle into *id and return SQLITE_OK. ** ** On failure, return SQLITE_CANTOPEN. */ -int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){ +int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){ + winFile f; HANDLE h; WCHAR *zWide = utf8ToUnicode(zFilename); - assert( !id->isOpen ); + assert( *pId==0 ); if( zWide ){ h = CreateFileW(zWide, GENERIC_READ, 0, NULL, @@ -315,31 +697,38 @@ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL ); sqliteFree(zWide); }else{ +#if OS_WINCE + return SQLITE_NOMEM; +#else h = CreateFileA(zFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL ); +#endif } if( h==INVALID_HANDLE_VALUE ){ return SQLITE_CANTOPEN; } - id->h = h; - id->locktype = NO_LOCK; - id->sharedLockByte = 0; - id->isOpen = 1; - OpenCounter(+1); + f.h = h; + f.locktype = NO_LOCK; + f.sharedLockByte = 0; +#if OS_WINCE + f.zDeleteOnClose = 0; +#ifndef SQLITE_OMIT_WIN_LOCKS + f.hMutex = NULL; +#endif +#endif TRACE3("OPEN RO %d \"%s\"\n", h, zFilename); - return SQLITE_OK; + return allocateWinFile(&f, pId); } -#endif // _WIN32_WCE /* ** Attempt to open a file descriptor for the directory that contains a ** file. This file descriptor can be used to fsync() the directory ** in order to make sure the creation of a new file is actually written @@ -353,13 +742,13 @@ ** returned. ** ** On failure, the function returns SQLITE_CANTOPEN and leaves ** *id unchanged. */ -int sqlite3OsOpenDirectory( - const char *zDirname, - OsFile *id +static int winOpenDirectory( + OsFile *id, + const char *zDirname ){ return SQLITE_OK; } /* @@ -371,11 +760,11 @@ /* ** Create a temporary file name in zBuf. zBuf must be big enough to ** hold at least SQLITE_TEMPNAME_SIZE characters. */ -int sqlite3OsTempFileName(char *zBuf){ +int sqlite3WinTempFileName(char *zBuf){ static char zChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; int i, j; @@ -410,36 +799,45 @@ } TRACE2("TEMP FILENAME: %s\n", zBuf); return SQLITE_OK; } -#ifndef _WIN32_WCE /* ** Close a file. */ -int sqlite3OsClose(OsFile *id){ - if( id->isOpen ){ - TRACE2("CLOSE %d\n", id->h); - CloseHandle(id->h); +static int winClose(OsFile **pId){ + winFile *pFile; + if( pId && (pFile = (winFile*)*pId)!=0 ){ + TRACE2("CLOSE %d\n", pFile->h); + CloseHandle(pFile->h); +#if OS_WINCE +#ifndef SQLITE_OMIT_WIN_LOCKS + DestroyLockStruct(pFile); +#endif + if( pFile->zDeleteOnClose ){ + DeleteFileW(pFile->zDeleteOnClose); + sqliteFree(pFile->zDeleteOnClose); + } +#endif OpenCounter(-1); - id->isOpen = 0; + sqliteFree(pFile); + *pId = 0; } return SQLITE_OK; } -#endif // _WIN32_WCE /* ** Read data from a file into a buffer. Return SQLITE_OK if all ** bytes were read successfully and SQLITE_IOERR if anything goes ** wrong. */ -int sqlite3OsRead(OsFile *id, void *pBuf, int amt){ +static int winRead(OsFile *id, void *pBuf, int amt){ DWORD got; - assert( id->isOpen ); + assert( id!=0 ); SimulateIOError(SQLITE_IOERR); - TRACE3("READ %d lock=%d\n", id->h, id->locktype); - if( !ReadFile(id->h, pBuf, amt, &got, 0) ){ + TRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype); + if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){ got = 0; } if( got==(DWORD)amt ){ return SQLITE_OK; }else{ @@ -449,19 +847,20 @@ /* ** Write data from a buffer into a file. Return SQLITE_OK on success ** or some other error code on failure. */ -int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ +static int winWrite(OsFile *id, const void *pBuf, int amt){ int rc = 0; DWORD wrote; - assert( id->isOpen ); + assert( id!=0 ); SimulateIOError(SQLITE_IOERR); SimulateDiskfullError; - TRACE3("WRITE %d lock=%d\n", id->h, id->locktype); + TRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype); assert( amt>0 ); - while( amt>0 && (rc = WriteFile(id->h, pBuf, amt, &wrote, 0))!=0 && wrote>0 ){ + while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0 + && wrote>0 ){ amt -= wrote; pBuf = &((char*)pBuf)[wrote]; } if( !rc || amt>(int)wrote ){ return SQLITE_FULL; @@ -477,34 +876,34 @@ #endif /* ** Move the read/write pointer in a file. */ -int sqlite3OsSeek(OsFile *id, i64 offset){ +static int winSeek(OsFile *id, i64 offset){ LONG upperBits = offset>>32; LONG lowerBits = offset & 0xffffffff; DWORD rc; - assert( id->isOpen ); + assert( id!=0 ); #ifdef SQLITE_TEST if( offset ) SimulateDiskfullError #endif SEEK(offset/1024 + 1); - rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN); - TRACE3("SEEK %d %lld\n", id->h, offset); + rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN); + TRACE3("SEEK %d %lld\n", ((winFile*)id)->h, offset); if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){ return SQLITE_FULL; } return SQLITE_OK; } /* ** Make sure all writes to a particular file are committed to disk. */ -int sqlite3OsSync(OsFile *id, int dataOnly){ - assert( id->isOpen ); - TRACE3("SYNC %d lock=%d\n", id->h, id->locktype); - if( FlushFileBuffers(id->h) ){ +static int winSync(OsFile *id, int dataOnly){ + assert( id!=0 ); + TRACE3("SYNC %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype); + if( FlushFileBuffers(((winFile*)id)->h) ){ return SQLITE_OK; }else{ return SQLITE_IOERR; } } @@ -511,47 +910,53 @@ /* ** Sync the directory zDirname. This is a no-op on operating systems other ** than UNIX. */ -int sqlite3OsSyncDirectory(const char *zDirname){ +int sqlite3WinSyncDirectory(const char *zDirname){ SimulateIOError(SQLITE_IOERR); return SQLITE_OK; } /* ** Truncate an open file to a specified size */ -int sqlite3OsTruncate(OsFile *id, i64 nByte){ +static int winTruncate(OsFile *id, i64 nByte){ LONG upperBits = nByte>>32; - assert( id->isOpen ); - TRACE3("TRUNCATE %d %lld\n", id->h, nByte); + assert( id!=0 ); + TRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte); SimulateIOError(SQLITE_IOERR); - SetFilePointer(id->h, nByte, &upperBits, FILE_BEGIN); - SetEndOfFile(id->h); + SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN); + SetEndOfFile(((winFile*)id)->h); return SQLITE_OK; } /* ** Determine the current size of a file in bytes */ -int sqlite3OsFileSize(OsFile *id, i64 *pSize){ +static int winFileSize(OsFile *id, i64 *pSize){ DWORD upperBits, lowerBits; - assert( id->isOpen ); + assert( id!=0 ); SimulateIOError(SQLITE_IOERR); - lowerBits = GetFileSize(id->h, &upperBits); + lowerBits = GetFileSize(((winFile*)id)->h, &upperBits); *pSize = (((i64)upperBits)<<32) + lowerBits; return SQLITE_OK; } -#ifndef _WIN32_WCE +/* +** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. +*/ +#ifndef LOCKFILE_FAIL_IMMEDIATELY +# define LOCKFILE_FAIL_IMMEDIATELY 1 +#endif + /* ** Acquire a reader lock. ** Different API routines are called depending on whether or not this ** is Win95 or WinNT. */ -static int getReadLock(OsFile *id){ +static int getReadLock(winFile *id){ int res; if( isNT() ){ OVERLAPPED ovlp; ovlp.Offset = SHARED_FIRST; ovlp.OffsetHigh = 0; @@ -567,36 +972,40 @@ } /* ** Undo a readlock */ -static int unlockReadLock(OsFile *id){ +static int unlockReadLock(winFile *pFile){ int res; if( isNT() ){ - res = UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0); + res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); }else{ - res = UnlockFile(id->h, SHARED_FIRST + id->sharedLockByte, 0, 1, 0); + res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0); } return res; } #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* ** Check that a given pathname is a directory and is writable ** */ -int sqlite3OsIsDirWritable(char *zDirname){ +int sqlite3WinIsDirWritable(char *zDirname){ int fileAttr; WCHAR *zWide; if( zDirname==0 ) return 0; if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0; zWide = utf8ToUnicode(zDirname); if( zWide ){ fileAttr = GetFileAttributesW(zWide); sqliteFree(zWide); }else{ +#if OS_WINCE + return 0; +#else fileAttr = GetFileAttributesA(zDirname); +#endif } if( fileAttr == 0xffffffff ) return 0; if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){ return 0; } @@ -623,49 +1032,50 @@ ** SHARED -> RESERVED ** SHARED -> (PENDING) -> EXCLUSIVE ** RESERVED -> (PENDING) -> EXCLUSIVE ** PENDING -> EXCLUSIVE ** -** This routine will only increase a lock. The sqlite3OsUnlock() routine +** This routine will only increase a lock. The winUnlock() routine ** erases all locks at once and returns us immediately to locking level 0. ** It is not possible to lower the locking level one step at a time. You ** must go straight to locking level 0. */ -int sqlite3OsLock(OsFile *id, int locktype){ +static int winLock(OsFile *id, int locktype){ int rc = SQLITE_OK; /* Return code from subroutines */ int res = 1; /* Result of a windows lock call */ int newLocktype; /* Set id->locktype to this value before exiting */ int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ + winFile *pFile = (winFile*)id; - assert( id->isOpen ); + assert( pFile!=0 ); TRACE5("LOCK %d %d was %d(%d)\n", - id->h, locktype, id->locktype, id->sharedLockByte); + pFile->h, locktype, pFile->locktype, pFile->sharedLockByte); /* If there is already a lock of this type or more restrictive on the ** OsFile, do nothing. Don't use the end_lock: exit path, as ** sqlite3OsEnterMutex() hasn't been called yet. */ - if( id->locktype>=locktype ){ + if( pFile->locktype>=locktype ){ return SQLITE_OK; } /* Make sure the locking sequence is correct */ - assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK ); + assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); assert( locktype!=PENDING_LOCK ); - assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK ); + assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK ); /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of ** the PENDING_LOCK byte is temporary. */ - newLocktype = id->locktype; - if( id->locktype==NO_LOCK - || (locktype==EXCLUSIVE_LOCK && id->locktype==RESERVED_LOCK) + newLocktype = pFile->locktype; + if( pFile->locktype==NO_LOCK + || (locktype==EXCLUSIVE_LOCK && pFile->locktype==RESERVED_LOCK) ){ int cnt = 3; - while( cnt-->0 && (res = LockFile(id->h, PENDING_BYTE, 0, 1, 0))==0 ){ + while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){ /* Try 3 times to get the pending lock. The pending lock might be ** held by another reader process who will release it momentarily. */ TRACE2("could not get a PENDING lock. cnt=%d\n", cnt); Sleep(1); @@ -674,22 +1084,22 @@ } /* Acquire a shared lock */ if( locktype==SHARED_LOCK && res ){ - assert( id->locktype==NO_LOCK ); - res = getReadLock(id); + assert( pFile->locktype==NO_LOCK ); + res = getReadLock(pFile); if( res ){ newLocktype = SHARED_LOCK; } } /* Acquire a RESERVED lock */ if( locktype==RESERVED_LOCK && res ){ - assert( id->locktype==SHARED_LOCK ); - res = LockFile(id->h, RESERVED_BYTE, 0, 1, 0); + assert( pFile->locktype==SHARED_LOCK ); + res = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); if( res ){ newLocktype = RESERVED_LOCK; } } @@ -701,14 +1111,14 @@ } /* Acquire an EXCLUSIVE lock */ if( locktype==EXCLUSIVE_LOCK && res ){ - assert( id->locktype>=SHARED_LOCK ); - res = unlockReadLock(id); + assert( pFile->locktype>=SHARED_LOCK ); + res = unlockReadLock(pFile); TRACE2("unreadlock = %d\n", res); - res = LockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0); + res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); if( res ){ newLocktype = EXCLUSIVE_LOCK; }else{ TRACE2("error-code = %d\n", GetLastError()); } @@ -716,45 +1126,46 @@ /* If we are holding a PENDING lock that ought to be released, then ** release it now. */ if( gotPendingLock && locktype==SHARED_LOCK ){ - UnlockFile(id->h, PENDING_BYTE, 0, 1, 0); + UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); } /* Update the state of the lock has held in the file descriptor then ** return the appropriate result code. */ if( res ){ rc = SQLITE_OK; }else{ - TRACE4("LOCK FAILED %d trying for %d but got %d\n", id->h, + TRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h, locktype, newLocktype); rc = SQLITE_BUSY; } - id->locktype = newLocktype; + pFile->locktype = newLocktype; return rc; } /* ** This routine checks if there is a RESERVED lock held on the specified ** file by this or any other process. If such a lock is held, return ** non-zero, otherwise zero. */ -int sqlite3OsCheckReservedLock(OsFile *id){ +static int winCheckReservedLock(OsFile *id){ int rc; - assert( id->isOpen ); - if( id->locktype>=RESERVED_LOCK ){ + winFile *pFile = (winFile*)id; + assert( pFile!=0 ); + if( pFile->locktype>=RESERVED_LOCK ){ rc = 1; - TRACE3("TEST WR-LOCK %d %d (local)\n", id->h, rc); + TRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc); }else{ - rc = LockFile(id->h, RESERVED_BYTE, 0, 1, 0); + rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); if( rc ){ - UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0); + UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); } rc = !rc; - TRACE3("TEST WR-LOCK %d %d (remote)\n", id->h, rc); + TRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc); } return rc; } /* @@ -766,58 +1177,61 @@ ** ** It is not possible for this routine to fail if the second argument ** is NO_LOCK. If the second argument is SHARED_LOCK then this routine ** might return SQLITE_IOERR; */ -int sqlite3OsUnlock(OsFile *id, int locktype){ +static int winUnlock(OsFile *id, int locktype){ int type; int rc = SQLITE_OK; - assert( id->isOpen ); + winFile *pFile = (winFile*)id; + assert( pFile!=0 ); assert( locktype<=SHARED_LOCK ); - TRACE5("UNLOCK %d to %d was %d(%d)\n", id->h, locktype, - id->locktype, id->sharedLockByte); - type = id->locktype; + TRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype, + pFile->locktype, pFile->sharedLockByte); + type = pFile->locktype; if( type>=EXCLUSIVE_LOCK ){ - UnlockFile(id->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( locktype==SHARED_LOCK && !getReadLock(id) ){ + UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); + if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ /* This should never happen. We should always be able to ** reacquire the read lock */ rc = SQLITE_IOERR; } } if( type>=RESERVED_LOCK ){ - UnlockFile(id->h, RESERVED_BYTE, 0, 1, 0); + UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); } if( locktype==NO_LOCK && type>=SHARED_LOCK ){ - unlockReadLock(id); + unlockReadLock(pFile); } if( type>=PENDING_LOCK ){ - UnlockFile(id->h, PENDING_BYTE, 0, 1, 0); + UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); } - id->locktype = locktype; + pFile->locktype = locktype; return rc; } -#endif // _WIN32_WCE - /* ** Turn a relative pathname into a full pathname. Return a pointer ** to the full pathname stored in space obtained from sqliteMalloc(). ** The calling function is responsible for freeing this space once it ** is no longer needed. */ -char *sqlite3OsFullPathname(const char *zRelative){ - char *zNotUsed; +char *sqlite3WinFullPathname(const char *zRelative){ char *zFull; - WCHAR *zWide; +#if defined(__CYGWIN__) int nByte; -#ifdef __CYGWIN__ nByte = strlen(zRelative) + MAX_PATH + 1001; zFull = sqliteMalloc( nByte ); if( zFull==0 ) return 0; if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0; +#elif OS_WINCE + /* WinCE has no concept of a relative pathname, or so I am told. */ + zFull = sqlite3StrDup(zRelative); #else + char *zNotUsed; + WCHAR *zWide; + int nByte; zWide = utf8ToUnicode(zRelative); if( zWide ){ WCHAR *zTemp, *zNotUsedW; nByte = GetFullPathNameW(zWide, 0, 0, &zNotUsedW) + 1; zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) ); @@ -833,10 +1247,77 @@ GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed); } #endif return zFull; } + +/* +** The fullSync option is meaningless on windows. This is a no-op. +*/ +static void winSetFullSync(OsFile *id, int v){ + return; +} + +/* +** Return the underlying file handle for an OsFile +*/ +static int winFileHandle(OsFile *id){ + return (int)((winFile*)id)->h; +} + +/* +** Return an integer that indices the type of lock currently held +** by this handle. (Used for testing and analysis only.) +*/ +static int winLockState(OsFile *id){ + return ((winFile*)id)->locktype; +} + +/* +** This vector defines all the methods that can operate on an OsFile +** for win32. +*/ +static const IoMethod sqlite3WinIoMethod = { + winClose, + winOpenDirectory, + winRead, + winWrite, + winSeek, + winTruncate, + winSync, + winSetFullSync, + winFileHandle, + winFileSize, + winLock, + winUnlock, + winLockState, + winCheckReservedLock, +}; + +/* +** Allocate memory for an OsFile. Initialize the new OsFile +** to the value given in pInit and return a pointer to the new +** OsFile. If we run out of memory, close the file and return NULL. +*/ +int allocateWinFile(winFile *pInit, OsFile **pId){ + winFile *pNew; + pNew = sqliteMalloc( sizeof(*pNew) ); + if( pNew==0 ){ + CloseHandle(pInit->h); +#if OS_WINCE + sqliteFree(pInit->zDeleteOnClose); +#endif + *pId = 0; + return SQLITE_NOMEM; + }else{ + *pNew = *pInit; + pNew->pMethod = &sqlite3WinIoMethod; + *pId = (OsFile*)pNew; + return SQLITE_OK; + } +} + #endif /* SQLITE_OMIT_DISKIO */ /*************************************************************************** ** Everything above deals with file I/O. Everything that follows deals ** with other miscellanous aspects of the operating system interface @@ -845,11 +1326,11 @@ /* ** Get information to seed the random number generator. The seed ** is written into the buffer zBuf[256]. The calling function must ** supply a sufficiently large buffer. */ -int sqlite3OsRandomSeed(char *zBuf){ +int sqlite3WinRandomSeed(char *zBuf){ /* We have to initialize zBuf to prevent valgrind from reporting ** errors. The reports issued by valgrind are incorrect - we would ** prefer that the randomness be increased by making use of the ** uninitialized space in zBuf - but valgrind errors tend to worry ** some users. Rather than argue, it seems easier just to initialize @@ -866,11 +1347,11 @@ } /* ** Sleep for a little while. Return the amount of time slept. */ -int sqlite3OsSleep(int ms){ +int sqlite3WinSleep(int ms){ Sleep(ms); return ms; } /* @@ -887,11 +1368,11 @@ ** executed code that is surrounded by EnterMutex() and LeaveMutex(). ** ** SQLite uses only a single Mutex. There is not much critical ** code and what little there is executes quickly and without blocking. */ -void sqlite3OsEnterMutex(){ +void sqlite3WinEnterMutex(){ #ifdef SQLITE_W32_THREADS static int isInit = 0; while( !isInit ){ static long lock = 0; if( InterlockedIncrement(&lock)==1 ){ @@ -904,17 +1385,25 @@ EnterCriticalSection(&cs); #endif assert( !inMutex ); inMutex = 1; } -void sqlite3OsLeaveMutex(){ +void sqlite3WinLeaveMutex(){ assert( inMutex ); inMutex = 0; #ifdef SQLITE_W32_THREADS LeaveCriticalSection(&cs); #endif } + +/* +** Return TRUE if we are currently within the mutex and FALSE if not. +*/ +int sqlite3WinInMutex(){ + return inMutex; +} + /* ** The following variable, if set to a non-zero value, becomes the result ** returned from sqlite3OsCurrentTime(). This is used for testing. */ @@ -925,17 +1414,23 @@ /* ** Find the current time (in Universal Coordinated Time). Write the ** current time and date as a Julian Day number into *prNow and ** return 0. Return 1 if the time and date cannot be found. */ -int sqlite3OsCurrentTime(double *prNow){ +int sqlite3WinCurrentTime(double *prNow){ FILETIME ft; /* FILETIME structure is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (= JD 2305813.5). */ double now; +#if OS_WINCE + SYSTEMTIME time; + GetSystemTime(&time); + SystemTimeToFileTime(&time,&ft); +#else GetSystemTimeAsFileTime( &ft ); +#endif now = ((double)ft.dwHighDateTime) * 4294967296.0; *prNow = (now + ft.dwLowDateTime)/864000000000.0 + 2305813.5; #ifdef SQLITE_TEST if( sqlite3_current_time ){ *prNow = sqlite3_current_time/86400.0 + 2440587.5; @@ -942,6 +1437,41 @@ } #endif return 0; } +/* +** The first time this function is called from a specific thread, nByte +** bytes of data area are allocated and zeroed. A pointer to the new +** allocation is returned to the caller. +** +** Each subsequent call to this function from the thread returns the same +** pointer. The argument is ignored in this case. +*/ +void *sqlite3WinThreadSpecificData(int nByte){ + static void *pTsd = 0; + static int key; + static int keyInit = 0; + + if( !keyInit ){ + sqlite3OsEnterMutex(); + if( !keyInit ){ + key = TlsAlloc(); + if( key==0xffffffff ){ + sqlite3OsLeaveMutex(); + return 0; + } + keyInit = 1; + } + sqlite3OsLeaveMutex(); + } + pTsd = TlsGetValue(key); + if( !pTsd ){ + pTsd = sqlite3OsMalloc(nByte); + if( pTsd ){ + memset(pTsd, 0, nByte); + TlsSetValue(key, pTsd); + } + } + return pTsd; +} #endif /* OS_WIN */ DELETED SQLite.Interop/src/os_win.h Index: SQLite.Interop/src/os_win.h ================================================================== --- SQLite.Interop/src/os_win.h +++ /dev/null @@ -1,79 +0,0 @@ -/* -** 2004 May 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This header file defines OS-specific features for Win32 -*/ -#ifndef _SQLITE_OS_WIN_H_ -#define _SQLITE_OS_WIN_H_ - -#include -#include - -#ifdef _WIN32_WCE -typedef struct sqlitewce_lockdata_t sqlitewce_lockdata_t; -#endif - -/* -** The OsFile structure is a operating-system independing representation -** of an open file handle. It is defined differently for each architecture. -** -** This is the definition for Win32. -*/ -typedef struct OsFile OsFile; -struct OsFile { - HANDLE h; /* Handle for accessing the file */ - unsigned char locktype; /* Type of lock currently held on this file */ - unsigned char isOpen; /* True if needs to be closed */ - short sharedLockByte; /* Randomly chosen byte used as a shared lock */ -#ifdef _WIN32_WCE - int delOnClose; /* To delete file on close */ - WCHAR * wFilename; /* filename (for delete & global name generation) */ -# ifndef SQLITE_WCE_OMIT_FILELOCK - HANDLE hMux; /* Named mutex handle */ - HANDLE hMem; /* Named memory file mapping handle */ - sqlitewce_lockdata_t * lockdata; /* shared locking data (map view) */ -# endif //!SQLITE_WCE_OMIT_FILELOCK -#endif //_WIN32_WCE -}; - - -#define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) -#define SQLITE_MIN_SLEEP_MS 1 - -/* -** This are WIN32 API functions not present in WinCE. -** They are implemented in the "os_wince.c" file. -**/ -#ifdef _WIN32_WCE -# define DeleteFileA sqlitewce_DeleteFileA -# define GetFileAttributesA sqlitewce_GetFileAttributesA -# define GetTempPathA sqlitewce_GetTempPathA -# define GetFullPathNameA sqlitewce_GetFullPathNameA -# define GetSystemTimeAsFileTime sqlitewce_GetSystemTimeAsFileTime -BOOL sqlitewce_DeleteFileA( LPCSTR zFilename ); -DWORD sqlitewce_GetFileAttributesA( LPCSTR lpFileName ); -DWORD sqlitewce_GetTempPathA( DWORD bufLen, LPSTR buf ); -DWORD sqlitewce_GetFullPathNameA( LPCSTR,DWORD,LPSTR,LPSTR* ); -void sqlitewce_GetSystemTimeAsFileTime( LPFILETIME ); -#endif - -/* -** It seems WinCE 4.x (don't know about 5) implements localtime, -** but only in the MFC library. -** To avoid any problems I just use my own implementation. -** It should be safe, as this header is not included by normal -** programs, only by the SQLite library. -**/ -#if _WIN32_WCE >= 400 -# define localtime sqlitewce_localtime -#endif -#endif /* _SQLITE_OS_WIN_H_ */ DELETED SQLite.Interop/src/os_wince.c Index: SQLite.Interop/src/os_wince.c ================================================================== --- SQLite.Interop/src/os_wince.c +++ /dev/null @@ -1,793 +0,0 @@ -/* -** 2005 April 1 - Nuno Lucas -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains code that is specific to Windows CE. -*/ -#include "sqliteInt.h" -#include "os.h" /* Must be first to enable large file support */ -#ifdef _WIN32_WCE /* This file is used for Windows CE only */ -#include - -/* -** Include code that is common to all os_*.c files -*/ -#include "os_common.h" - - -/* -** -** Implementation of the assert function for systems not having it -** -** Very basic, just opens a message box displaying where and what fired the -** the assert failure. -*/ -void sqlitewce_assert( int x, char * test, char * file, int line ) -{ - /* This should be fixed somehow, to avoid overflows. - * Also, when an assert is caused by memory allocation faillure, this - * will probably fail. - */ - WCHAR buf[2048]; - if (x) return; - swprintf( buf, L"assert( %hs )\r\n\r\nFile: '%hs' Line: %d", test, file, line ); - MessageBoxW( 0, buf, L"Assertion Error", MB_ICONERROR ); -} - -/* -** Implementation of the localtime function for systems not having it. -** Convert time_t to local time in tm struct format. -*/ -struct tm * sqlitewce_localtime( const time_t *timer ) -{ - static struct tm s_tm; - FILETIME uf, lf; - SYSTEMTIME ls; - // Convert time_t to FILETIME - unsigned __int64 i64 = Int32x32To64(timer, 10000000) + 116444736000000000; - uf.dwLowDateTime = (DWORD) i64; - uf.dwHighDateTime = (DWORD) (i64 >> 32); - // Convert UTC(GMT) FILETIME to local FILETIME - FileTimeToLocalFileTime( &uf, &lf ); - // Convert FILETIME to SYSTEMTIME - FileTimeToSystemTime( &lf, &ls ); - // Convert SYSTEMTIME to tm - s_tm.tm_sec = ls.wSecond; - s_tm.tm_min = ls.wMinute; - s_tm.tm_hour = ls.wHour; - s_tm.tm_mday = ls.wDay; - s_tm.tm_mon = ls.wMonth -1; - s_tm.tm_year = ls.wYear - 1900; - s_tm.tm_wday = ls.wDayOfWeek; - // Return pointer to static data - return &s_tm; -} - -/* -** Similar to strdup, but first converts the MBCS string to UNICODE -** and then returns the UNICODE clone. -** Don't forget to free() the returned string. -** I assume a 2 byte size per character for unicode. That's what windows -** thinks unicode strings are (expect having to change this in 2010 ;) -*/ -static WCHAR * StrDupW( const char * str ) -{ - size_t size = strlen(str) + 1; // +1 for terminating '\0' - WCHAR * aux = (WCHAR *) malloc( size*sizeof(WCHAR) ); - MultiByteToWideChar( CP_ACP, 0, str,-1, aux, size ); - return aux; -} - -/* -** Windows CE versions prior to 3.0 don't implement atof(), so we -** implement it here as a wrapper to wcstod(). -*/ -double sqlitewce_atof( const char *str ) -{ - wchar_t * aux = StrDupW( str ); - double d = wcstod( aux, NULL ); - free( aux ); - return d; -} - -/* -** This is needed for the command line version of sqlite to compile. -**/ -int isatty( int handle ) -{ - UNREFERENCED_PARAMETER(handle); - return 1; -} - -// Stubbed in WinCE -DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart) -{ - return 0; -} - -/* -** Converts a relative path to an absolute path. -** There is no current directory concept on Windows CE, so we assume -** we are working always with absolute paths and simply copy -** the given path to the provided buffer. -*/ -DWORD sqlitewce_GetFullPathNameA - ( - LPCSTR lpFileName, - DWORD nBufferLength, - LPSTR lpBuffer, - LPSTR * lpFilePart - ) -{ - DWORD i = 0; - for ( ; i < nBufferLength; ++i ) - { - lpBuffer[i] = lpFileName[i]; - if ( lpBuffer[i] == '\\' || lpBuffer[i] == '/' ) - *lpFilePart = lpBuffer + i + 1; - if ( lpBuffer[i] == '\0' ) - break; - } - return (i >= nBufferLength)? strlen(lpFileName) + 1 : i; -} - -/* -** Simple wrapper to the Unicode version of GetFileAttributes(). -*/ -DWORD sqlitewce_GetFileAttributesA( LPCSTR lpFileName ) -{ - wchar_t * aux = StrDupW( lpFileName ); - DWORD ret = GetFileAttributesW( aux ); - free( aux ); - return ret; -} - -/* -** WinCE doesn't implement GetSystemTimeAsFileTime(), but is -** trivial to code. -*/ -void sqlitewce_GetSystemTimeAsFileTime( LPFILETIME ft ) -{ - SYSTEMTIME st; - GetSystemTime( &st ); - SystemTimeToFileTime( &st, ft ); -} - -/* -** Simple wrapper to the Unicode version of DeleteFile(). -*/ -BOOL sqlitewce_DeleteFileA( LPCSTR zFilename ) -{ - wchar_t * aux = StrDupW( zFilename ); - BOOL ret = DeleteFileW( aux ); - free( aux ); - return ret; -} - -/* -** Wrapper to the Unicode version of GetTempPath(). -** -** NOTE: The MSDN says GetTempPath() can fail if no temporary path -** defined. No check for this, as now is possible to define -** an alternate temporary path for sqlite. -*/ -DWORD sqlitewce_GetTempPathA( DWORD bufLen, LPSTR buf ) -{ - int len = GetTempPathW( 0,0 ); - LPWSTR wTempPath = (LPWSTR) malloc( (len+1)*sizeof(WCHAR) ); - GetTempPathW( len+1, wTempPath ); - len = WideCharToMultiByte( CP_ACP, 0, wTempPath,-1, buf,bufLen, 0,0 ); - free( wTempPath ); - return len; -} - - -/********************************************************************** - * File locking helper functions for Windows CE - *********************************************************************/ - -#ifndef SQLITE_WCE_OMIT_FILELOCK - -/* -** Structure holding the global locking data for each open database/file. -** sqlitewce_LockMutex() must be used before using this data. -** -** holds the global lock state of the file. Every time a process -** holds a lock on the file, 1 << locktype is set, i.e., bit 1 -** if any process with a SHARED lock, bit 2 is set if any with -** a RESERVED lock, bit 3 for the PENDING lock and bit 4 for -** the EXCLUSIVE lock. bit 0 is ignored, and may be set or not -** in between (if it simplifies the algorithm). -** is the count of processes holding the SHARED lock. -** -*/ -typedef struct sqlitewce_lockdata_t -{ - unsigned lock; /* global lock state */ - unsigned shared; /* global share count */ -} sqlitewce_lockdata_t; - -/* -** Lock access to file locking data. -** Only returns on success. -** -** NOTE: I'm not sure in what conditions this can turn into an infinite -** loop. I don't think it is possible without a serious bug in -** sqlite or windows, but i'm not sure of this. -*/ -static void lock_file( OsFile *id ) -{ - DWORD res; - if (id->lockdata == NULL) return; - - while ( 1 ) - { - res = WaitForSingleObject( id->hMux, INFINITE ); - // I don't know very well what I have to do in this case. - // The MSDN says that this case is when a thread terminates without - // releasing the mutex. So I have to release it and try again - if ( res == WAIT_ABANDONED ) - { - ReleaseMutex( id->hMux ); - continue; - } - // success ? - if ( res == WAIT_OBJECT_0 ) - break; - // Let the owner have time to release it - Sleep( 1 ); - } -} - -/* -** Releases ownership of the file mutex. -** Always success -*/ -static void unlock_file( OsFile *id ) -{ - if (id->hMux) - ReleaseMutex( id->hMux ); -} - -/* -** Acquire a lock on the file. -** Returns non-zero on success, zero on failure. -*/ -static int getLock( OsFile *id, int locktype ) -{ - int rc = 0; - if (id->lockdata == NULL) return 1; - - lock_file( id ); - - if ( locktype == SHARED_LOCK ) - { - assert( id->lockdata->shared >= 0 ); - ++id->lockdata->shared; /* Increment number of readers */ - id->lockdata->lock |= 1 << SHARED_LOCK; - } - else - { - if ( id->lockdata->lock & (1 << locktype) ) - { - unlock_file( id ); - return 0; /* Already locked by others */ - } - id->lockdata->lock |= 1 << locktype; - } - unlock_file( id ); - return 1; -} - -/* -** Releases lock on the file. -** Always succeeds, so no return value. -*/ -static void unsetLock( OsFile *id, int locktype ) -{ - assert( locktype >= SHARED_LOCK ); - if (id->lockdata == NULL) return; - - lock_file( id ); - if ( locktype == SHARED_LOCK ) - { - assert( id->lockdata->shared > 0 ); - --id->lockdata->shared; /* Decrement number of readers */ - if ( id->lockdata->shared == 0 ) /* Last reader? */ - id->lockdata->lock &= ~(1 << SHARED_LOCK); - } - else - { - id->lockdata->lock &= ~(1 << locktype); - } - unlock_file( id ); -} - -/* -** Initializes file locking struture. -** Returns non-zero on success, zero on error. -** -** Each open file will have an associated shared memory area, where the global -** lock information will be stored. -** The file path is used to generate a unique name for each file. -** An aditional global mutex per file is created, for syncronization between -** processes. -*/ -static int sqlitewce_InitLocks( OsFile *id ) -{ - WCHAR * aux; - WCHAR muxName[256] = L"sqwce_mux_"; - WCHAR memName[256] = L"sqwce_mem_"; - int i, exists; - - // Generate resource names suffix from the file name - aux = _wcsdup( id->wFilename ); - if ( aux == NULL ) return 0; // No mem - for ( i = 0; aux[i]; ++i ) - { - if ( aux[i] == '\\' ) - aux[i] = '/'; // can't use '\\' in name - else - aux[i] = towlower( aux[i] ); // names are case sensitive - } - wcsncat( muxName, aux, 256 ); - wcsncat( memName, aux, 256 ); - free( aux ); - - // Create named mutex (or open existing) - id->hMux = CreateMutex( NULL, FALSE, muxName ); - if ( id->hMux == NULL ) - return 0; // No mem or something weird - - // Lock access to file data (avoid race condition on create/open) - lock_file( id ); - - // Create shared memory mapping or open existing - id->hMem = CreateFileMapping( - INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, - 0, sizeof(sqlitewce_lockdata_t), - memName ); - if ( id->hMem == NULL ) - { - unlock_file( id ); - CloseHandle( id->hMux ); - return 0; // No mem or something weird - } - - // Check if already exists (created by other process) - exists = (GetLastError() == ERROR_ALREADY_EXISTS); - - // Open view to the data - id->lockdata = (sqlitewce_lockdata_t *)MapViewOfFile( id->hMem, FILE_MAP_WRITE, 0,0, 0 ); - if ( id->lockdata == NULL ) - { - unlock_file( id ); - CloseHandle( id->hMem ); - CloseHandle( id->hMux ); - return 0; // No mem or something weird - } - - // Initialize lockdata, if first time - if ( ! exists ) - memset( id->lockdata, 0, sizeof(sqlitewce_lockdata_t) ); - - // Done, release global lock on the file. - unlock_file( id ); - - return 1; -} - -/* -** Releases any locks held on the file and releases locking data. -** Doesn't return anything, because there is no way to recover -** from a faillure to remove the lock (and a faillure to do so -** would be a bug either in windows or in sqlite). -*/ -static void sqlitewce_ReleaseLocks( OsFile *id ) -{ - if ( id->lockdata ) - { - sqlite3OsUnlock( id, NO_LOCK ); - UnmapViewOfFile( id->lockdata ); - CloseHandle( id->hMem ); - CloseHandle( id->hMux ); - } -} - -#endif // !defined(SQLITE_WCE_OMIT_FILELOCK) - - -/********************************************************************** - * sqlite3Os functions implemented specificaly for WinCE - *********************************************************************/ - -/* -** Attempt to open a file for both reading and writing. If that -** fails, try opening it read-only. If the file does not exist, -** try to create it. -** -** On success, a handle for the open file is written to *id -** and *pReadonly is set to 0 if the file was opened for reading and -** writing or 1 if the file was opened read-only. The function returns -** SQLITE_OK. -** -** On failure, the function returns SQLITE_CANTOPEN and leaves -** *id and *pReadonly unchanged. -*/ -int sqlite3OsOpenReadWrite( const char *zFilename, OsFile *id, int *pReadonly ) -{ - HANDLE h; - WCHAR *wFilename = StrDupW( zFilename ); - if ( wFilename == NULL ) - return SQLITE_NOMEM; - assert( !id->isOpen ); - h = CreateFileW( wFilename, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, - NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL ); - if ( h == INVALID_HANDLE_VALUE ) - { - h = CreateFileW( wFilename, GENERIC_READ, - FILE_SHARE_READ, - NULL, OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, - NULL ); - if ( h == INVALID_HANDLE_VALUE ) - { - free( wFilename ); - return SQLITE_CANTOPEN; - } - *pReadonly = 1; - } - else - { - *pReadonly = 0; - } - // Fill file context data - id->h = h; - id->locktype = NO_LOCK; - id->sharedLockByte = 0; - id->isOpen = 1; - id->wFilename = wFilename; - id->delOnClose = 0; -#ifndef SQLITE_WCE_OMIT_FILELOCK - if ( ! sqlitewce_InitLocks(id) ) - { // Failled to initialize file lock mechanism - free( wFilename ); - CloseHandle( h ); - return SQLITE_NOMEM; - } -#endif - OpenCounter(+1); - TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename); - return SQLITE_OK; -} - -/* -** Attempt to open a new file for exclusive access by this process. -** The file will be opened for both reading and writing. To avoid -** a potential security problem, we do not allow the file to have -** previously existed. Nor do we allow the file to be a symbolic -** link. -** -** If delFlag is true, then make arrangements to automatically delete -** the file when it is closed. -** -** On success, write the file handle into *id and return SQLITE_OK. -** -** On failure, return SQLITE_CANTOPEN. -*/ -int sqlite3OsOpenExclusive( const char *zFilename, OsFile *id, int delFlag ) -{ - HANDLE h; - WCHAR * wFilename = StrDupW( zFilename ); - assert( !id->isOpen ); - h = CreateFileW( wFilename, GENERIC_READ | GENERIC_WRITE, 0, - NULL, CREATE_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL ); - if ( h == INVALID_HANDLE_VALUE ) - { - free( wFilename ); - return SQLITE_CANTOPEN; - } - id->h = h; - id->locktype = NO_LOCK; - id->sharedLockByte = 0; - id->isOpen = 1; - id->wFilename = wFilename; - id->delOnClose = delFlag; -#ifndef SQLITE_WCE_OMIT_FILELOCK - id->lockdata = NULL; - id->hMux = NULL; - id->hMem = NULL; -#endif - OpenCounter(+1); - TRACE3("OPEN EX %d \"%s\"\n", h, zFilename); - return SQLITE_OK; -} - -/* -** Attempt to open a new file for read-only access. -** -** On success, write the file handle into *id and return SQLITE_OK. -** -** On failure, return SQLITE_CANTOPEN. -*/ -int sqlite3OsOpenReadOnly( const char *zFilename, OsFile *id ) -{ - HANDLE h; - WCHAR * wFilename = StrDupW( zFilename ); - assert( !id->isOpen ); - h = CreateFileW( wFilename, GENERIC_READ, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL ); - if ( h == INVALID_HANDLE_VALUE ) - { - free( wFilename ); - return SQLITE_CANTOPEN; - } - id->h = h; - id->locktype = NO_LOCK; - id->sharedLockByte = 0; - id->isOpen = 1; - id->wFilename = wFilename; - id->delOnClose = 0; -#ifndef SQLITE_WCE_OMIT_FILELOCK - id->lockdata = NULL; - id->hMux = NULL; - id->hMem = NULL; -#endif - OpenCounter(+1); - TRACE3("OPEN RO %d \"%s\"\n", h, zFilename); - return SQLITE_OK; -} - -/* -** Close a file. -*/ -int sqlite3OsClose( OsFile *id ) -{ - if ( id->isOpen ) - { - TRACE2("CLOSE %d\n", id->h); -#ifndef SQLITE_WCE_OMIT_FILELOCK - sqlitewce_ReleaseLocks( id ); -#endif - CloseHandle(id->h); - OpenCounter(-1); - id->isOpen = 0; - if ( id->delOnClose ) - DeleteFileW( id->wFilename ); - free( id->wFilename ); - } - return SQLITE_OK; -} - -/* -** Lock the file with the lock specified by parameter locktype - one -** of the following: -** -** (1) SHARED_LOCK -** (2) RESERVED_LOCK -** (3) PENDING_LOCK -** (4) EXCLUSIVE_LOCK -** -** Sometimes when requesting one lock state, additional lock states -** are inserted in between. The locking might fail on one of the later -** transitions leaving the lock state different from what it started but -** still short of its goal. The following chart shows the allowed -** transitions and the inserted intermediate states: -** -** UNLOCKED -> SHARED -** SHARED -> RESERVED -** SHARED -> (PENDING) -> EXCLUSIVE -** RESERVED -> (PENDING) -> EXCLUSIVE -** PENDING -> EXCLUSIVE -** -** This routine will only increase a lock. The sqlite3OsUnlock() routine -** erases all locks at once and returns us immediately to locking level 0. -** It is not possible to lower the locking level one step at a time. You -** must go straight to locking level 0. -*/ -int sqlite3OsLock( OsFile *id, int locktype ) -{ -#ifdef SQLITE_WCE_OMIT_FILELOCK - id->locktype = locktype; - return SQLITE_OK; -#else - int rc = SQLITE_OK; /* Return code from subroutines */ - int res = 1; /* Result of a windows lock call */ - int newLocktype; /* Set id->locktype to this value before exiting */ - int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ - - assert( id->isOpen ); - TRACE5("LOCK %d %d was %d(%d)\n", - id->h, locktype, id->locktype, id->sharedLockByte); - - /* If there is already a lock of this type or more restrictive on the - ** OsFile, do nothing. Don't use the end_lock: exit path, as - ** sqlite3OsEnterMutex() hasn't been called yet. - */ - if( id->locktype>=locktype ){ - return SQLITE_OK; - } - - /* Make sure the locking sequence is correct - */ - assert( id->locktype!=NO_LOCK || locktype==SHARED_LOCK ); - assert( locktype!=PENDING_LOCK ); - assert( locktype!=RESERVED_LOCK || id->locktype==SHARED_LOCK ); - - /* Lock the PENDING_LOCK byte if we need to acquire a PENDING lock or - ** a SHARED lock. If we are acquiring a SHARED lock, the acquisition of - ** the PENDING_LOCK byte is temporary. - */ - newLocktype = id->locktype; - if( id->locktype==NO_LOCK - || (locktype==EXCLUSIVE_LOCK && id->locktype==RESERVED_LOCK) - ){ - int cnt = 3; - while( cnt-->0 && (res = getLock(id, PENDING_LOCK))==0 ){ - /* Try 3 times to get the pending lock. The pending lock might be - ** held by another reader process who will release it momentarily. - */ - TRACE2("could not get a PENDING lock. cnt=%d\n", cnt); - Sleep(1); - } - gotPendingLock = res; - } - - /* Acquire a shared lock - */ - if( locktype==SHARED_LOCK && res ){ - assert( id->locktype==NO_LOCK ); - res = getLock( id, SHARED_LOCK ); - if( res ){ - newLocktype = SHARED_LOCK; - } - } - - /* Acquire a RESERVED lock - */ - if( locktype==RESERVED_LOCK && res ){ - assert( id->locktype==SHARED_LOCK ); - res = getLock( id, RESERVED_LOCK ); - if( res ){ - newLocktype = RESERVED_LOCK; - } - } - - /* Acquire a PENDING lock - */ - if( locktype==EXCLUSIVE_LOCK && res ){ - newLocktype = PENDING_LOCK; - gotPendingLock = 0; - } - - /* Acquire an EXCLUSIVE lock - */ - if( locktype==EXCLUSIVE_LOCK && res ){ - assert( id->locktype>=SHARED_LOCK ); -// res = unlockReadLock(id); -// TRACE2("unreadlock = %d\n", res); - res = getLock( id, EXCLUSIVE_LOCK ); - if( res ){ - newLocktype = EXCLUSIVE_LOCK; - }else{ - TRACE2("error-code = %d\n", GetLastError()); - } - } - - /* If we are holding a PENDING lock that ought to be released, then - ** release it now. - */ - if( gotPendingLock && locktype==SHARED_LOCK ){ - unsetLock( id, PENDING_LOCK ); - } - - /* Update the state of the lock has held in the file descriptor then - ** return the appropriate result code. - */ - if( res ){ - rc = SQLITE_OK; - }else{ - TRACE4("LOCK FAILED %d trying for %d but got %d\n", id->h, - locktype, newLocktype); - rc = SQLITE_BUSY; - } - id->locktype = newLocktype; - return rc; -#endif -} - -/* -** This routine checks if there is a RESERVED lock held on the specified -** file by this or any other process. If such a lock is held, return -** non-zero, otherwise zero. -*/ -int sqlite3OsCheckReservedLock( OsFile *id ) -{ - int rc; - assert( id->isOpen ); - if( id->locktype>=RESERVED_LOCK ){ - rc = 1; - TRACE3("TEST WR-LOCK %d %d (local)\n", id->h, rc); - }else{ -#ifdef SQLITE_WCE_OMIT_FILELOCK - rc = 0; -#else - /* Only an atomic read, no need to lock_file() */ - rc = ( id->lockdata->lock & (1<h, rc ); -#endif - } - return rc; -} - -/* -** Lower the locking level on file descriptor id to locktype. locktype -** must be either NO_LOCK or SHARED_LOCK. -** -** If the locking level of the file descriptor is already at or below -** the requested locking level, this routine is a no-op. -** -** It is not possible for this routine to fail if the second argument -** is NO_LOCK. If the second argument is SHARED_LOCK then this routine -** might return SQLITE_IOERR; -*/ -int sqlite3OsUnlock( OsFile *id, int locktype ) -{ -#ifdef SQLITE_WCE_OMIT_FILELOCK - return SQLITE_OK; -#else - int type; - int rc = SQLITE_OK; - assert( id->isOpen ); - assert( locktype<=SHARED_LOCK ); - TRACE5("UNLOCK %d to %d was %d(%d)\n", id->h, locktype, - id->locktype, id->sharedLockByte); - type = id->locktype; - if( type>=EXCLUSIVE_LOCK ){ - unsetLock( id, EXCLUSIVE_LOCK ); - } - if( type>=RESERVED_LOCK ){ - unsetLock( id, RESERVED_LOCK ); - } - if( locktype==NO_LOCK && type>=SHARED_LOCK ){ - unsetLock( id, SHARED_LOCK ); - } - if( type>=PENDING_LOCK ){ - unsetLock( id, PENDING_LOCK ); - } - id->locktype = locktype; - return rc; -#endif -} - - -#ifndef SQLITE_OMIT_PAGER_PRAGMAS -/* -** Check that a given pathname is a directory and is writable -** -*/ -int sqlite3OsIsDirWritable(char *zBuf){ - int fileAttr; - if(! zBuf ) return 0; - fileAttr = GetFileAttributesA(zBuf); - if( fileAttr == 0xffffffff ) return 0; - if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){ - return 0; - } - return 1; -} -#endif /* SQLITE_OMIT_PAGER_PRAGMAS */ - - -#endif /* _WIN32_WCE */ Index: SQLite.Interop/src/pager.c ================================================================== --- SQLite.Interop/src/pager.c +++ SQLite.Interop/src/pager.c @@ -16,11 +16,11 @@ ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.11 2005/12/19 17:57:47 rmsimpson Exp $ +** @(#) $Id: pager.c,v 1.12 2006/01/10 18:40:37 rmsimpson Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include "os.h" #include "pager.h" @@ -44,25 +44,18 @@ #define TRACE5(X,Y,Z,W,V) #endif /* ** The following two macros are used within the TRACEX() macros above -** to print out file-descriptors. They are required so that tracing -** can be turned on when using both the regular os_unix.c and os_test.c -** backends. +** to print out file-descriptors. ** ** PAGERID() takes a pointer to a Pager struct as it's argument. The ** associated file-descriptor is returned. FILEHANDLEID() takes an OsFile ** struct as it's argument. */ -#ifdef OS_TEST -#define PAGERID(p) (p->fd->fd.h) -#define FILEHANDLEID(fd) (fd->fd.h) -#else -#define PAGERID(p) (p->fd.h) -#define FILEHANDLEID(fd) (fd.h) -#endif +#define PAGERID(p) FILEHANDLEID(&(p)->fd) +#define FILEHANDLEID(fd) (sqlite3OsFileHandle(&fd)) /* ** The page cache as a whole is always in one of the following ** states: ** @@ -267,12 +260,12 @@ u8 *aInJournal; /* One bit for each page in the database file */ u8 *aInStmt; /* One bit for each page in the database */ char *zFilename; /* Name of the database file */ char *zJournal; /* Name of the journal file */ char *zDirectory; /* Directory hold database and journal files */ - OsFile fd, jfd; /* File descriptors for database and journal */ - OsFile stfd; /* File descriptor for the statement subjournal*/ + OsFile *fd, *jfd; /* File descriptors for database and journal */ + OsFile *stfd; /* File descriptor for the statement subjournal*/ BusyHandler *pBusyHandler; /* Pointer to sqlite.busyHandler */ PgHdr *pFirst, *pLast; /* List of free pages */ PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */ PgHdr *pAll; /* List of all pages */ PgHdr *pStmt; /* List of pages in the statement subjournal */ @@ -289,10 +282,13 @@ void (*xDestructor)(void*,int); /* Call this routine when freeing pages */ void (*xReiniter)(void*,int); /* Call this routine when reloading pages */ void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */ void *pCodecArg; /* First argument to xCodec() */ PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */ +#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT + Pager *pNext; /* Linked list of pagers in this thread */ +#endif }; /* ** If SQLITE_TEST is defined then increment the variable given in ** the argument @@ -303,16 +299,40 @@ # define TEST_INCR(x) #endif /* ** These are bits that can be set in Pager.errMask. +** +** TODO: Maybe we just want a variable - Pager.errCode. Can we really +** have two simultaneous error conditions? +** +** Recovering from an SQLITE_FULL, SQLITE_LOCK, SQLITE_CORRUPT or +** SQLITE_IOERR error is not a simple matter, particularly if the pager +** cache is shared between multiple connections. +** +** SQLITE_FULL (PAGER_ERR_FULL): +** Cleared when the transaction is rolled back. +** +** SQLITE_CORRUPT (PAGER_ERR_CORRUPT): +** Cannot be cleared. The upper layer must close the current pager +** and open a new one on the same file to continue. +** +** SQLITE_PROTOCOL (PAGER_ERR_LOCK): +** This error only occurs if an internal error occurs or another process +** is not following the sqlite locking protocol (i.e. someone is +** manipulating the database file using something other than sqlite). +** This is handled in the same way as database corruption - the error +** cannot be cleared except by closing the current pager and opening +** a brand new one on the same file. +** +** SQLITE_IOERR (PAGER_ERR_DISK): +** Cleared when the transaction is rolled back. */ #define PAGER_ERR_FULL 0x01 /* a write() failed */ -#define PAGER_ERR_MEM 0x02 /* malloc() failed */ -#define PAGER_ERR_LOCK 0x04 /* error in the locking protocol */ -#define PAGER_ERR_CORRUPT 0x08 /* database or journal corruption */ -#define PAGER_ERR_DISK 0x10 /* general disk I/O error - bad hard drive? */ +#define PAGER_ERR_LOCK 0x02 /* error in the locking protocol */ +#define PAGER_ERR_CORRUPT 0x04 /* database or journal corruption */ +#define PAGER_ERR_DISK 0x08 /* general disk I/O error - bad hard drive? */ /* ** Journal files begin with the following magic string. The data ** was obtained from /dev/random. It is used only as a sanity check. ** @@ -467,14 +487,35 @@ static int pager_errcode(Pager *pPager){ int rc = SQLITE_OK; if( pPager->errMask & PAGER_ERR_LOCK ) rc = SQLITE_PROTOCOL; if( pPager->errMask & PAGER_ERR_DISK ) rc = SQLITE_IOERR; if( pPager->errMask & PAGER_ERR_FULL ) rc = SQLITE_FULL; - if( pPager->errMask & PAGER_ERR_MEM ) rc = SQLITE_NOMEM; if( pPager->errMask & PAGER_ERR_CORRUPT ) rc = SQLITE_CORRUPT; return rc; } + +/* +** This function should be called when an error occurs within the pager +** code to set the appropriate bits in Pager.errMask. +*/ +static int pager_error(Pager *pPager, int rc){ + switch( rc ){ + case SQLITE_PROTOCOL: + pPager->errMask |= PAGER_ERR_LOCK; + break; + case SQLITE_IOERR: + pPager->errMask |= PAGER_ERR_DISK; + break; + case SQLITE_FULL: + pPager->errMask |= PAGER_ERR_FULL; + break; + case SQLITE_CORRUPT: + pPager->errMask |= PAGER_ERR_CORRUPT; + break; + } + return rc; +} #ifdef SQLITE_CHECK_PAGES /* ** Return a 32-bit hash of the page data for pPage. */ @@ -595,11 +636,11 @@ } assert( offset%JOURNAL_HDR_SZ(pPager)==0 ); assert( offset>=c ); assert( (offset-c)journalOff = offset; - return sqlite3OsSeek(&pPager->jfd, pPager->journalOff); + return sqlite3OsSeek(pPager->jfd, pPager->journalOff); } /* ** The journal file must be open when this routine is called. A journal ** header (JOURNAL_HDR_SZ bytes) is written into the journal file at the @@ -631,37 +672,37 @@ ** be written until nRec is filled in as part of next syncJournal(). ** ** Actually maybe the whole journal header should be delayed until that ** point. Think about this. */ - rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); + rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); if( rc==SQLITE_OK ){ /* The nRec Field. 0xFFFFFFFF for no-sync journals. */ - rc = write32bits(&pPager->jfd, pPager->noSync ? 0xffffffff : 0); + rc = write32bits(pPager->jfd, pPager->noSync ? 0xffffffff : 0); } if( rc==SQLITE_OK ){ /* The random check-hash initialiser */ sqlite3Randomness(sizeof(pPager->cksumInit), &pPager->cksumInit); - rc = write32bits(&pPager->jfd, pPager->cksumInit); + rc = write32bits(pPager->jfd, pPager->cksumInit); } if( rc==SQLITE_OK ){ /* The initial database size */ - rc = write32bits(&pPager->jfd, pPager->dbSize); + rc = write32bits(pPager->jfd, pPager->dbSize); } if( rc==SQLITE_OK ){ /* The assumed sector size for this process */ - rc = write32bits(&pPager->jfd, pPager->sectorSize); + rc = write32bits(pPager->jfd, pPager->sectorSize); } /* The journal header has been written successfully. Seek the journal ** file descriptor to the end of the journal header sector. */ if( rc==SQLITE_OK ){ - rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1); + rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff-1); if( rc==SQLITE_OK ){ - rc = sqlite3OsWrite(&pPager->jfd, "\000", 1); + rc = sqlite3OsWrite(pPager->jfd, "\000", 1); } } return rc; } @@ -695,37 +736,37 @@ if( pPager->journalOff+JOURNAL_HDR_SZ(pPager) > journalSize ){ return SQLITE_DONE; } - rc = sqlite3OsRead(&pPager->jfd, aMagic, sizeof(aMagic)); + rc = sqlite3OsRead(pPager->jfd, aMagic, sizeof(aMagic)); if( rc ) return rc; if( memcmp(aMagic, aJournalMagic, sizeof(aMagic))!=0 ){ return SQLITE_DONE; } - rc = read32bits(&pPager->jfd, pNRec); + rc = read32bits(pPager->jfd, pNRec); if( rc ) return rc; - rc = read32bits(&pPager->jfd, &pPager->cksumInit); + rc = read32bits(pPager->jfd, &pPager->cksumInit); if( rc ) return rc; - rc = read32bits(&pPager->jfd, pDbSize); + rc = read32bits(pPager->jfd, pDbSize); if( rc ) return rc; /* Update the assumed sector-size to match the value used by ** the process that created this journal. If this journal was ** created by a process other than this one, then this routine ** is being called from within pager_playback(). The local value ** of Pager.sectorSize is restored at the end of that routine. */ - rc = read32bits(&pPager->jfd, (u32 *)&pPager->sectorSize); + rc = read32bits(pPager->jfd, (u32 *)&pPager->sectorSize); if( rc ) return rc; pPager->journalOff += JOURNAL_HDR_SZ(pPager); - rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff); + rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff); return rc; } /* @@ -741,10 +782,13 @@ ** + 4 bytes: Master journal name checksum. ** + 8 bytes: aJournalMagic[]. ** ** The master journal page checksum is the sum of the bytes in the master ** journal name. +** +** If zMaster is a NULL pointer (occurs for a single database transaction), +** this call is a no-op. */ static int writeMasterJournal(Pager *pPager, const char *zMaster){ int rc; int len; int i; @@ -766,23 +810,23 @@ rc = seekJournalHdr(pPager); if( rc!=SQLITE_OK ) return rc; } pPager->journalOff += (len+20); - rc = write32bits(&pPager->jfd, PAGER_MJ_PGNO(pPager)); + rc = write32bits(pPager->jfd, PAGER_MJ_PGNO(pPager)); + if( rc!=SQLITE_OK ) return rc; + + rc = sqlite3OsWrite(pPager->jfd, zMaster, len); if( rc!=SQLITE_OK ) return rc; - rc = sqlite3OsWrite(&pPager->jfd, zMaster, len); + rc = write32bits(pPager->jfd, len); if( rc!=SQLITE_OK ) return rc; - rc = write32bits(&pPager->jfd, len); + rc = write32bits(pPager->jfd, cksum); if( rc!=SQLITE_OK ) return rc; - rc = write32bits(&pPager->jfd, cksum); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3OsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); + rc = sqlite3OsWrite(pPager->jfd, aJournalMagic, sizeof(aJournalMagic)); pPager->needSync = !pPager->noSync; return rc; } /* @@ -856,39 +900,16 @@ memset(pPager->aHash, 0, sizeof(pPager->aHash)); pPager->nPage = 0; if( pPager->state>=PAGER_RESERVED ){ sqlite3pager_rollback(pPager); } - sqlite3OsUnlock(&pPager->fd, NO_LOCK); + sqlite3OsUnlock(pPager->fd, NO_LOCK); pPager->state = PAGER_UNLOCK; pPager->dbSize = -1; pPager->nRef = 0; assert( pPager->journalOpen==0 ); } - -/* -** This function is used to reset the pager after a malloc() failure. This -** doesn't work with in-memory databases. If a malloc() fails when an -** in-memory database is in use it is not possible to recover. -** -** If a transaction or statement transaction is active, it is rolled back. -** -** It is an error to call this function if any pages are in use. -*/ -#ifndef SQLITE_OMIT_GLOBALRECOVER -int sqlite3pager_reset(Pager *pPager){ - if( pPager ){ - if( pPager->nRef || MEMDB ){ - return SQLITE_ERROR; - } - pPager->errMask &= ~(PAGER_ERR_MEM); - pager_reset(pPager); - } - return SQLITE_OK; -} -#endif - /* ** When this routine is called, the pager has the journal file open and ** a RESERVED or EXCLUSIVE lock on the database. This routine releases ** the database lock and acquires a SHARED lock in its place. The journal @@ -928,11 +949,11 @@ pPager->nRec = 0; }else{ assert( pPager->aInJournal==0 ); assert( pPager->dirtyCache==0 || pPager->useJournal==0 ); } - rc = sqlite3OsUnlock(&pPager->fd, SHARED_LOCK); + rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK); pPager->state = PAGER_SHARED; pPager->origDbSize = 0; pPager->setMaster = 0; return rc; } @@ -955,11 +976,11 @@ ** FIX ME: Consider adding every 200th (or so) byte of the data to the ** checksum. That way if a single page spans 3 or more disk sectors and ** only the middle sector is corrupt, we will still have a reasonable ** chance of failing the checksum and thus detecting the problem. */ -static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){ +static u32 pager_cksum(Pager *pPager, Pgno pgno, const u8 *aData){ u32 cksum = pPager->cksumInit; int i = pPager->pageSize-200; while( i>0 ){ cksum += aData[i]; i -= 200; @@ -983,11 +1004,11 @@ u8 aData[SQLITE_MAX_PAGE_SIZE]; /* Temp storage for a page */ /* useCksum should be true for the main journal and false for ** statement journals. Verify that this is always the case */ - assert( jfd == (useCksum ? &pPager->jfd : &pPager->stfd) ); + assert( jfd == (useCksum ? pPager->jfd : pPager->stfd) ); rc = read32bits(jfd, &pgno); if( rc!=SQLITE_OK ) return rc; rc = sqlite3OsRead(jfd, &aData, pPager->pageSize); @@ -1038,13 +1059,13 @@ */ pPg = pager_lookup(pPager, pgno); assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 ); TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno); if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){ - rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize); + rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize); if( rc==SQLITE_OK ){ - rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize); + rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize); } if( pPg ) pPg->dirty = 0; } if( pPg ){ /* No page should ever be explicitly rolled back that is in use, except @@ -1080,22 +1101,21 @@ ** a different master journal, then this master journal can be deleted. */ static int pager_delmaster(const char *zMaster){ int rc; int master_open = 0; - OsFile master; + OsFile *master = 0; char *zMasterJournal = 0; /* Contents of master journal file */ i64 nMasterJournal; /* Size of master journal file */ /* Open the master journal file exclusively in case some other process ** is running this routine also. Not that it makes too much difference. */ - memset(&master, 0, sizeof(master)); rc = sqlite3OsOpenReadOnly(zMaster, &master); if( rc!=SQLITE_OK ) goto delmaster_out; master_open = 1; - rc = sqlite3OsFileSize(&master, &nMasterJournal); + rc = sqlite3OsFileSize(master, &nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; if( nMasterJournal>0 ){ char *zJournal; char *zMasterPtr = 0; @@ -1106,30 +1126,29 @@ zMasterJournal = (char *)sqliteMalloc(nMasterJournal); if( !zMasterJournal ){ rc = SQLITE_NOMEM; goto delmaster_out; } - rc = sqlite3OsRead(&master, zMasterJournal, nMasterJournal); + rc = sqlite3OsRead(master, zMasterJournal, nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; zJournal = zMasterJournal; while( (zJournal-zMasterJournal)pAll; pPg; pPg=pPg->pNextAll){ char zBuf[SQLITE_MAX_PAGE_SIZE]; if( !pPg->dirty ) continue; if( (int)pPg->pgno <= pPager->origDbSize ){ - rc = sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1)); + rc = sqlite3OsSeek(pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1)); if( rc==SQLITE_OK ){ - rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize); + rc = sqlite3OsRead(pPager->fd, zBuf, pPager->pageSize); } TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno); if( rc ) break; CODEC(pPager, zBuf, pPg->pgno, 2); }else{ @@ -1203,11 +1222,11 @@ ** Truncate the main file of the given pager to the number of pages ** indicated. */ static int pager_truncate(Pager *pPager, int nPage){ assert( pPager->state>=PAGER_EXCLUSIVE ); - return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(i64)nPage); + return sqlite3OsTruncate(pPager->fd, pPager->pageSize*(i64)nPage); } /* ** Playback the journal and thus restore the database file to ** the state it was in before we started making changes. @@ -1271,29 +1290,29 @@ /* Figure out how many records are in the journal. Abort early if ** the journal is empty. */ assert( pPager->journalOpen ); - rc = sqlite3OsFileSize(&pPager->jfd, &szJ); + rc = sqlite3OsFileSize(pPager->jfd, &szJ); if( rc!=SQLITE_OK ){ goto end_playback; } /* Read the master journal name from the journal, if it is present. ** If a master journal file name is specified, but the file is not ** present on disk, then the journal is not hot and does not need to be ** played back. */ - rc = readMasterJournal(&pPager->jfd, &zMaster); + rc = readMasterJournal(pPager->jfd, &zMaster); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK || (zMaster && !sqlite3OsFileExists(zMaster)) ){ sqliteFree(zMaster); zMaster = 0; if( rc==SQLITE_DONE ) rc = SQLITE_OK; goto end_playback; } - sqlite3OsSeek(&pPager->jfd, 0); + sqlite3OsSeek(pPager->jfd, 0); pPager->journalOff = 0; /* This loop terminates either when the readJournalHdr() call returns ** SQLITE_DONE or an IO error occurs. */ while( 1 ){ @@ -1332,17 +1351,17 @@ goto end_playback; } pPager->dbSize = mxPg; } - /* rc = sqlite3OsSeek(&pPager->jfd, JOURNAL_HDR_SZ(pPager)); */ + /* rc = sqlite3OsSeek(pPager->jfd, JOURNAL_HDR_SZ(pPager)); */ if( rc!=SQLITE_OK ) goto end_playback; /* Copy original pages out of the journal and back into the database file. */ for(i=0; ijfd, 1); + rc = pager_playback_one_page(pPager, pPager->jfd, 1); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; pPager->journalOff = szJ; break; @@ -1405,11 +1424,11 @@ szJ = pPager->journalOff; #ifndef NDEBUG { i64 os_szJ; - rc = sqlite3OsFileSize(&pPager->jfd, &os_szJ); + rc = sqlite3OsFileSize(pPager->jfd, &os_szJ); if( rc!=SQLITE_OK ) return rc; assert( szJ==os_szJ ); } #endif @@ -1431,20 +1450,20 @@ pPager->dbSize = pPager->stmtSize; /* Figure out how many records are in the statement journal. */ assert( pPager->stmtInUse && pPager->journalOpen ); - sqlite3OsSeek(&pPager->stfd, 0); + sqlite3OsSeek(pPager->stfd, 0); nRec = pPager->stmtNRec; /* Copy original pages out of the statement journal and back into the ** database file. Note that the statement journal omits checksums from ** each record since power-failure recovery is not important to statement ** journals. */ for(i=nRec-1; i>=0; i--){ - rc = pager_playback_one_page(pPager, &pPager->stfd, 0); + rc = pager_playback_one_page(pPager, pPager->stfd, 0); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } /* Now roll some pages back from the transaction journal. Pager.stmtJSize @@ -1453,19 +1472,19 @@ ** database, the memory cache, or both. ** ** If it is not zero, then Pager.stmtHdrOff is the offset to the start ** of the first journal header written during this statement transaction. */ - rc = sqlite3OsSeek(&pPager->jfd, pPager->stmtJSize); + rc = sqlite3OsSeek(pPager->jfd, pPager->stmtJSize); if( rc!=SQLITE_OK ){ goto end_stmt_playback; } pPager->journalOff = pPager->stmtJSize; pPager->cksumInit = pPager->stmtCksum; assert( JOURNAL_HDR_SZ(pPager)<(pPager->pageSize+8) ); while( pPager->journalOff <= (hdrOff-(pPager->pageSize+8)) ){ - rc = pager_playback_one_page(pPager, &pPager->jfd, 1); + rc = pager_playback_one_page(pPager, pPager->jfd, 1); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } while( pPager->journalOff < szJ ){ @@ -1478,11 +1497,11 @@ } if( nRec==0 ){ nRec = (szJ - pPager->journalOff) / (pPager->pageSize+8); } for(i=nRec-1; i>=0 && pPager->journalOff < szJ; i--){ - rc = pager_playback_one_page(pPager, &pPager->jfd, 1); + rc = pager_playback_one_page(pPager, pPager->jfd, 1); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } } @@ -1558,18 +1577,18 @@ ** other error code if we fail. ** ** The OS will automatically delete the temporary file when it is ** closed. */ -static int sqlite3pager_opentemp(char *zFile, OsFile *fd){ +static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){ int cnt = 8; int rc; sqlite3_opentemp_count++; /* Used for testing and analysis only */ do{ cnt--; sqlite3OsTempFileName(zFile); - rc = sqlite3OsOpenExclusive(zFile, fd, 1); + rc = sqlite3OsOpenExclusive(zFile, pFd, 1); }while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM ); return rc; } /* @@ -1590,34 +1609,44 @@ Pager **ppPager, /* Return the Pager structure here */ const char *zFilename, /* Name of the database file to open */ int nExtra, /* Extra bytes append to each in-memory page */ int flags /* flags controlling this file */ ){ - Pager *pPager; + Pager *pPager = 0; char *zFullPathname = 0; int nameLen; - OsFile fd; + OsFile *fd; int rc = SQLITE_OK; int i; int tempFile = 0; int memDb = 0; int readOnly = 0; int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; int noReadlock = (flags & PAGER_NO_READLOCK)!=0; char zTemp[SQLITE_TEMPNAME_SIZE]; +#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT + ThreadData *pTsd = sqlite3ThreadData(); +#endif + /* If malloc() has already failed return SQLITE_NOMEM. Before even + ** testing for this, set *ppPager to NULL so the caller knows the pager + ** structure was never allocated. + */ *ppPager = 0; - memset(&fd, 0, sizeof(fd)); - if( sqlite3_malloc_failed ){ + if( sqlite3ThreadData()->mallocFailed ){ return SQLITE_NOMEM; } + memset(&fd, 0, sizeof(fd)); + + /* Open the pager file and set zFullPathname to point at malloc()ed + ** memory containing the complete filename (i.e. including the directory). + */ if( zFilename && zFilename[0] ){ #ifndef SQLITE_OMIT_MEMORYDB if( strcmp(zFilename,":memory:")==0 ){ memDb = 1; zFullPathname = sqliteStrDup(""); - rc = SQLITE_OK; }else #endif { zFullPathname = sqlite3OsFullPathname(zFilename); if( zFullPathname ){ @@ -1630,41 +1659,45 @@ zFullPathname = sqlite3OsFullPathname(zFilename); if( rc==SQLITE_OK ){ tempFile = 1; } } - if( !zFullPathname ){ - sqlite3OsClose(&fd); - return SQLITE_NOMEM; - } - if( rc!=SQLITE_OK ){ - sqlite3OsClose(&fd); - sqliteFree(zFullPathname); - return rc; - } - nameLen = strlen(zFullPathname); - pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 ); - if( pPager==0 ){ - sqlite3OsClose(&fd); - sqliteFree(zFullPathname); - return SQLITE_NOMEM; - } + + /* Allocate the Pager structure. As part of the same allocation, allocate + ** space for the full paths of the file, directory and journal + ** (Pager.zFilename, Pager.zDirectory and Pager.zJournal). + */ + if( zFullPathname ){ + nameLen = strlen(zFullPathname); + pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 ); + } + + /* If an error occured in either of the blocks above, free the memory + ** pointed to by zFullPathname, free the Pager structure and close the + ** file. Since the pager is not allocated there is no need to set + ** any Pager.errMask variables. + */ + if( !pPager || !zFullPathname || rc!=SQLITE_OK ){ + sqlite3OsClose(&fd); + sqliteFree(zFullPathname); + sqliteFree(pPager); + return ((rc==SQLITE_OK)?SQLITE_NOMEM:rc); + } + TRACE3("OPEN %d %s\n", FILEHANDLEID(fd), zFullPathname); pPager->zFilename = (char*)&pPager[1]; pPager->zDirectory = &pPager->zFilename[nameLen+1]; pPager->zJournal = &pPager->zDirectory[nameLen+1]; strcpy(pPager->zFilename, zFullPathname); strcpy(pPager->zDirectory, zFullPathname); + for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){} if( i>0 ) pPager->zDirectory[i-1] = 0; strcpy(pPager->zJournal, zFullPathname); sqliteFree(zFullPathname); strcpy(&pPager->zJournal[nameLen], "-journal"); pPager->fd = fd; -#if OS_UNIX - pPager->fd.pPager = pPager; -#endif pPager->journalOpen = 0; pPager->useJournal = useJournal && !memDb; pPager->noReadlock = noReadlock && readOnly; pPager->stmtOpen = 0; pPager->stmtInUse = 0; @@ -1690,10 +1723,16 @@ pPager->nExtra = FORCE_ALIGNMENT(nExtra); pPager->sectorSize = PAGER_SECTOR_SIZE; pPager->pBusyHandler = 0; memset(pPager->aHash, 0, sizeof(pPager->aHash)); *ppPager = pPager; +#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT + if( pTsd->useMemoryManagement ){ + pPager->pNext = pTsd->pPager; + pTsd->pPager = pPager; + } +#endif return SQLITE_OK; } /* ** Set the busy handler function. @@ -1736,19 +1775,54 @@ pPager->pageSize = pageSize; } return pPager->pageSize; } +/* +** The following set of routines are used to disable the simulated +** I/O error mechanism. These routines are used to avoid simulated +** errors in places where we do not care about errors. +** +** Unless -DSQLITE_TEST=1 is used, these routines are all no-ops +** and generate no code. +*/ +#ifdef SQLITE_TEST +extern int sqlite3_io_error_pending; +extern int sqlite3_io_error_hit; +static int saved_cnt; +void clear_simulated_io_error(){ + sqlite3_io_error_hit = 0; +} +void disable_simulated_io_errors(void){ + saved_cnt = sqlite3_io_error_pending; + sqlite3_io_error_pending = -1; +} +void enable_simulated_io_errors(void){ + sqlite3_io_error_pending = saved_cnt; +} +#else +# define clear_simulated_io_error() +# define disable_simulated_io_errors() +# define enable_simulated_io_errors() +#endif + /* ** Read the first N bytes from the beginning of the file into memory -** that pDest points to. No error checking is done. +** that pDest points to. +** +** No error checking is done. The rational for this is that this function +** may be called even if the file does not exist or contain a header. In +** these cases sqlite3OsRead() will return an error, to which the correct +** response is to zero the memory at pDest and continue. A real IO error +** will presumably recur and be picked up later (Todo: Think about this). */ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){ memset(pDest, 0, N); if( MEMDB==0 ){ - sqlite3OsSeek(&pPager->fd, 0); - sqlite3OsRead(&pPager->fd, pDest, N); + sqlite3OsSeek(pPager->fd, 0); + sqlite3OsRead(pPager->fd, pDest, N); + clear_simulated_io_error(); } } /* ** Return the total number of pages in the disk file associated with @@ -1763,11 +1837,11 @@ i64 n; assert( pPager!=0 ); if( pPager->dbSize>=0 ){ n = pPager->dbSize; } else { - if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){ + if( sqlite3OsFileSize(pPager->fd, &n)!=SQLITE_OK ){ pPager->errMask |= PAGER_ERR_DISK; return 0; } if( n>0 && npageSize ){ n = 1; @@ -1895,11 +1969,11 @@ assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); if( pPager->state>=locktype ){ rc = SQLITE_OK; }else{ do { - rc = sqlite3OsLock(&pPager->fd, locktype); + rc = sqlite3OsLock(pPager->fd, locktype); }while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) ); if( rc==SQLITE_OK ){ pPager->state = locktype; } } @@ -1948,39 +2022,42 @@ ** If a transaction was in progress when this routine is called, that ** transaction is rolled back. All outstanding pages are invalidated ** and their memory is freed. Any attempt to use a page associated ** with this page cache after this function returns will likely ** result in a coredump. +** +** This function always succeeds. If a transaction is active an attempt +** is made to roll it back. If an error occurs during the rollback +** a hot journal may be left in the filesystem but no error is returned +** to the caller. */ int sqlite3pager_close(Pager *pPager){ PgHdr *pPg, *pNext; +#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT + ThreadData *pTsd = sqlite3ThreadData(); +#endif + switch( pPager->state ){ case PAGER_RESERVED: case PAGER_SYNCED: case PAGER_EXCLUSIVE: { /* We ignore any IO errors that occur during the rollback ** operation. So disable IO error simulation so that testing ** works more easily. */ -#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN)) - extern int sqlite3_io_error_pending; - int ioerr_cnt = sqlite3_io_error_pending; - sqlite3_io_error_pending = -1; -#endif + disable_simulated_io_errors(); sqlite3pager_rollback(pPager); -#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN)) - sqlite3_io_error_pending = ioerr_cnt; -#endif + enable_simulated_io_errors(); if( !MEMDB ){ - sqlite3OsUnlock(&pPager->fd, NO_LOCK); + sqlite3OsUnlock(pPager->fd, NO_LOCK); } assert( pPager->errMask || pPager->journalOpen==0 ); break; } case PAGER_SHARED: { if( !MEMDB ){ - sqlite3OsUnlock(&pPager->fd, NO_LOCK); + sqlite3OsUnlock(pPager->fd, NO_LOCK); } break; } default: { /* Do nothing */ @@ -2012,10 +2089,25 @@ /* Temp files are automatically deleted by the OS ** if( pPager->tempFile ){ ** sqlite3OsDelete(pPager->zFilename); ** } */ + +#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT + /* Remove the pager from the linked list of pagers starting at + ** ThreadData.pPager if memory-management is enabled. + */ + if( pTsd->useMemoryManagement ){ + if( pPager==pTsd->pPager ){ + pTsd->pPager = pPager->pNext; + }else{ + Pager *pTmp; + for(pTmp = pTsd->pPager; pTmp->pNext!=pPager; pTmp=pTmp->pNext); + pTmp->pNext = pPager->pNext; + } + } +#endif sqliteFree(pPager); return SQLITE_OK; } @@ -2118,11 +2210,11 @@ { /* Make sure the pPager->nRec counter we are keeping agrees ** with the nRec computed from the size of the journal file. */ i64 jSz; - rc = sqlite3OsFileSize(&pPager->jfd, &jSz); + rc = sqlite3OsFileSize(pPager->jfd, &jSz); if( rc!=0 ) return rc; assert( pPager->journalOff==jSz ); } #endif { @@ -2131,24 +2223,24 @@ ** all data has really hit the disk before nRec is updated to mark ** it as a candidate for rollback. */ if( pPager->fullSync ){ TRACE2("SYNC journal of %d\n", PAGERID(pPager)); - rc = sqlite3OsSync(&pPager->jfd, 0); + rc = sqlite3OsSync(pPager->jfd, 0); if( rc!=0 ) return rc; } - rc = sqlite3OsSeek(&pPager->jfd, + rc = sqlite3OsSeek(pPager->jfd, pPager->journalHdr + sizeof(aJournalMagic)); if( rc ) return rc; - rc = write32bits(&pPager->jfd, pPager->nRec); + rc = write32bits(pPager->jfd, pPager->nRec); if( rc ) return rc; - rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff); + rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff); if( rc ) return rc; } TRACE2("SYNC journal of %d\n", PAGERID(pPager)); - rc = sqlite3OsSync(&pPager->jfd, pPager->fullSync); + rc = sqlite3OsSync(pPager->jfd, pPager->fullSync); if( rc!=0 ) return rc; pPager->journalStarted = 1; } pPager->needSync = 0; @@ -2209,21 +2301,22 @@ return rc; } while( pList ){ assert( pList->dirty ); - rc = sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize); + rc = sqlite3OsSeek(pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize); if( rc ) return rc; /* If there are dirty pages in the page cache with page numbers greater ** than Pager.dbSize, this means sqlite3pager_truncate() was called to ** make the file smaller (presumably by auto-vacuum code). Do not write ** any such pages to the file. */ if( pList->pgno<=pPager->dbSize ){ CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6); TRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno); - rc = sqlite3OsWrite(&pPager->fd, PGHDR_TO_DATA(pList), pPager->pageSize); + rc = sqlite3OsWrite(pPager->fd, PGHDR_TO_DATA(pList), + pPager->pageSize); CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0); TEST_INCR(pPager->nWrite); } #ifndef NDEBUG else{ @@ -2266,19 +2359,183 @@ ** database with the same name. Just delete the journal. */ static int hasHotJournal(Pager *pPager){ if( !pPager->useJournal ) return 0; if( !sqlite3OsFileExists(pPager->zJournal) ) return 0; - if( sqlite3OsCheckReservedLock(&pPager->fd) ) return 0; + if( sqlite3OsCheckReservedLock(pPager->fd) ) return 0; if( sqlite3pager_pagecount(pPager)==0 ){ sqlite3OsDelete(pPager->zJournal); return 0; }else{ return 1; } } +/* +** Try to find a page in the cache that can be recycled. +** +** This routine may return SQLITE_IOERR, SQLITE_FULL or SQLITE_OK. It +** does not set the pPager->errMask variable. +*/ +static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){ + PgHdr *pPg; + *ppPg = 0; + + /* Find a page to recycle. Try to locate a page that does not + ** require us to do an fsync() on the journal. + */ + pPg = pPager->pFirstSynced; + + /* If we could not find a page that does not require an fsync() + ** on the journal file then fsync the journal file. This is a + ** very slow operation, so we work hard to avoid it. But sometimes + ** it can't be helped. + */ + if( pPg==0 && pPager->pFirst && syncOk && !MEMDB){ + int rc = syncJournal(pPager); + if( rc!=0 ){ + return rc; + } + if( pPager->fullSync ){ + /* If in full-sync mode, write a new journal header into the + ** journal file. This is done to avoid ever modifying a journal + ** header that is involved in the rollback of pages that have + ** already been written to the database (in case the header is + ** trashed when the nRec field is updated). + */ + pPager->nRec = 0; + assert( pPager->journalOff > 0 ); + rc = writeJournalHdr(pPager); + if( rc!=0 ){ + return rc; + } + } + pPg = pPager->pFirst; + } + if( pPg==0 ){ + return SQLITE_OK; + } + + assert( pPg->nRef==0 ); + + /* Write the page to the database file if it is dirty. + */ + if( pPg->dirty ){ + int rc; + assert( pPg->needSync==0 ); + pPg->pDirty = 0; + rc = pager_write_pagelist( pPg ); + if( rc!=SQLITE_OK ){ + return rc; + } + } + assert( pPg->dirty==0 ); + + /* If the page we are recycling is marked as alwaysRollback, then + ** set the global alwaysRollback flag, thus disabling the + ** sqlite_dont_rollback() optimization for the rest of this transaction. + ** It is necessary to do this because the page marked alwaysRollback + ** might be reloaded at a later time but at that point we won't remember + ** that is was marked alwaysRollback. This means that all pages must + ** be marked as alwaysRollback from here on out. + */ + if( pPg->alwaysRollback ){ + pPager->alwaysRollback = 1; + } + + /* Unlink the old page from the free list and the hash table + */ + unlinkPage(pPg); + TEST_INCR(pPager->nOvfl); + + *ppPg = pPg; + return SQLITE_OK; +} + +/* +** This function is called to free superfluous dynamically allocated memory +** held by the pager system. Memory in use by any SQLite pager allocated +** by the current thread may be sqliteFree()ed. +** +** nReq is the number of bytes of memory required. Once this much has +** been released, the function returns. A negative value for nReq means +** free as much memory as possible. The return value is the total number +** of bytes of memory released. +*/ +#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT +int sqlite3pager_release_memory(int nReq){ + ThreadData *pTsd = sqlite3ThreadData(); + Pager *p; + int nReleased = 0; + int i; + + /* If the the global mutex is held, this subroutine becomes a + ** o-op; zero bytes of memory are freed. This is because + ** some of the code invoked by this function may also + ** try to obtain the mutex, resulting in a deadlock. + */ + if( sqlite3OsInMutex() ){ + return 0; + } + + /* Outermost loop runs for at most two iterations. First iteration we + ** try to find memory that can be released without calling fsync(). Second + ** iteration (which only runs if the first failed to free nReq bytes of + ** memory) is permitted to call fsync(). This is of course much more + ** expensive. + */ + for(i=0; i<=1; i++){ + + /* Loop through all the SQLite pagers opened by the current thread. */ + for(p=pTsd->pPager; p && (nReq<0 || nReleasedpNext){ + PgHdr *pPg; + int rc; + + /* For each pager, try to free as many pages as possible (without + ** calling fsync() if this is the first iteration of the outermost + ** loop). + */ + while( SQLITE_OK==(rc = pager_recycle(p, i, &pPg)) && pPg) { + /* We've found a page to free. At this point the page has been + ** removed from the page hash-table, free-list and synced-list + ** (pFirstSynced). It is still in the all pages (pAll) list. + ** Remove it from this list before freeing. + ** + ** Todo: Check the Pager.pStmt list to make sure this is Ok. It + ** probably is though. + */ + PgHdr *pTmp; + assert( pPg ); + page_remove_from_stmt_list(pPg); + if( pPg==p->pAll ){ + p->pAll = pPg->pNextAll; + }else{ + for( pTmp=p->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ); + pTmp->pNextAll = pPg->pNextAll; + } + nReleased += sqliteAllocSize(pPg); + sqliteFree(pPg); + } + + if( rc!=SQLITE_OK ){ + /* An error occured whilst writing to the database file or + ** journal in pager_recycle(). The error is not returned to the + ** caller of this function. Instead, set the Pager.errMask variable. + ** The error will be returned to the user (or users, in the case + ** of a shared pager cache) of the pager for which the error occured. + */ + assert( rc==SQLITE_IOERR || rc==SQLITE_FULL ); + assert( p->state>=PAGER_RESERVED ); + pager_error(p, rc); + } + } + } + + return nReleased; +} +#endif /* SQLITE_OMIT_MEMORY_MANAGEMENT */ + /* ** Acquire a page. ** ** A read lock on the disk file is obtained when the first page is acquired. ** This read lock is dropped when the last page is released. @@ -2324,11 +2581,11 @@ */ if( pPager->nRef==0 && !MEMDB ){ if( !pPager->noReadlock ){ rc = pager_wait_on_lock(pPager, SHARED_LOCK); if( rc!=SQLITE_OK ){ - return rc; + return pager_error(pPager, rc); } } /* If a journal file exists, and there is no RESERVED lock on the ** database file, then it either needs to be played back or deleted. @@ -2345,15 +2602,15 @@ ** ** Because the intermediate RESERVED lock is not requested, the ** second process will get to this point in the code and fail to ** obtain it's own EXCLUSIVE lock on the database file. */ - rc = sqlite3OsLock(&pPager->fd, EXCLUSIVE_LOCK); + rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ - sqlite3OsUnlock(&pPager->fd, NO_LOCK); + sqlite3OsUnlock(pPager->fd, NO_LOCK); pPager->state = PAGER_UNLOCK; - return rc; + return pager_error(pPager, rc); } pPager->state = PAGER_EXCLUSIVE; /* Open the journal for reading only. Return SQLITE_BUSY if ** we are unable to open the journal file. @@ -2363,11 +2620,11 @@ ** a write lock, so there is never any chance of two or more ** processes opening the journal at the same time. */ rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd); if( rc!=SQLITE_OK ){ - sqlite3OsUnlock(&pPager->fd, NO_LOCK); + sqlite3OsUnlock(pPager->fd, NO_LOCK); pPager->state = PAGER_UNLOCK; return SQLITE_BUSY; } pPager->journalOpen = 1; pPager->journalStarted = 0; @@ -2378,11 +2635,11 @@ /* Playback and delete the journal. Drop the database write ** lock and reacquire the read lock. */ rc = pager_playback(pPager); if( rc!=SQLITE_OK ){ - return rc; + return pager_error(pPager, rc); } } pPg = 0; }else{ /* Search for page in cache */ @@ -2399,11 +2656,10 @@ /* Create a new page */ pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize + sizeof(u32) + pPager->nExtra + MEMDB*sizeof(PgHistory) ); if( pPg==0 ){ - pPager->errMask |= PAGER_ERR_MEM; return SQLITE_NOMEM; } memset(pPg, 0, sizeof(*pPg)); if( MEMDB ){ memset(PGHDR_TO_HIST(pPg, pPager), 0, sizeof(PgHistory)); @@ -2415,74 +2671,15 @@ if( pPager->nPage>pPager->nMaxPage ){ assert( pPager->nMaxPage==(pPager->nPage-1) ); pPager->nMaxPage++; } }else{ - /* Find a page to recycle. Try to locate a page that does not - ** require us to do an fsync() on the journal. - */ - pPg = pPager->pFirstSynced; - - /* If we could not find a page that does not require an fsync() - ** on the journal file then fsync the journal file. This is a - ** very slow operation, so we work hard to avoid it. But sometimes - ** it can't be helped. - */ - if( pPg==0 ){ - int rc = syncJournal(pPager); - if( rc!=0 ){ - sqlite3pager_rollback(pPager); - return SQLITE_IOERR; - } - if( pPager->fullSync ){ - /* If in full-sync mode, write a new journal header into the - ** journal file. This is done to avoid ever modifying a journal - ** header that is involved in the rollback of pages that have - ** already been written to the database (in case the header is - ** trashed when the nRec field is updated). - */ - pPager->nRec = 0; - assert( pPager->journalOff > 0 ); - rc = writeJournalHdr(pPager); - if( rc!=0 ){ - sqlite3pager_rollback(pPager); - return SQLITE_IOERR; - } - } - pPg = pPager->pFirst; - } - assert( pPg->nRef==0 ); - - /* Write the page to the database file if it is dirty. - */ - if( pPg->dirty ){ - assert( pPg->needSync==0 ); - pPg->pDirty = 0; - rc = pager_write_pagelist( pPg ); - if( rc!=SQLITE_OK ){ - sqlite3pager_rollback(pPager); - return SQLITE_IOERR; - } - } - assert( pPg->dirty==0 ); - - /* If the page we are recycling is marked as alwaysRollback, then - ** set the global alwaysRollback flag, thus disabling the - ** sqlite_dont_rollback() optimization for the rest of this transaction. - ** It is necessary to do this because the page marked alwaysRollback - ** might be reloaded at a later time but at that point we won't remember - ** that is was marked alwaysRollback. This means that all pages must - ** be marked as alwaysRollback from here on out. - */ - if( pPg->alwaysRollback ){ - pPager->alwaysRollback = 1; - } - - /* Unlink the old page from the free list and the hash table - */ - unlinkPage(pPg); - TEST_INCR(pPager->nOvfl); + rc = pager_recycle(pPager, 1, &pPg); + if( rc!=SQLITE_OK ){ + return pager_error(pPager, rc); + } + assert(pPg) ; } pPg->pgno = pgno; if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ sqlite3CheckMemory(pPager->aInJournal, pgno/8); assert( pPager->journalOpen ); @@ -2520,23 +2717,25 @@ if( sqlite3pager_pagecount(pPager)<(int)pgno ){ memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); }else{ int rc; assert( MEMDB==0 ); - rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize); + rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize); if( rc==SQLITE_OK ){ - rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize); + rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg), + pPager->pageSize); } TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno); CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3); if( rc!=SQLITE_OK ){ i64 fileSize; - if( sqlite3OsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK + if( sqlite3OsFileSize(pPager->fd,&fileSize)!=SQLITE_OK || fileSize>=pgno*pPager->pageSize ){ sqlite3pager_unref(PGHDR_TO_DATA(pPg)); - return rc; + return pager_error(pPager, rc); }else{ + clear_simulated_io_error(); memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); } }else{ TEST_INCR(pPager->nRead); } @@ -2649,20 +2848,21 @@ pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInJournal==0 ){ rc = SQLITE_NOMEM; goto failed_to_open_journal; } - rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile); + rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd, + pPager->tempFile); pPager->journalOff = 0; pPager->setMaster = 0; pPager->journalHdr = 0; if( rc!=SQLITE_OK ){ goto failed_to_open_journal; } - SET_FULLSYNC(pPager->jfd, pPager->fullSync); - SET_FULLSYNC(pPager->fd, pPager->fullSync); - sqlite3OsOpenDirectory(pPager->zDirectory, &pPager->jfd); + sqlite3OsSetFullSync(pPager->jfd, pPager->fullSync); + sqlite3OsSetFullSync(pPager->fd, pPager->fullSync); + sqlite3OsOpenDirectory(pPager->jfd, pPager->zDirectory); pPager->journalOpen = 1; pPager->journalStarted = 0; pPager->needSync = 0; pPager->alwaysRollback = 0; pPager->nRec = 0; @@ -2675,11 +2875,11 @@ rc = writeJournalHdr(pPager); if( pPager->stmtAutoopen && rc==SQLITE_OK ){ rc = sqlite3pager_stmt_begin(pPager); } - if( rc!=SQLITE_OK ){ + if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){ rc = pager_unwritelock(pPager); if( rc==SQLITE_OK ){ rc = SQLITE_FULL; } } @@ -2686,12 +2886,21 @@ return rc; failed_to_open_journal: sqliteFree(pPager->aInJournal); pPager->aInJournal = 0; - sqlite3OsUnlock(&pPager->fd, NO_LOCK); - pPager->state = PAGER_UNLOCK; + if( rc==SQLITE_NOMEM ){ + /* If this was a malloc() failure, then we will not be closing the pager + ** file. So delete any journal file we may have just created. Otherwise, + ** the system will get confused, we have a read-lock on the file and a + ** mysterious journal has appeared in the filesystem. + */ + sqlite3OsDelete(pPager->zJournal); + }else{ + sqlite3OsUnlock(pPager->fd, NO_LOCK); + pPager->state = PAGER_UNLOCK; + } return rc; } /* ** Acquire a write-lock on the database. The lock is removed when @@ -2730,11 +2939,11 @@ assert( pPager->aInJournal==0 ); if( MEMDB ){ pPager->state = PAGER_EXCLUSIVE; pPager->origDbSize = pPager->dbSize; }else{ - rc = sqlite3OsLock(&pPager->fd, RESERVED_LOCK); + rc = sqlite3OsLock(pPager->fd, RESERVED_LOCK); if( rc==SQLITE_OK ){ pPager->state = PAGER_RESERVED; if( exFlag ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } @@ -2841,11 +3050,11 @@ cksum = pager_cksum(pPager, pPg->pgno, pData); saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager); store32bits(cksum, pPg, pPager->pageSize); szPg = pPager->pageSize+8; store32bits(pPg->pgno, pPg, -4); - rc = sqlite3OsWrite(&pPager->jfd, &((char*)pData)[-4], szPg); + rc = sqlite3OsWrite(pPager->jfd, &((char*)pData)[-4], szPg); pPager->journalOff += szPg; TRACE4("JOURNAL %d page %d needSync=%d\n", PAGERID(pPager), pPg->pgno, pPg->needSync); CODEC(pPager, pData, pPg->pgno, 0); *(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved; @@ -2890,11 +3099,12 @@ } TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); }else{ store32bits(pPg->pgno, pPg, -4); CODEC(pPager, pData, pPg->pgno, 7); - rc = sqlite3OsWrite(&pPager->stfd,((char*)pData)-4, pPager->pageSize+4); + rc = sqlite3OsWrite(pPager->stfd,((char*)pData)-4, + pPager->pageSize+4); TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno); CODEC(pPager, pData, pPg->pgno, 0); if( rc!=SQLITE_OK ){ sqlite3pager_rollback(pPager); pPager->errMask |= PAGER_ERR_FULL; @@ -3252,15 +3462,15 @@ return SQLITE_OK; } assert( pPager->journalOpen ); pPager->aInStmt = sqliteMalloc( pPager->dbSize/8 + 1 ); if( pPager->aInStmt==0 ){ - sqlite3OsLock(&pPager->fd, SHARED_LOCK); + /* sqlite3OsLock(pPager->fd, SHARED_LOCK); */ return SQLITE_NOMEM; } #ifndef NDEBUG - rc = sqlite3OsFileSize(&pPager->jfd, &pPager->stmtJSize); + rc = sqlite3OsFileSize(pPager->jfd, &pPager->stmtJSize); if( rc ) goto stmt_begin_failed; assert( pPager->stmtJSize == pPager->journalOff ); #endif pPager->stmtJSize = pPager->journalOff; pPager->stmtSize = pPager->dbSize; @@ -3289,12 +3499,12 @@ int sqlite3pager_stmt_commit(Pager *pPager){ if( pPager->stmtInUse ){ PgHdr *pPg, *pNext; TRACE2("STMT-COMMIT %d\n", PAGERID(pPager)); if( !MEMDB ){ - sqlite3OsSeek(&pPager->stfd, 0); - /* sqlite3OsTruncate(&pPager->stfd, 0); */ + sqlite3OsSeek(pPager->stfd, 0); + /* sqlite3OsTruncate(pPager->stfd, 0); */ sqliteFree( pPager->aInStmt ); pPager->aInStmt = 0; } for(pPg=pPager->pStmt; pPg; pPg=pNext){ pNext = pPg->pNextStmt; @@ -3493,11 +3703,11 @@ rc = pager_write_pagelist(pPg); if( rc!=SQLITE_OK ) goto sync_exit; /* Sync the database file. */ if( !pPager->noSync ){ - rc = sqlite3OsSync(&pPager->fd, 0); + rc = sqlite3OsSync(pPager->fd, 0); } pPager->state = PAGER_SYNCED; } @@ -3607,15 +3817,11 @@ ** Return the current state of the file lock for the given pager. ** The return value is one of NO_LOCK, SHARED_LOCK, RESERVED_LOCK, ** PENDING_LOCK, or EXCLUSIVE_LOCK. */ int sqlite3pager_lockstate(Pager *pPager){ -#ifdef OS_TEST - return pPager->fd->fd.locktype; -#else - return pPager->fd.locktype; -#endif + return sqlite3OsLockState(pPager->fd); } #endif #ifdef SQLITE_DEBUG /* Index: SQLite.Interop/src/pager.h ================================================================== --- SQLite.Interop/src/pager.h +++ SQLite.Interop/src/pager.h @@ -11,12 +11,15 @@ ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** -** @(#) $Id: pager.h,v 1.11 2005/12/19 17:57:47 rmsimpson Exp $ +** @(#) $Id: pager.h,v 1.12 2006/01/10 18:40:37 rmsimpson Exp $ */ + +#ifndef _PAGER_H_ +#define _PAGER_H_ /* ** The default size of a database page. */ #ifndef SQLITE_DEFAULT_PAGE_SIZE @@ -103,14 +106,17 @@ int sqlite3pager_nosync(Pager*); int sqlite3pager_rename(Pager*, const char *zNewName); void sqlite3pager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*); int sqlite3pager_movepage(Pager*,void*,Pgno); int sqlite3pager_reset(Pager*); +int sqlite3pager_release_memory(int); #if defined(SQLITE_DEBUG) || defined(SQLITE_TEST) int sqlite3pager_lockstate(Pager*); #endif #ifdef SQLITE_TEST void sqlite3pager_refdump(Pager*); int pager3_refinfo_enable; #endif + +#endif /* _PAGER_H_ */ Index: SQLite.Interop/src/parse.c ================================================================== --- SQLite.Interop/src/parse.c +++ SQLite.Interop/src/parse.c @@ -91,39 +91,39 @@ ** YYNRULE the number of rules in the grammar ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. */ #define YYCODETYPE unsigned char -#define YYNOCODE 247 +#define YYNOCODE 240 #define YYACTIONTYPE unsigned short int #define sqlite3ParserTOKENTYPE Token typedef union { sqlite3ParserTOKENTYPE yy0; - struct TrigEvent yy30; - Expr* yy62; - SrcList* yy151; - Token yy198; - struct LimitVal yy220; - struct LikeOp yy222; - IdList* yy240; - int yy280; - struct {int value; int mask;} yy359; - TriggerStep* yy360; - struct AttachKey yy361; - Select* yy375; - ExprList* yy418; - int yy493; + struct {int value; int mask;} yy13; + struct TrigEvent yy132; + IdList* yy160; + Expr* yy178; + int yy230; + Select* yy239; + TriggerStep* yy247; + struct LimitVal yy270; + SrcList* yy285; + Expr * yy292; + Token yy384; + struct LikeOp yy440; + ExprList* yy462; + int yy479; } YYMINORTYPE; #define YYSTACKDEPTH 100 #define sqlite3ParserARG_SDECL Parse *pParse; #define sqlite3ParserARG_PDECL ,Parse *pParse #define sqlite3ParserARG_FETCH Parse *pParse = yypParser->pParse #define sqlite3ParserARG_STORE yypParser->pParse = pParse -#define YYNSTATE 581 -#define YYNRULE 311 -#define YYERRORSYMBOL 146 -#define YYERRSYMDT yy493 +#define YYNSTATE 561 +#define YYNRULE 295 +#define YYERRORSYMBOL 137 +#define YYERRSYMDT yy479 #define YYFALLBACK 1 #define YY_NO_ACTION (YYNSTATE+YYNRULE+2) #define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) #define YY_ERROR_ACTION (YYNSTATE+YYNRULE) @@ -173,489 +173,401 @@ ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. */ static const YYACTIONTYPE yy_action[] = { - /* 0 */ 286, 584, 113, 140, 142, 138, 144, 581, 150, 152, - /* 10 */ 154, 156, 158, 160, 162, 164, 166, 168, 3, 577, - /* 20 */ 740, 170, 178, 150, 152, 154, 156, 158, 160, 162, - /* 30 */ 164, 166, 168, 158, 160, 162, 164, 166, 168, 135, - /* 40 */ 97, 171, 181, 186, 191, 180, 185, 146, 148, 140, - /* 50 */ 142, 138, 144, 51, 150, 152, 154, 156, 158, 160, - /* 60 */ 162, 164, 166, 168, 16, 17, 18, 114, 7, 248, - /* 70 */ 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, - /* 80 */ 13, 37, 362, 40, 59, 67, 69, 326, 357, 170, - /* 90 */ 6, 5, 331, 95, 364, 359, 25, 374, 258, 893, - /* 100 */ 1, 580, 514, 13, 4, 575, 33, 135, 97, 171, - /* 110 */ 181, 186, 191, 180, 185, 146, 148, 140, 142, 138, - /* 120 */ 144, 9, 150, 152, 154, 156, 158, 160, 162, 164, - /* 130 */ 166, 168, 374, 136, 592, 80, 112, 99, 269, 34, - /* 140 */ 32, 33, 132, 373, 115, 14, 15, 378, 333, 99, - /* 150 */ 380, 387, 392, 13, 367, 370, 194, 170, 78, 500, - /* 160 */ 525, 315, 395, 369, 375, 408, 10, 98, 14, 15, - /* 170 */ 78, 200, 286, 864, 113, 135, 97, 171, 181, 186, - /* 180 */ 191, 180, 185, 146, 148, 140, 142, 138, 144, 80, - /* 190 */ 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, - /* 200 */ 104, 105, 106, 661, 496, 376, 374, 170, 467, 13, - /* 210 */ 2, 28, 237, 4, 409, 33, 3, 577, 14, 15, - /* 220 */ 51, 132, 133, 115, 241, 135, 97, 171, 181, 186, - /* 230 */ 191, 180, 185, 146, 148, 140, 142, 138, 144, 114, - /* 240 */ 150, 152, 154, 156, 158, 160, 162, 164, 166, 168, - /* 250 */ 40, 59, 67, 69, 326, 357, 136, 44, 45, 501, - /* 260 */ 473, 463, 359, 36, 361, 130, 128, 660, 275, 31, - /* 270 */ 84, 99, 356, 378, 14, 15, 380, 387, 392, 52, - /* 280 */ 170, 117, 122, 123, 113, 541, 369, 643, 395, 348, - /* 290 */ 98, 54, 78, 200, 302, 57, 58, 819, 135, 97, - /* 300 */ 171, 181, 186, 191, 180, 185, 146, 148, 140, 142, - /* 310 */ 138, 144, 861, 150, 152, 154, 156, 158, 160, 162, - /* 320 */ 164, 166, 168, 104, 105, 106, 817, 80, 48, 316, - /* 330 */ 162, 164, 166, 168, 319, 277, 12, 49, 99, 303, - /* 340 */ 283, 818, 99, 124, 304, 99, 241, 172, 593, 114, - /* 350 */ 50, 193, 46, 378, 170, 13, 380, 387, 392, 78, - /* 360 */ 260, 276, 47, 78, 200, 64, 78, 260, 395, 174, - /* 370 */ 175, 221, 135, 97, 171, 181, 186, 191, 180, 185, - /* 380 */ 146, 148, 140, 142, 138, 144, 199, 150, 152, 154, - /* 390 */ 156, 158, 160, 162, 164, 166, 168, 173, 252, 261, - /* 400 */ 120, 122, 123, 212, 170, 268, 254, 130, 128, 288, - /* 410 */ 590, 176, 246, 187, 192, 414, 195, 241, 197, 198, - /* 420 */ 14, 15, 135, 97, 171, 181, 186, 191, 180, 185, - /* 430 */ 146, 148, 140, 142, 138, 144, 433, 150, 152, 154, - /* 440 */ 156, 158, 160, 162, 164, 166, 168, 311, 99, 707, - /* 450 */ 99, 422, 708, 417, 275, 81, 318, 598, 99, 219, - /* 460 */ 13, 231, 124, 13, 176, 48, 187, 192, 20, 78, - /* 470 */ 317, 78, 214, 195, 49, 197, 198, 462, 170, 78, - /* 480 */ 200, 116, 27, 13, 410, 113, 591, 50, 80, 225, - /* 490 */ 195, 11, 197, 198, 506, 235, 135, 97, 171, 181, - /* 500 */ 186, 191, 180, 185, 146, 148, 140, 142, 138, 144, - /* 510 */ 80, 150, 152, 154, 156, 158, 160, 162, 164, 166, - /* 520 */ 168, 277, 215, 324, 606, 14, 15, 301, 14, 15, - /* 530 */ 512, 13, 508, 240, 196, 486, 195, 685, 197, 198, - /* 540 */ 22, 834, 445, 331, 462, 170, 444, 276, 14, 15, - /* 550 */ 114, 468, 278, 394, 599, 280, 470, 288, 446, 680, - /* 560 */ 13, 321, 404, 135, 97, 171, 181, 186, 191, 180, - /* 570 */ 185, 146, 148, 140, 142, 138, 144, 80, 150, 152, - /* 580 */ 154, 156, 158, 160, 162, 164, 166, 168, 74, 99, - /* 590 */ 540, 366, 73, 99, 352, 289, 14, 15, 176, 333, - /* 600 */ 187, 192, 486, 869, 359, 273, 283, 542, 543, 867, - /* 610 */ 78, 500, 510, 170, 78, 323, 682, 176, 472, 187, - /* 620 */ 192, 746, 118, 470, 119, 14, 15, 195, 346, 197, - /* 630 */ 198, 135, 97, 171, 181, 186, 191, 180, 185, 146, - /* 640 */ 148, 140, 142, 138, 144, 99, 150, 152, 154, 156, - /* 650 */ 158, 160, 162, 164, 166, 168, 532, 334, 341, 343, - /* 660 */ 841, 39, 195, 170, 197, 198, 78, 94, 124, 356, - /* 670 */ 271, 353, 439, 441, 440, 544, 883, 428, 72, 862, - /* 680 */ 288, 135, 97, 171, 181, 186, 191, 180, 185, 146, - /* 690 */ 148, 140, 142, 138, 144, 13, 150, 152, 154, 156, - /* 700 */ 158, 160, 162, 164, 166, 168, 195, 99, 197, 198, - /* 710 */ 406, 330, 195, 170, 197, 198, 568, 405, 306, 195, - /* 720 */ 42, 197, 198, 65, 195, 539, 197, 198, 78, 96, - /* 730 */ 66, 135, 97, 171, 181, 186, 191, 180, 185, 146, - /* 740 */ 148, 140, 142, 138, 144, 885, 150, 152, 154, 156, - /* 750 */ 158, 160, 162, 164, 166, 168, 99, 740, 99, 298, - /* 760 */ 14, 15, 272, 170, 13, 74, 572, 86, 600, 73, - /* 770 */ 126, 127, 614, 709, 309, 478, 24, 78, 247, 78, - /* 780 */ 111, 135, 97, 171, 181, 186, 191, 180, 185, 146, - /* 790 */ 148, 140, 142, 138, 144, 99, 150, 152, 154, 156, - /* 800 */ 158, 160, 162, 164, 166, 168, 99, 238, 113, 239, - /* 810 */ 295, 26, 296, 170, 338, 337, 78, 137, 294, 320, - /* 820 */ 347, 239, 348, 390, 211, 348, 30, 78, 139, 14, - /* 830 */ 15, 135, 189, 171, 181, 186, 191, 180, 185, 146, - /* 840 */ 148, 140, 142, 138, 144, 99, 150, 152, 154, 156, - /* 850 */ 158, 160, 162, 164, 166, 168, 99, 80, 99, 372, - /* 860 */ 399, 442, 348, 170, 298, 243, 78, 141, 363, 601, - /* 870 */ 428, 437, 438, 114, 411, 269, 605, 78, 143, 78, - /* 880 */ 145, 448, 97, 171, 181, 186, 191, 180, 185, 146, - /* 890 */ 148, 140, 142, 138, 144, 99, 150, 152, 154, 156, - /* 900 */ 158, 160, 162, 164, 166, 168, 99, 80, 99, 430, - /* 910 */ 99, 296, 555, 170, 413, 856, 78, 147, 672, 457, - /* 920 */ 352, 348, 298, 443, 465, 45, 35, 78, 149, 78, - /* 930 */ 151, 78, 153, 171, 181, 186, 191, 180, 185, 146, - /* 940 */ 148, 140, 142, 138, 144, 99, 150, 152, 154, 156, - /* 950 */ 158, 160, 162, 164, 166, 168, 99, 459, 99, 29, - /* 960 */ 79, 464, 183, 483, 71, 339, 78, 155, 709, 421, - /* 970 */ 428, 79, 109, 99, 491, 71, 296, 78, 157, 78, - /* 980 */ 159, 490, 243, 109, 99, 340, 99, 449, 857, 223, - /* 990 */ 99, 460, 182, 709, 78, 161, 99, 349, 827, 136, - /* 1000 */ 223, 99, 80, 201, 99, 78, 163, 78, 165, 507, - /* 1010 */ 136, 78, 167, 42, 201, 38, 493, 78, 169, 569, - /* 1020 */ 207, 205, 78, 177, 674, 78, 179, 477, 203, 76, - /* 1030 */ 77, 207, 205, 98, 99, 84, 99, 42, 336, 203, - /* 1040 */ 76, 77, 99, 43, 98, 41, 428, 79, 494, 80, - /* 1050 */ 428, 71, 84, 99, 352, 78, 188, 78, 190, 109, - /* 1060 */ 499, 428, 497, 78, 202, 60, 104, 105, 106, 107, - /* 1070 */ 108, 209, 213, 99, 78, 204, 223, 104, 105, 106, - /* 1080 */ 107, 108, 209, 213, 820, 509, 136, 53, 383, 511, - /* 1090 */ 201, 99, 56, 61, 78, 206, 55, 428, 428, 889, - /* 1100 */ 513, 99, 243, 99, 352, 99, 79, 207, 205, 312, - /* 1110 */ 71, 99, 78, 208, 483, 203, 76, 77, 109, 533, - /* 1120 */ 98, 497, 78, 220, 78, 222, 78, 232, 84, 99, - /* 1130 */ 428, 353, 78, 234, 352, 223, 517, 521, 389, 99, - /* 1140 */ 62, 530, 99, 64, 63, 136, 68, 529, 70, 201, - /* 1150 */ 78, 236, 352, 104, 105, 106, 107, 108, 209, 213, - /* 1160 */ 78, 249, 99, 78, 265, 877, 207, 205, 398, 527, - /* 1170 */ 99, 615, 616, 313, 203, 76, 77, 99, 523, 98, - /* 1180 */ 80, 353, 8, 78, 270, 99, 456, 19, 21, 23, - /* 1190 */ 412, 78, 300, 75, 78, 310, 82, 84, 78, 365, - /* 1200 */ 563, 83, 547, 99, 87, 553, 78, 393, 85, 557, - /* 1210 */ 99, 353, 104, 105, 106, 107, 108, 209, 213, 99, - /* 1220 */ 269, 536, 99, 467, 78, 434, 88, 266, 534, 353, - /* 1230 */ 560, 78, 481, 566, 264, 89, 250, 90, 93, 91, - /* 1240 */ 78, 485, 101, 78, 498, 92, 100, 102, 103, 110, - /* 1250 */ 131, 121, 134, 125, 129, 168, 184, 242, 686, 687, - /* 1260 */ 688, 210, 233, 218, 224, 216, 227, 226, 217, 229, - /* 1270 */ 228, 230, 243, 251, 515, 519, 463, 245, 253, 244, - /* 1280 */ 505, 257, 255, 256, 258, 84, 259, 262, 263, 239, - /* 1290 */ 267, 279, 274, 281, 282, 299, 285, 292, 284, 287, - /* 1300 */ 290, 293, 297, 305, 314, 291, 307, 322, 308, 325, - /* 1310 */ 327, 345, 329, 328, 332, 350, 354, 330, 358, 335, - /* 1320 */ 342, 379, 381, 382, 344, 351, 368, 385, 355, 371, - /* 1330 */ 388, 360, 396, 397, 400, 401, 415, 54, 416, 386, - /* 1340 */ 384, 391, 418, 402, 407, 419, 377, 420, 423, 424, - /* 1350 */ 403, 426, 425, 427, 429, 435, 431, 849, 436, 854, - /* 1360 */ 432, 855, 450, 447, 451, 452, 454, 453, 825, 455, - /* 1370 */ 458, 826, 469, 461, 466, 747, 748, 848, 471, 464, - /* 1380 */ 863, 480, 474, 475, 476, 482, 865, 479, 487, 484, - /* 1390 */ 489, 488, 492, 866, 495, 868, 504, 679, 502, 681, - /* 1400 */ 833, 875, 518, 503, 516, 739, 520, 524, 522, 742, - /* 1410 */ 745, 531, 526, 835, 535, 528, 538, 537, 836, 837, - /* 1420 */ 838, 839, 545, 546, 840, 550, 876, 556, 551, 878, - /* 1430 */ 548, 549, 554, 879, 559, 882, 884, 562, 886, 561, - /* 1440 */ 552, 558, 564, 567, 570, 565, 571, 887, 576, 574, - /* 1450 */ 573, 888, 578, 559, 559, 579, + /* 0 */ 281, 67, 344, 80, 150, 157, 225, 517, 92, 92, + /* 10 */ 92, 92, 288, 59, 59, 59, 59, 58, 58, 57, + /* 20 */ 57, 57, 65, 346, 478, 48, 544, 86, 59, 59, + /* 30 */ 59, 59, 58, 58, 57, 57, 57, 65, 67, 481, + /* 40 */ 80, 150, 231, 64, 88, 295, 525, 518, 530, 530, + /* 50 */ 72, 72, 92, 92, 92, 92, 219, 59, 59, 59, + /* 60 */ 59, 58, 58, 57, 57, 57, 65, 281, 252, 189, + /* 70 */ 517, 296, 344, 81, 59, 59, 59, 59, 58, 58, + /* 80 */ 57, 57, 57, 65, 166, 115, 246, 303, 264, 323, + /* 90 */ 196, 236, 158, 544, 478, 49, 387, 69, 228, 857, + /* 100 */ 128, 560, 247, 56, 2, 381, 22, 476, 456, 363, + /* 110 */ 64, 88, 295, 525, 518, 530, 530, 72, 72, 92, + /* 120 */ 92, 92, 92, 283, 59, 59, 59, 59, 58, 58, + /* 130 */ 57, 57, 57, 65, 281, 344, 279, 386, 395, 553, + /* 140 */ 388, 165, 386, 276, 361, 288, 223, 439, 520, 451, + /* 150 */ 344, 58, 58, 57, 57, 57, 65, 478, 38, 365, + /* 160 */ 544, 145, 143, 282, 67, 393, 80, 150, 451, 500, + /* 170 */ 393, 189, 478, 36, 500, 424, 425, 64, 88, 295, + /* 180 */ 525, 518, 530, 530, 72, 72, 92, 92, 92, 92, + /* 190 */ 71, 59, 59, 59, 59, 58, 58, 57, 57, 57, + /* 200 */ 65, 281, 508, 508, 508, 429, 146, 508, 508, 508, + /* 210 */ 294, 512, 507, 198, 344, 520, 350, 357, 362, 246, + /* 220 */ 303, 264, 323, 196, 236, 283, 221, 544, 367, 310, + /* 230 */ 228, 228, 57, 57, 57, 65, 478, 48, 308, 299, + /* 240 */ 534, 537, 306, 417, 64, 88, 295, 525, 518, 530, + /* 250 */ 530, 72, 72, 92, 92, 92, 92, 551, 59, 59, + /* 260 */ 59, 59, 58, 58, 57, 57, 57, 65, 281, 550, + /* 270 */ 202, 416, 198, 375, 520, 350, 357, 362, 512, 507, + /* 280 */ 413, 414, 344, 293, 344, 372, 21, 367, 198, 522, + /* 290 */ 517, 350, 357, 362, 544, 359, 539, 371, 374, 126, + /* 300 */ 403, 209, 200, 367, 478, 18, 478, 43, 194, 169, + /* 310 */ 384, 64, 88, 295, 525, 518, 530, 530, 72, 72, + /* 320 */ 92, 92, 92, 92, 232, 59, 59, 59, 59, 58, + /* 330 */ 58, 57, 57, 57, 65, 511, 344, 512, 507, 427, + /* 340 */ 281, 420, 479, 479, 148, 419, 331, 233, 344, 67, + /* 350 */ 344, 80, 150, 517, 344, 176, 155, 309, 478, 32, + /* 360 */ 315, 436, 149, 184, 464, 195, 544, 348, 78, 533, + /* 370 */ 478, 51, 478, 51, 378, 428, 478, 51, 479, 443, + /* 380 */ 158, 377, 85, 64, 88, 295, 525, 518, 530, 530, + /* 390 */ 72, 72, 92, 92, 92, 92, 479, 59, 59, 59, + /* 400 */ 59, 58, 58, 57, 57, 57, 65, 281, 387, 467, + /* 410 */ 504, 162, 77, 324, 344, 290, 521, 457, 22, 300, + /* 420 */ 353, 520, 513, 513, 432, 487, 14, 487, 329, 271, + /* 430 */ 257, 487, 426, 544, 523, 524, 478, 51, 217, 208, + /* 440 */ 206, 144, 380, 355, 534, 537, 353, 55, 513, 513, + /* 450 */ 64, 88, 295, 525, 518, 530, 530, 72, 72, 92, + /* 460 */ 92, 92, 92, 375, 59, 59, 59, 59, 58, 58, + /* 470 */ 57, 57, 57, 65, 281, 372, 11, 127, 71, 218, + /* 480 */ 520, 241, 182, 126, 512, 507, 164, 155, 374, 520, + /* 490 */ 338, 488, 452, 398, 543, 353, 200, 513, 513, 1, + /* 500 */ 544, 401, 353, 520, 513, 513, 200, 553, 366, 165, + /* 510 */ 157, 463, 517, 358, 540, 538, 479, 64, 88, 295, + /* 520 */ 525, 518, 530, 530, 72, 72, 92, 92, 92, 92, + /* 530 */ 468, 59, 59, 59, 59, 58, 58, 57, 57, 57, + /* 540 */ 65, 370, 541, 512, 507, 437, 281, 344, 172, 506, + /* 550 */ 239, 344, 512, 507, 344, 387, 224, 448, 93, 344, + /* 560 */ 89, 344, 313, 344, 555, 22, 512, 507, 182, 478, + /* 570 */ 27, 520, 544, 478, 43, 517, 478, 50, 561, 547, + /* 580 */ 369, 478, 47, 478, 114, 478, 95, 528, 91, 64, + /* 590 */ 88, 295, 525, 518, 530, 530, 72, 72, 92, 92, + /* 600 */ 92, 92, 479, 59, 59, 59, 59, 58, 58, 57, + /* 610 */ 57, 57, 65, 281, 226, 344, 251, 174, 110, 344, + /* 620 */ 141, 147, 344, 465, 344, 449, 325, 370, 270, 344, + /* 630 */ 421, 344, 450, 554, 512, 507, 2, 478, 52, 544, + /* 640 */ 595, 478, 44, 311, 478, 30, 478, 45, 313, 173, + /* 650 */ 418, 478, 53, 478, 25, 479, 64, 88, 295, 525, + /* 660 */ 518, 530, 530, 72, 72, 92, 92, 92, 92, 344, + /* 670 */ 59, 59, 59, 59, 58, 58, 57, 57, 57, 65, + /* 680 */ 281, 344, 404, 479, 433, 344, 470, 344, 152, 344, + /* 690 */ 469, 478, 112, 344, 415, 314, 415, 344, 411, 344, + /* 700 */ 126, 287, 161, 478, 94, 440, 544, 478, 113, 478, + /* 710 */ 12, 478, 99, 401, 465, 478, 41, 292, 456, 478, + /* 720 */ 100, 478, 46, 64, 88, 295, 525, 518, 530, 530, + /* 730 */ 72, 72, 92, 92, 92, 92, 344, 59, 59, 59, + /* 740 */ 59, 58, 58, 57, 57, 57, 65, 281, 344, 485, + /* 750 */ 19, 404, 344, 514, 344, 79, 307, 260, 478, 111, + /* 760 */ 344, 242, 344, 548, 548, 344, 503, 501, 497, 466, + /* 770 */ 478, 42, 404, 544, 478, 26, 478, 39, 478, 3, + /* 780 */ 304, 423, 478, 31, 478, 40, 291, 478, 37, 305, + /* 790 */ 64, 88, 295, 525, 518, 530, 530, 72, 72, 92, + /* 800 */ 92, 92, 92, 344, 59, 59, 59, 59, 58, 58, + /* 810 */ 57, 57, 57, 65, 281, 344, 470, 404, 126, 344, + /* 820 */ 469, 344, 20, 344, 139, 478, 97, 344, 320, 7, + /* 830 */ 242, 344, 190, 181, 180, 208, 451, 478, 28, 258, + /* 840 */ 544, 478, 54, 478, 35, 478, 33, 222, 327, 478, + /* 850 */ 34, 262, 204, 478, 29, 435, 191, 64, 76, 295, + /* 860 */ 525, 518, 530, 530, 72, 72, 92, 92, 92, 92, + /* 870 */ 404, 59, 59, 59, 59, 58, 58, 57, 57, 57, + /* 880 */ 65, 281, 404, 454, 177, 162, 344, 208, 344, 175, + /* 890 */ 479, 320, 447, 235, 211, 794, 242, 286, 456, 516, + /* 900 */ 352, 441, 409, 410, 409, 298, 385, 544, 478, 24, + /* 910 */ 478, 98, 252, 252, 252, 252, 275, 284, 479, 252, + /* 920 */ 334, 252, 252, 479, 281, 88, 295, 525, 518, 530, + /* 930 */ 530, 72, 72, 92, 92, 92, 92, 274, 59, 59, + /* 940 */ 59, 59, 58, 58, 57, 57, 57, 65, 517, 242, + /* 950 */ 544, 244, 252, 237, 340, 215, 494, 214, 390, 546, + /* 960 */ 492, 242, 256, 489, 475, 406, 79, 397, 273, 295, + /* 970 */ 525, 518, 530, 530, 72, 72, 92, 92, 92, 92, + /* 980 */ 116, 59, 59, 59, 59, 58, 58, 57, 57, 57, + /* 990 */ 65, 62, 345, 484, 4, 407, 412, 269, 289, 126, + /* 1000 */ 519, 259, 23, 550, 202, 552, 349, 62, 345, 549, + /* 1010 */ 4, 517, 354, 493, 289, 14, 547, 369, 402, 316, + /* 1020 */ 240, 453, 349, 339, 472, 356, 142, 266, 471, 477, + /* 1030 */ 249, 319, 505, 386, 459, 343, 529, 428, 255, 339, + /* 1040 */ 71, 458, 499, 118, 333, 130, 121, 192, 389, 386, + /* 1050 */ 123, 156, 60, 61, 483, 103, 87, 125, 212, 480, + /* 1060 */ 62, 328, 330, 178, 277, 500, 229, 210, 60, 61, + /* 1070 */ 438, 297, 399, 491, 476, 473, 62, 328, 330, 62, + /* 1080 */ 345, 500, 4, 474, 208, 302, 289, 342, 207, 186, + /* 1090 */ 498, 68, 278, 120, 349, 136, 400, 556, 508, 508, + /* 1100 */ 508, 509, 510, 17, 312, 106, 243, 326, 205, 245, + /* 1110 */ 373, 339, 434, 285, 508, 508, 508, 509, 510, 17, + /* 1120 */ 74, 386, 160, 431, 248, 8, 321, 227, 220, 230, + /* 1130 */ 102, 332, 137, 382, 383, 536, 405, 234, 75, 183, + /* 1140 */ 60, 61, 317, 170, 265, 254, 135, 336, 62, 328, + /* 1150 */ 330, 442, 267, 500, 263, 66, 318, 261, 201, 455, + /* 1160 */ 447, 73, 461, 408, 168, 531, 443, 83, 482, 446, + /* 1170 */ 376, 171, 396, 167, 444, 542, 545, 208, 238, 272, + /* 1180 */ 213, 163, 188, 101, 364, 96, 508, 508, 508, 509, + /* 1190 */ 510, 17, 490, 63, 270, 322, 153, 105, 335, 535, + /* 1200 */ 526, 108, 558, 394, 527, 532, 250, 515, 379, 391, + /* 1210 */ 13, 368, 557, 107, 351, 337, 216, 257, 82, 132, + /* 1220 */ 559, 280, 109, 179, 347, 140, 208, 159, 65, 185, + /* 1230 */ 502, 341, 268, 193, 392, 131, 129, 203, 496, 151, + /* 1240 */ 10, 104, 154, 430, 486, 138, 253, 199, 495, 422, + /* 1250 */ 360, 162, 445, 5, 15, 597, 9, 187, 117, 122, + /* 1260 */ 596, 119, 133, 16, 6, 124, 301, 134, 14, 90, + /* 1270 */ 70, 462, 84, 460, 197, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 28, 11, 30, 77, 78, 79, 80, 0, 82, 83, - /* 10 */ 84, 85, 86, 87, 88, 89, 90, 91, 11, 12, - /* 20 */ 11, 49, 81, 82, 83, 84, 85, 86, 87, 88, - /* 30 */ 89, 90, 91, 86, 87, 88, 89, 90, 91, 67, - /* 40 */ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - /* 50 */ 78, 79, 80, 69, 82, 83, 84, 85, 86, 87, - /* 60 */ 88, 89, 90, 91, 17, 18, 19, 95, 11, 29, - /* 70 */ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - /* 80 */ 30, 97, 98, 99, 100, 101, 102, 103, 104, 49, - /* 90 */ 150, 151, 50, 53, 26, 111, 156, 155, 30, 147, - /* 100 */ 148, 149, 162, 30, 152, 163, 164, 67, 68, 69, - /* 110 */ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - /* 120 */ 80, 153, 82, 83, 84, 85, 86, 87, 88, 89, - /* 130 */ 90, 91, 155, 65, 11, 195, 28, 155, 129, 165, - /* 140 */ 163, 164, 168, 169, 170, 95, 96, 97, 106, 155, - /* 150 */ 100, 101, 102, 30, 86, 87, 162, 49, 176, 177, - /* 160 */ 220, 88, 112, 95, 187, 188, 154, 99, 95, 96, - /* 170 */ 176, 177, 28, 21, 30, 67, 68, 69, 70, 71, - /* 180 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 195, - /* 190 */ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - /* 200 */ 132, 133, 134, 27, 222, 29, 155, 49, 56, 30, - /* 210 */ 149, 160, 218, 152, 163, 164, 11, 12, 95, 96, - /* 220 */ 69, 168, 169, 170, 230, 67, 68, 69, 70, 71, - /* 230 */ 72, 73, 74, 75, 76, 77, 78, 79, 80, 95, - /* 240 */ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - /* 250 */ 99, 100, 101, 102, 103, 104, 65, 192, 193, 107, - /* 260 */ 108, 109, 111, 174, 175, 86, 87, 27, 29, 29, - /* 270 */ 118, 155, 183, 97, 95, 96, 100, 101, 102, 99, - /* 280 */ 49, 171, 172, 173, 30, 106, 95, 27, 112, 29, - /* 290 */ 99, 111, 176, 177, 162, 17, 18, 139, 67, 68, - /* 300 */ 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - /* 310 */ 79, 80, 15, 82, 83, 84, 85, 86, 87, 88, - /* 320 */ 89, 90, 91, 132, 133, 134, 21, 195, 22, 27, - /* 330 */ 88, 89, 90, 91, 218, 96, 155, 31, 155, 207, - /* 340 */ 208, 21, 155, 233, 212, 155, 230, 49, 11, 95, - /* 350 */ 44, 26, 46, 97, 49, 30, 100, 101, 102, 176, - /* 360 */ 177, 122, 56, 176, 177, 105, 176, 177, 112, 71, - /* 370 */ 72, 140, 67, 68, 69, 70, 71, 72, 73, 74, - /* 380 */ 75, 76, 77, 78, 79, 80, 27, 82, 83, 84, - /* 390 */ 85, 86, 87, 88, 89, 90, 91, 99, 215, 216, - /* 400 */ 171, 172, 173, 27, 49, 218, 216, 86, 87, 168, - /* 410 */ 11, 223, 224, 225, 226, 24, 114, 230, 116, 117, - /* 420 */ 95, 96, 67, 68, 69, 70, 71, 72, 73, 74, - /* 430 */ 75, 76, 77, 78, 79, 80, 139, 82, 83, 84, - /* 440 */ 85, 86, 87, 88, 89, 90, 91, 206, 155, 27, - /* 450 */ 155, 60, 27, 62, 29, 162, 27, 11, 155, 139, - /* 460 */ 30, 141, 233, 30, 223, 22, 225, 226, 154, 176, - /* 470 */ 177, 176, 177, 114, 31, 116, 117, 162, 49, 176, - /* 480 */ 177, 26, 26, 30, 28, 30, 11, 44, 195, 46, - /* 490 */ 114, 16, 116, 117, 24, 140, 67, 68, 69, 70, - /* 500 */ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - /* 510 */ 195, 82, 83, 84, 85, 86, 87, 88, 89, 90, - /* 520 */ 91, 96, 227, 27, 11, 95, 96, 26, 95, 96, - /* 530 */ 60, 30, 62, 230, 115, 220, 114, 118, 116, 117, - /* 540 */ 154, 11, 32, 50, 162, 49, 36, 122, 95, 96, - /* 550 */ 95, 236, 122, 178, 11, 122, 241, 168, 48, 11, - /* 560 */ 30, 88, 69, 67, 68, 69, 70, 71, 72, 73, - /* 570 */ 74, 75, 76, 77, 78, 79, 80, 195, 82, 83, - /* 580 */ 84, 85, 86, 87, 88, 89, 90, 91, 115, 155, - /* 590 */ 155, 27, 119, 155, 155, 206, 95, 96, 223, 106, - /* 600 */ 225, 226, 220, 11, 111, 207, 208, 172, 173, 11, - /* 610 */ 176, 177, 142, 49, 176, 177, 11, 223, 236, 225, - /* 620 */ 226, 11, 27, 241, 29, 95, 96, 114, 189, 116, - /* 630 */ 117, 67, 68, 69, 70, 71, 72, 73, 74, 75, - /* 640 */ 76, 77, 78, 79, 80, 155, 82, 83, 84, 85, - /* 650 */ 86, 87, 88, 89, 90, 91, 222, 107, 108, 109, - /* 660 */ 11, 175, 114, 49, 116, 117, 176, 177, 233, 183, - /* 670 */ 29, 232, 107, 108, 109, 26, 11, 155, 26, 15, - /* 680 */ 168, 67, 68, 69, 70, 71, 72, 73, 74, 75, - /* 690 */ 76, 77, 78, 79, 80, 30, 82, 83, 84, 85, - /* 700 */ 86, 87, 88, 89, 90, 91, 114, 155, 116, 117, - /* 710 */ 183, 184, 114, 49, 116, 117, 194, 190, 206, 114, - /* 720 */ 106, 116, 117, 34, 114, 76, 116, 117, 176, 177, - /* 730 */ 41, 67, 68, 69, 70, 71, 72, 73, 74, 75, - /* 740 */ 76, 77, 78, 79, 80, 11, 82, 83, 84, 85, - /* 750 */ 86, 87, 88, 89, 90, 91, 155, 11, 155, 155, - /* 760 */ 95, 96, 121, 49, 30, 115, 244, 198, 11, 119, - /* 770 */ 132, 133, 120, 28, 205, 29, 154, 176, 177, 176, - /* 780 */ 177, 67, 68, 69, 70, 71, 72, 73, 74, 75, - /* 790 */ 76, 77, 78, 79, 80, 155, 82, 83, 84, 85, - /* 800 */ 86, 87, 88, 89, 90, 91, 155, 27, 30, 29, - /* 810 */ 27, 157, 29, 49, 98, 99, 176, 177, 214, 27, - /* 820 */ 27, 29, 29, 27, 162, 29, 27, 176, 177, 95, - /* 830 */ 96, 67, 68, 69, 70, 71, 72, 73, 74, 75, - /* 840 */ 76, 77, 78, 79, 80, 155, 82, 83, 84, 85, - /* 850 */ 86, 87, 88, 89, 90, 91, 155, 195, 155, 167, - /* 860 */ 27, 52, 29, 49, 155, 120, 176, 177, 176, 11, - /* 870 */ 155, 58, 59, 95, 162, 129, 11, 176, 177, 176, - /* 880 */ 177, 25, 68, 69, 70, 71, 72, 73, 74, 75, - /* 890 */ 76, 77, 78, 79, 80, 155, 82, 83, 84, 85, - /* 900 */ 86, 87, 88, 89, 90, 91, 155, 195, 155, 194, - /* 910 */ 155, 29, 134, 49, 158, 106, 176, 177, 11, 27, - /* 920 */ 155, 29, 155, 214, 192, 193, 166, 176, 177, 176, - /* 930 */ 177, 176, 177, 69, 70, 71, 72, 73, 74, 75, - /* 940 */ 76, 77, 78, 79, 80, 155, 82, 83, 84, 85, - /* 950 */ 86, 87, 88, 89, 90, 91, 155, 101, 155, 161, - /* 960 */ 26, 67, 69, 155, 30, 37, 176, 177, 106, 162, - /* 970 */ 155, 26, 38, 155, 27, 30, 29, 176, 177, 176, - /* 980 */ 177, 214, 120, 38, 155, 57, 155, 231, 106, 55, - /* 990 */ 155, 235, 99, 11, 176, 177, 155, 232, 142, 65, - /* 1000 */ 55, 155, 195, 69, 155, 176, 177, 176, 177, 194, - /* 1010 */ 65, 176, 177, 106, 69, 155, 162, 176, 177, 64, - /* 1020 */ 86, 87, 176, 177, 130, 176, 177, 219, 94, 95, - /* 1030 */ 96, 86, 87, 99, 155, 118, 155, 106, 110, 94, - /* 1040 */ 95, 96, 155, 39, 99, 178, 155, 26, 131, 195, - /* 1050 */ 155, 30, 118, 155, 155, 176, 177, 176, 177, 38, - /* 1060 */ 27, 155, 29, 176, 177, 51, 132, 133, 134, 135, - /* 1070 */ 136, 137, 138, 155, 176, 177, 55, 132, 133, 134, - /* 1080 */ 135, 136, 137, 138, 139, 194, 65, 178, 189, 194, - /* 1090 */ 69, 155, 47, 179, 176, 177, 186, 155, 155, 144, - /* 1100 */ 194, 155, 120, 155, 155, 155, 26, 86, 87, 88, - /* 1110 */ 30, 155, 176, 177, 155, 94, 95, 96, 38, 27, - /* 1120 */ 99, 29, 176, 177, 176, 177, 176, 177, 118, 155, - /* 1130 */ 155, 232, 176, 177, 155, 55, 194, 194, 189, 155, - /* 1140 */ 178, 131, 155, 105, 180, 65, 178, 162, 26, 69, - /* 1150 */ 176, 177, 155, 132, 133, 134, 135, 136, 137, 138, - /* 1160 */ 176, 177, 155, 176, 177, 11, 86, 87, 189, 194, - /* 1170 */ 155, 120, 120, 155, 94, 95, 96, 155, 219, 99, - /* 1180 */ 195, 232, 15, 176, 177, 155, 189, 20, 21, 22, - /* 1190 */ 23, 176, 177, 197, 176, 177, 196, 118, 176, 177, - /* 1200 */ 33, 195, 35, 155, 199, 51, 176, 177, 197, 42, - /* 1210 */ 155, 232, 132, 133, 134, 135, 136, 137, 138, 155, - /* 1220 */ 129, 54, 155, 56, 176, 177, 200, 126, 61, 232, - /* 1230 */ 63, 176, 177, 66, 127, 201, 124, 202, 128, 203, - /* 1240 */ 176, 177, 155, 176, 177, 204, 120, 120, 155, 26, - /* 1250 */ 168, 27, 27, 234, 234, 91, 99, 155, 118, 118, - /* 1260 */ 118, 26, 139, 21, 26, 228, 193, 27, 229, 155, - /* 1270 */ 29, 27, 120, 125, 107, 108, 109, 159, 29, 155, - /* 1280 */ 113, 104, 217, 179, 30, 118, 167, 217, 179, 29, - /* 1290 */ 125, 155, 209, 155, 122, 106, 159, 123, 155, 155, - /* 1300 */ 210, 26, 155, 27, 120, 211, 210, 27, 211, 178, - /* 1310 */ 155, 26, 182, 181, 155, 217, 217, 184, 167, 185, - /* 1320 */ 185, 155, 51, 26, 185, 179, 176, 27, 179, 176, - /* 1330 */ 26, 186, 51, 26, 103, 155, 155, 111, 159, 178, - /* 1340 */ 180, 178, 155, 181, 188, 159, 188, 28, 155, 159, - /* 1350 */ 182, 238, 237, 106, 159, 45, 239, 15, 43, 106, - /* 1360 */ 240, 106, 142, 52, 155, 159, 155, 106, 11, 26, - /* 1370 */ 178, 142, 21, 15, 191, 130, 130, 11, 11, 67, - /* 1380 */ 21, 76, 191, 155, 110, 200, 11, 155, 130, 76, - /* 1390 */ 26, 155, 221, 11, 26, 11, 200, 11, 121, 11, - /* 1400 */ 11, 11, 200, 155, 121, 11, 191, 200, 110, 11, - /* 1410 */ 11, 26, 130, 11, 155, 221, 159, 155, 11, 11, - /* 1420 */ 11, 11, 155, 27, 11, 28, 11, 40, 155, 11, - /* 1430 */ 242, 168, 168, 11, 155, 11, 11, 159, 11, 155, - /* 1440 */ 243, 242, 155, 24, 143, 159, 155, 11, 145, 245, - /* 1450 */ 144, 11, 13, 246, 246, 14, + /* 0 */ 16, 216, 146, 218, 219, 21, 146, 23, 68, 69, + /* 10 */ 70, 71, 16, 73, 74, 75, 76, 77, 78, 79, + /* 20 */ 80, 81, 82, 146, 168, 169, 42, 72, 73, 74, + /* 30 */ 75, 76, 77, 78, 79, 80, 81, 82, 216, 217, + /* 40 */ 218, 219, 146, 59, 60, 61, 62, 63, 64, 65, + /* 50 */ 66, 67, 68, 69, 70, 71, 146, 73, 74, 75, + /* 60 */ 76, 77, 78, 79, 80, 81, 82, 16, 146, 43, + /* 70 */ 86, 215, 146, 22, 73, 74, 75, 76, 77, 78, + /* 80 */ 79, 80, 81, 82, 88, 89, 90, 91, 92, 93, + /* 90 */ 94, 95, 22, 42, 168, 169, 146, 46, 102, 138, + /* 100 */ 139, 140, 152, 19, 143, 155, 156, 23, 160, 187, + /* 110 */ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + /* 120 */ 69, 70, 71, 97, 73, 74, 75, 76, 77, 78, + /* 130 */ 79, 80, 81, 82, 16, 146, 157, 58, 20, 160, + /* 140 */ 161, 162, 58, 189, 16, 16, 220, 199, 23, 146, + /* 150 */ 146, 77, 78, 79, 80, 81, 82, 168, 169, 237, + /* 160 */ 42, 77, 78, 149, 216, 86, 218, 219, 146, 90, + /* 170 */ 86, 43, 168, 169, 90, 89, 90, 59, 60, 61, + /* 180 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + /* 190 */ 120, 73, 74, 75, 76, 77, 78, 79, 80, 81, + /* 200 */ 82, 16, 123, 124, 125, 20, 22, 123, 124, 125, + /* 210 */ 207, 86, 87, 88, 146, 23, 91, 92, 93, 90, + /* 220 */ 91, 92, 93, 94, 95, 97, 146, 42, 103, 207, + /* 230 */ 102, 102, 79, 80, 81, 82, 168, 169, 224, 163, + /* 240 */ 164, 165, 228, 177, 59, 60, 61, 62, 63, 64, + /* 250 */ 65, 66, 67, 68, 69, 70, 71, 146, 73, 74, + /* 260 */ 75, 76, 77, 78, 79, 80, 81, 82, 16, 77, + /* 270 */ 78, 177, 88, 12, 23, 91, 92, 93, 86, 87, + /* 280 */ 51, 52, 146, 215, 146, 24, 19, 103, 88, 97, + /* 290 */ 23, 91, 92, 93, 42, 141, 142, 20, 37, 22, + /* 300 */ 39, 147, 226, 103, 168, 169, 168, 169, 154, 154, + /* 310 */ 49, 59, 60, 61, 62, 63, 64, 65, 66, 67, + /* 320 */ 68, 69, 70, 71, 14, 73, 74, 75, 76, 77, + /* 330 */ 78, 79, 80, 81, 82, 20, 146, 86, 87, 146, + /* 340 */ 16, 25, 188, 188, 154, 29, 208, 209, 146, 216, + /* 350 */ 146, 218, 219, 86, 146, 200, 201, 41, 168, 169, + /* 360 */ 205, 20, 154, 53, 113, 55, 42, 213, 44, 236, + /* 370 */ 168, 169, 168, 169, 175, 176, 168, 169, 188, 49, + /* 380 */ 22, 182, 130, 59, 60, 61, 62, 63, 64, 65, + /* 390 */ 66, 67, 68, 69, 70, 71, 188, 73, 74, 75, + /* 400 */ 76, 77, 78, 79, 80, 81, 82, 16, 146, 20, + /* 410 */ 20, 22, 21, 211, 146, 211, 146, 155, 156, 211, + /* 420 */ 105, 23, 107, 108, 20, 223, 22, 223, 98, 99, + /* 430 */ 100, 223, 177, 42, 164, 165, 168, 169, 14, 109, + /* 440 */ 191, 179, 180, 163, 164, 165, 105, 198, 107, 108, + /* 450 */ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + /* 460 */ 69, 70, 71, 12, 73, 74, 75, 76, 77, 78, + /* 470 */ 79, 80, 81, 82, 16, 24, 19, 53, 120, 55, + /* 480 */ 23, 20, 154, 22, 86, 87, 200, 201, 37, 23, + /* 490 */ 39, 223, 166, 167, 42, 105, 226, 107, 108, 19, + /* 500 */ 42, 175, 105, 23, 107, 108, 226, 160, 161, 162, + /* 510 */ 21, 113, 23, 16, 62, 63, 188, 59, 60, 61, + /* 520 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + /* 530 */ 22, 73, 74, 75, 76, 77, 78, 79, 80, 81, + /* 540 */ 82, 213, 90, 86, 87, 79, 16, 146, 19, 146, + /* 550 */ 20, 146, 86, 87, 146, 146, 132, 229, 129, 146, + /* 560 */ 131, 146, 234, 146, 155, 156, 86, 87, 154, 168, + /* 570 */ 169, 23, 42, 168, 169, 86, 168, 169, 0, 1, + /* 580 */ 2, 168, 169, 168, 169, 168, 169, 90, 130, 59, + /* 590 */ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + /* 600 */ 70, 71, 188, 73, 74, 75, 76, 77, 78, 79, + /* 610 */ 80, 81, 82, 16, 209, 146, 90, 230, 21, 146, + /* 620 */ 112, 154, 146, 22, 146, 27, 231, 213, 102, 146, + /* 630 */ 30, 146, 34, 140, 86, 87, 143, 168, 169, 42, + /* 640 */ 111, 168, 169, 229, 168, 169, 168, 169, 234, 154, + /* 650 */ 50, 168, 169, 168, 169, 188, 59, 60, 61, 62, + /* 660 */ 63, 64, 65, 66, 67, 68, 69, 70, 71, 146, + /* 670 */ 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + /* 680 */ 16, 146, 146, 188, 20, 146, 106, 146, 87, 146, + /* 690 */ 110, 168, 169, 146, 98, 99, 100, 146, 20, 146, + /* 700 */ 22, 101, 19, 168, 169, 167, 42, 168, 169, 168, + /* 710 */ 169, 168, 169, 175, 113, 168, 169, 181, 160, 168, + /* 720 */ 169, 168, 169, 59, 60, 61, 62, 63, 64, 65, + /* 730 */ 66, 67, 68, 69, 70, 71, 146, 73, 74, 75, + /* 740 */ 76, 77, 78, 79, 80, 81, 82, 16, 146, 146, + /* 750 */ 67, 146, 146, 20, 146, 22, 146, 199, 168, 169, + /* 760 */ 146, 225, 146, 123, 124, 146, 7, 8, 9, 202, + /* 770 */ 168, 169, 146, 42, 168, 169, 168, 169, 168, 169, + /* 780 */ 146, 18, 168, 169, 168, 169, 181, 168, 169, 79, + /* 790 */ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, + /* 800 */ 69, 70, 71, 146, 73, 74, 75, 76, 77, 78, + /* 810 */ 79, 80, 81, 82, 16, 146, 106, 146, 22, 146, + /* 820 */ 110, 146, 19, 146, 21, 168, 169, 146, 146, 190, + /* 830 */ 225, 146, 98, 99, 100, 109, 146, 168, 169, 146, + /* 840 */ 42, 168, 169, 168, 169, 168, 169, 146, 122, 168, + /* 850 */ 169, 225, 181, 168, 169, 92, 154, 59, 60, 61, + /* 860 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + /* 870 */ 146, 73, 74, 75, 76, 77, 78, 79, 80, 81, + /* 880 */ 82, 16, 146, 20, 154, 22, 146, 109, 146, 154, + /* 890 */ 188, 146, 96, 146, 212, 132, 225, 207, 160, 146, + /* 900 */ 122, 184, 185, 184, 185, 181, 146, 42, 168, 169, + /* 910 */ 168, 169, 146, 146, 146, 146, 146, 181, 188, 146, + /* 920 */ 146, 146, 146, 188, 16, 60, 61, 62, 63, 64, + /* 930 */ 65, 66, 67, 68, 69, 70, 71, 199, 73, 74, + /* 940 */ 75, 76, 77, 78, 79, 80, 81, 82, 23, 225, + /* 950 */ 42, 146, 146, 187, 187, 187, 187, 212, 159, 227, + /* 960 */ 187, 225, 187, 187, 20, 171, 22, 168, 146, 61, + /* 970 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, + /* 980 */ 146, 73, 74, 75, 76, 77, 78, 79, 80, 81, + /* 990 */ 82, 16, 17, 187, 19, 7, 8, 20, 23, 22, + /* 1000 */ 20, 171, 22, 77, 78, 160, 31, 16, 17, 227, + /* 1010 */ 19, 86, 172, 20, 23, 22, 1, 2, 171, 146, + /* 1020 */ 192, 146, 31, 48, 171, 146, 190, 144, 148, 171, + /* 1030 */ 146, 146, 193, 58, 146, 222, 146, 176, 146, 48, + /* 1040 */ 120, 193, 193, 59, 15, 183, 186, 111, 151, 58, + /* 1050 */ 186, 6, 77, 78, 145, 19, 129, 186, 221, 193, + /* 1060 */ 85, 86, 87, 151, 173, 90, 95, 210, 77, 78, + /* 1070 */ 79, 40, 178, 145, 23, 159, 85, 86, 87, 16, + /* 1080 */ 17, 90, 19, 145, 109, 151, 23, 15, 210, 150, + /* 1090 */ 197, 119, 173, 19, 31, 214, 159, 136, 123, 124, + /* 1100 */ 125, 126, 127, 128, 97, 238, 193, 117, 210, 194, + /* 1110 */ 170, 48, 170, 151, 123, 124, 125, 126, 127, 128, + /* 1120 */ 118, 58, 5, 170, 195, 22, 153, 10, 11, 12, + /* 1130 */ 13, 115, 214, 170, 170, 33, 151, 196, 235, 150, + /* 1140 */ 77, 78, 38, 26, 170, 28, 151, 151, 85, 86, + /* 1150 */ 87, 183, 35, 90, 232, 97, 114, 203, 210, 204, + /* 1160 */ 96, 129, 170, 233, 47, 145, 49, 235, 151, 172, + /* 1170 */ 170, 54, 178, 56, 204, 151, 151, 109, 135, 203, + /* 1180 */ 174, 183, 134, 174, 57, 158, 123, 124, 125, 126, + /* 1190 */ 127, 128, 188, 19, 102, 146, 146, 14, 185, 1, + /* 1200 */ 90, 19, 180, 168, 20, 20, 20, 106, 180, 168, + /* 1210 */ 19, 44, 20, 19, 44, 98, 99, 100, 19, 121, + /* 1220 */ 4, 104, 19, 111, 3, 19, 109, 121, 82, 111, + /* 1230 */ 11, 16, 146, 97, 17, 101, 112, 44, 20, 19, + /* 1240 */ 5, 19, 111, 20, 17, 21, 132, 22, 20, 45, + /* 1250 */ 133, 22, 11, 116, 22, 111, 1, 112, 32, 45, + /* 1260 */ 111, 101, 20, 19, 116, 97, 36, 19, 22, 67, + /* 1270 */ 19, 113, 67, 20, 94, }; -#define YY_SHIFT_USE_DFLT (-75) +#define YY_SHIFT_USE_DFLT (-61) +#define YY_SHIFT_MAX 371 static const short yy_shift_ofst[] = { - /* 0 */ 205, 7, -75, -75, 1167, -10, 57, -75, 47, 475, - /* 10 */ 399, 123, 337, -75, -75, -75, -75, -75, -75, 475, - /* 20 */ 446, 475, 543, 475, 757, 456, 858, 453, 240, 799, - /* 30 */ 865, 50, -75, 254, -75, -16, -75, 453, 151, -75, - /* 40 */ 931, -75, 1004, 306, -75, -75, -75, -75, -75, -75, - /* 50 */ -75, 180, 931, -75, 1045, -75, 278, -75, -75, 1014, - /* 60 */ 689, 931, 1038, -75, -75, -75, -75, 931, -75, 1122, - /* 70 */ 1080, 652, 473, -75, -75, 1080, 1051, 1052, -75, 934, - /* 80 */ -75, 302, 1079, -75, 650, -75, 641, 1091, 1101, 1107, - /* 90 */ 1112, 1110, -75, 1080, 40, 1080, 714, 1080, -75, 1126, - /* 100 */ 453, 1127, 453, -75, -75, -75, -75, -75, -75, 1223, - /* 110 */ 1080, 108, 254, -75, -75, 455, 321, 595, -75, 321, - /* 120 */ 1224, -75, -75, -75, 638, -75, -75, -75, 638, -75, - /* 130 */ -75, -75, -75, 1225, -75, 1080, -75, 814, 1080, -12, - /* 140 */ 1080, -12, 1080, -12, 1080, -12, 1080, -74, 1080, -74, - /* 150 */ 1080, -53, 1080, -53, 1080, -53, 1080, -53, 1080, 242, - /* 160 */ 1080, 242, 1080, 1164, 1080, 1164, 1080, 1164, 1080, -75, - /* 170 */ -75, 298, -75, -75, -75, -75, 1080, -59, 1080, -12, - /* 180 */ -75, 893, -75, 1157, -75, -75, -75, 1080, 764, 1080, - /* 190 */ -74, -75, 325, 934, 359, 419, 1140, 1141, 1142, -75, - /* 200 */ 714, 1080, 864, 1080, -75, 1080, -75, 1080, -75, 1235, - /* 210 */ 1079, 376, -75, 945, 158, 1123, 320, 1242, -75, 1080, - /* 220 */ 231, 1080, 714, 1238, 443, 1240, -75, 1241, 453, 1244, - /* 230 */ -75, 1080, 305, 1080, 355, 1080, 714, 780, -75, 1080, - /* 240 */ -75, -75, 1152, 453, -75, -75, -75, 864, 1080, 714, - /* 250 */ 1148, 1080, 1249, 1080, 1177, 689, -75, 1254, -75, -75, - /* 260 */ 714, 1177, 689, -75, 1080, 714, 1165, 1080, 1260, 1080, - /* 270 */ 714, -75, -75, 239, -75, -75, -75, 430, -75, 433, - /* 280 */ -75, 1172, -75, 501, 1152, 144, 453, -75, -75, 1189, - /* 290 */ 1174, -75, 1275, 453, 783, -75, 453, -75, -75, 1080, - /* 300 */ 714, 1079, 422, 425, 1276, 144, 1189, 1174, -75, 1021, - /* 310 */ -28, -75, -75, 1184, 73, -75, -75, 429, -75, 792, - /* 320 */ -75, 1280, -75, 496, 931, -75, 453, 1285, -75, 42, - /* 330 */ -75, 453, -75, 550, 928, -75, 716, -75, -75, -75, - /* 340 */ -75, 928, -75, 928, -75, 453, 793, -75, 453, 1177, - /* 350 */ 689, -75, -75, 1177, 689, -75, -75, 1254, -75, 1045, - /* 360 */ -75, -75, 68, -75, 1080, 564, -75, 191, -75, -75, - /* 370 */ 191, -75, -75, -75, -75, 176, 256, -75, 453, -75, - /* 380 */ 1271, 1297, 453, 260, 1300, 931, -75, 1304, 453, 796, - /* 390 */ 931, -75, 1080, 614, -75, 1281, 1307, 453, 833, 1231, - /* 400 */ 453, 1285, -75, 493, 1226, -75, -75, -75, -75, -75, - /* 410 */ 1079, 513, 856, 391, 453, 1152, -75, 453, 745, 1319, - /* 420 */ 1079, 548, 453, 1152, 510, 565, 1247, 453, 1152, -75, - /* 430 */ 1310, 297, 1342, 1080, 664, 1315, 813, -75, -75, 1253, - /* 440 */ 1255, 809, 453, 882, -75, -75, 1311, -75, -75, 1220, - /* 450 */ 453, 862, 1261, 453, 1343, 453, 892, 907, 1357, 1229, - /* 460 */ 1358, 152, 592, 894, 306, -75, 1245, 1246, 1351, 1366, - /* 470 */ 1367, 152, 1359, 1312, 453, 1274, 453, 746, 453, 1305, - /* 480 */ 1080, 714, 1375, 1313, 1080, 714, 1258, 453, 1364, 453, - /* 490 */ 947, -75, 917, 598, 1368, 1080, 1033, 1080, 714, 1382, - /* 500 */ 714, 1277, 453, 9, 1384, 470, 453, 1386, 453, 1388, - /* 510 */ 453, 1389, 453, 1390, 605, 1283, 453, 9, 1394, 1312, - /* 520 */ 453, 1298, 453, 746, 1398, 1282, 453, 1364, 1010, 610, - /* 530 */ 1385, 1080, 1092, 1399, 530, 1402, 453, 1152, 649, 179, - /* 540 */ 1407, 1408, 1409, 1410, 453, 1396, 1413, 1387, 254, 1397, - /* 550 */ 453, 1154, 1415, 778, 1418, 1422, -75, 1387, 453, 1424, - /* 560 */ 665, 982, 1425, 734, 982, 1427, 1419, 453, 955, 1301, - /* 570 */ 453, 1436, 1306, 1303, 453, 1440, -75, 1439, 1441, -75, - /* 580 */ -75, + /* 0 */ 1015, 975, 1117, -16, 975, 1063, 1063, 1063, 125, 330, + /* 10 */ 330, 1068, 324, 1063, 1063, 1063, 1063, 1063, -45, 192, + /* 20 */ 548, 926, 925, 926, 51, 391, 118, 185, 252, 458, + /* 30 */ 530, 597, 664, 731, 731, 731, 731, 731, 731, 731, + /* 40 */ 731, 731, 798, 731, 731, 731, 731, 731, 731, 731, + /* 50 */ 731, 731, 865, 908, 908, 991, 1063, 1063, 1063, 1063, + /* 60 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 70 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 80 */ 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, 1063, + /* 90 */ 1063, 1063, 1063, 1063, -60, -60, -4, 1, 1, 74, + /* 100 */ 153, 128, 763, 548, 548, 548, 548, 548, 548, 548, + /* 110 */ 925, 1146, -61, -61, -61, 84, 129, 261, 261, 548, + /* 120 */ 548, 548, 548, 548, 548, 548, 548, 548, 578, 548, + /* 130 */ 548, 548, 548, 489, 548, 489, 778, 726, 1068, 1068, + /* 140 */ 1068, -61, -61, 79, 184, 79, 200, 390, 341, 315, + /* 150 */ 480, 451, 251, 398, 466, 457, 548, 548, 548, 548, + /* 160 */ 759, 548, 548, 548, 601, 267, 548, 548, 548, 397, + /* 170 */ 548, 548, 710, 397, 596, 397, 601, 397, 316, 548, + /* 180 */ 600, 600, 397, 548, 548, 548, 548, 548, 548, 548, + /* 190 */ 600, 397, 548, 548, 397, 548, 548, 548, 548, 548, + /* 200 */ 640, 598, 640, 598, 796, 598, 508, 598, 580, 803, + /* 210 */ 598, 70, 429, 26, 358, 920, 984, 1029, 1029, 936, + /* 220 */ 1045, 920, 1036, 927, 1029, 936, 971, 1045, 1031, 1051, + /* 230 */ 1045, 936, 1072, 971, 972, 1036, 1051, 1074, 961, 1007, + /* 240 */ 920, 1007, 971, 990, 936, 1002, 1007, 1103, 1016, 1074, + /* 250 */ 1007, 1007, 936, 1072, 1102, 936, 1104, 984, 936, 1007, + /* 260 */ 1058, 1042, 971, 1032, 1007, 1064, 1045, 1102, 936, 1007, + /* 270 */ 1031, 984, 1042, 936, 1058, 936, 1068, -61, -61, -61, + /* 280 */ 424, 452, 310, 734, 277, 683, 389, 86, 526, 529, + /* 290 */ 404, 461, 678, 733, 863, 497, 944, 988, 977, 980, + /* 300 */ 993, 229, 1136, 1193, 1222, 1223, 1235, 1131, 1114, 1204, + /* 310 */ 1229, 1241, 1226, 1255, 1214, 1242, 1160, 1230, 1248, 1202, + /* 320 */ 1205, 1253, 1158, 1251, 1246, 1168, 1148, 1244, 1149, 1145, + /* 330 */ 1144, 1232, 1137, 1227, 1228, 1225, 1224, 1124, 1218, 1220, + /* 340 */ 1134, 1217, 1215, 1219, 1118, 1206, 1112, 1216, 1098, 1199, + /* 350 */ 1170, 1194, 1191, 1101, 1186, 1185, 1184, 1182, 1110, 1198, + /* 360 */ 1183, 1092, 1174, 1127, 1048, 1043, 1192, 1167, 1203, 1221, + /* 370 */ 1106, 1180, }; -#define YY_REDUCE_USE_DFLT (-61) +#define YY_REDUCE_USE_DFLT (-216) +#define YY_REDUCE_MAX 279 static const short yy_reduce_ofst[] = { - /* 0 */ -48, 61, -61, -61, -60, -61, -61, -61, -32, 12, - /* 10 */ -61, 181, -61, -61, -61, -61, -61, -61, -61, 314, - /* 20 */ -61, 386, -61, 622, -61, 654, -61, 51, 798, -61, - /* 30 */ -61, -23, -61, -26, 760, 89, -61, 860, 486, -61, - /* 40 */ 867, -61, -61, 65, -61, -61, -61, -61, -61, -61, - /* 50 */ -61, -61, 909, -61, 910, -61, -61, -61, -61, -61, - /* 60 */ 914, 962, 964, -61, -61, -61, -61, 968, -61, -61, - /* 70 */ 438, -61, 996, -61, -61, 116, -61, -61, -61, 293, - /* 80 */ -61, 1000, 1006, -61, 1011, 569, 1005, 1026, 1034, 1035, - /* 90 */ 1036, 1041, -61, 490, 394, 552, 394, 601, -61, -61, - /* 100 */ 1087, -61, 1093, -61, -61, -61, -61, -61, -61, -61, - /* 110 */ 603, 394, 53, -61, -61, 1082, 110, -61, -61, 229, - /* 120 */ -61, -61, -61, -61, 1019, -61, -61, -61, 1020, -61, - /* 130 */ -61, -61, -61, -61, -61, 640, -61, 394, 651, 394, - /* 140 */ 690, 394, 701, 394, 703, 394, 740, 394, 751, 394, - /* 150 */ 753, 394, 755, 394, 790, 394, 801, 394, 803, 394, - /* 160 */ 818, 394, 829, 394, 831, 394, 835, 394, 841, 394, - /* 170 */ -61, -61, -61, -61, -61, -61, 846, 188, 849, 394, - /* 180 */ -61, -61, -61, -61, -61, -61, -61, 879, 394, 881, - /* 190 */ 394, -61, 1102, -6, 1000, -61, -61, -61, -61, -61, - /* 200 */ 394, 887, 394, 898, 394, 918, 394, 936, 394, -61, - /* 210 */ 662, 1000, -61, 295, 394, 1037, 1039, -61, -61, 946, - /* 220 */ 394, 948, 394, -61, 1073, -61, -61, -61, 1114, -61, - /* 230 */ -61, 950, 394, 956, 394, 974, 394, -61, -61, 303, - /* 240 */ -61, -61, 1118, 1124, -61, -61, -61, 394, 984, 394, - /* 250 */ -61, 183, -61, 190, 1065, 1104, -61, 1119, -61, -61, - /* 260 */ 394, 1070, 1109, -61, 987, 394, -61, 187, -61, 1007, - /* 270 */ 394, -61, 398, 1083, -61, -61, -61, 1136, -61, 1138, - /* 280 */ -61, -61, -61, 1143, 1137, 389, 1144, -61, -61, 1090, - /* 290 */ 1094, -61, -61, 604, -61, -61, 1147, -61, -61, 1015, - /* 300 */ 394, 132, 1000, 1083, -61, 512, 1096, 1097, -61, 1018, - /* 310 */ 241, -61, -61, -61, 1087, -61, -61, 394, -61, -61, - /* 320 */ -61, -61, -61, 394, 1131, -61, 1155, 1132, 1130, 1133, - /* 330 */ -61, 1159, -61, -61, 1134, -61, -61, -61, -61, -61, - /* 340 */ -61, 1135, -61, 1139, -61, 439, -61, -61, 765, 1098, - /* 350 */ 1146, -61, -61, 1099, 1149, -61, -61, 1151, -61, 1145, - /* 360 */ -61, -61, 692, -61, 1022, 394, -61, 1150, -61, -61, - /* 370 */ 1153, -61, -61, -61, -61, 1156, 1158, -61, 1166, -61, - /* 380 */ -61, -61, 899, 1160, -61, 1161, -61, -61, 949, -61, - /* 390 */ 1163, -61, 1030, 375, -61, -61, -61, 979, -61, -61, - /* 400 */ 1180, 1162, 1168, 527, -61, -61, -61, -61, -61, -61, - /* 410 */ 712, 1000, 756, -61, 1181, 1179, -61, 1187, 1186, -61, - /* 420 */ 807, 1000, 1193, 1190, 1115, 1113, -61, 715, 1195, -61, - /* 430 */ 1117, 1120, -61, 1048, 394, -61, -61, -61, -61, -61, - /* 440 */ -61, -61, 709, -61, -61, -61, -61, -61, -61, -61, - /* 450 */ 1209, 1206, -61, 1211, -61, 997, -61, 1192, -61, -61, - /* 460 */ -61, 315, 1000, 1183, 732, -61, -61, -61, -61, -61, - /* 470 */ -61, 382, -61, 1191, 1228, -61, 808, 1185, 1232, -61, - /* 480 */ 1055, 394, -61, -61, 1064, 394, -61, 1236, 1171, 767, - /* 490 */ -61, -61, 854, 1000, -61, -18, -61, 1067, 394, -61, - /* 500 */ 394, -61, 1248, 1196, -61, -61, 815, -61, 891, -61, - /* 510 */ 895, -61, 906, -61, 1000, -61, 942, 1202, -61, 1215, - /* 520 */ 943, -61, 959, 1207, -61, -61, 975, 1194, 985, 1000, - /* 530 */ -61, 434, -61, -61, 1259, -61, 1262, 1257, -61, 435, - /* 540 */ -61, -61, -61, -61, 1267, -61, -61, 1188, 1263, -61, - /* 550 */ 1273, 1197, -61, 1264, -61, -61, -61, 1199, 1279, -61, - /* 560 */ 1284, 1278, -61, 1287, 1286, -61, -61, 522, -61, -61, - /* 570 */ 1291, -61, -61, 1204, -58, -61, -61, -61, -61, -61, - /* 580 */ -61, + /* 0 */ -39, 208, 154, -52, 190, 138, 202, 204, 262, 328, + /* 10 */ 414, 155, 133, 68, 268, 405, -144, -74, -178, 270, + /* 20 */ -50, 76, -21, 280, -215, -215, -215, -215, -215, -215, + /* 30 */ -215, -215, -215, -215, -215, -215, -215, -215, -215, -215, + /* 40 */ -215, -215, -215, -215, -215, -215, -215, -215, -215, -215, + /* 50 */ -215, -215, -215, -215, -215, 610, 606, 590, 551, 543, + /* 60 */ 539, 523, 483, 476, 469, 415, 408, 136, 740, -11, + /* 70 */ 401, 413, 417, 473, 478, 485, 535, 541, 547, 553, + /* 80 */ 602, 608, 614, 4, 616, 619, 657, 669, 673, 675, + /* 90 */ 677, 681, 742, 685, -215, -215, 326, -215, -215, -215, + /* 100 */ -215, 199, 14, 536, 605, -78, 409, 671, 724, 736, + /* 110 */ 347, -215, -215, -215, -215, 799, 538, 719, 717, 745, + /* 120 */ 690, 806, 22, 776, 775, 773, 626, 769, 493, 768, + /* 130 */ 767, 682, 766, 738, 3, 558, 735, 730, 702, 495, + /* 140 */ 467, 286, 249, 1041, 1028, 1035, 1022, -46, -46, -46, + /* 150 */ 1086, 1013, 1050, 1049, -123, 892, 890, 888, 885, 884, + /* 160 */ 883, 879, 875, 873, 567, 845, 834, 822, 805, -46, + /* 170 */ 770, 753, 639, -46, 395, -46, 567, -46, 387, 403, + /* 180 */ 94, 66, -46, -104, -140, -123, -90, 80, 111, 193, + /* 190 */ 255, -46, 603, 634, -46, 693, 701, 747, 760, 774, + /* 200 */ 732, 794, 782, 830, 840, 847, 828, 853, 836, 880, + /* 210 */ 858, 839, 813, 861, 848, 849, 862, 860, 864, 897, + /* 220 */ 909, 866, 891, 837, 871, 912, 857, 928, 894, 916, + /* 230 */ 938, 934, 939, 878, 893, 919, 937, 881, 867, 940, + /* 240 */ 913, 942, 898, 915, 962, 929, 953, 973, 941, 918, + /* 250 */ 963, 964, 985, 989, 903, 995, 922, 968, 996, 974, + /* 260 */ 954, 955, 948, 930, 992, 997, 1020, 932, 1017, 1000, + /* 270 */ 994, 998, 970, 1024, 976, 1025, 1004, 1006, 1009, 1027, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 587, 587, 582, 585, 892, 892, 892, 586, 594, 892, - /* 10 */ 892, 892, 892, 614, 615, 616, 595, 596, 597, 892, - /* 20 */ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, - /* 30 */ 892, 892, 607, 617, 627, 609, 626, 892, 892, 628, - /* 40 */ 672, 635, 892, 892, 673, 676, 677, 678, 872, 873, - /* 50 */ 874, 892, 672, 636, 657, 655, 892, 658, 659, 892, - /* 60 */ 728, 672, 643, 637, 644, 726, 727, 672, 638, 892, - /* 70 */ 892, 758, 692, 690, 691, 824, 764, 759, 755, 892, - /* 80 */ 683, 892, 892, 684, 692, 694, 701, 740, 731, 733, - /* 90 */ 721, 735, 689, 892, 736, 892, 737, 892, 757, 892, - /* 100 */ 892, 760, 892, 761, 762, 763, 765, 766, 767, 892, - /* 110 */ 892, 892, 892, 612, 613, 619, 847, 892, 620, 847, - /* 120 */ 892, 621, 624, 625, 892, 842, 844, 845, 892, 843, - /* 130 */ 846, 623, 622, 892, 768, 892, 771, 773, 892, 774, - /* 140 */ 892, 775, 892, 776, 892, 777, 892, 778, 892, 779, - /* 150 */ 892, 780, 892, 781, 892, 782, 892, 783, 892, 784, - /* 160 */ 892, 785, 892, 786, 892, 787, 892, 788, 892, 789, - /* 170 */ 790, 892, 791, 798, 805, 808, 892, 793, 892, 792, - /* 180 */ 795, 892, 796, 892, 799, 797, 804, 892, 892, 892, - /* 190 */ 806, 807, 892, 824, 892, 892, 892, 892, 892, 811, - /* 200 */ 823, 892, 800, 892, 801, 892, 802, 892, 803, 892, - /* 210 */ 892, 892, 813, 892, 892, 892, 892, 892, 814, 892, - /* 220 */ 892, 892, 815, 892, 892, 892, 870, 892, 892, 892, - /* 230 */ 871, 892, 892, 892, 892, 892, 816, 892, 809, 824, - /* 240 */ 821, 822, 709, 892, 710, 812, 794, 772, 892, 738, - /* 250 */ 892, 892, 722, 892, 729, 728, 723, 892, 611, 730, - /* 260 */ 725, 729, 728, 724, 892, 734, 892, 824, 732, 892, - /* 270 */ 741, 693, 704, 702, 703, 712, 713, 892, 714, 892, - /* 280 */ 715, 892, 716, 892, 709, 700, 892, 698, 699, 718, - /* 290 */ 720, 705, 892, 892, 892, 719, 892, 753, 754, 892, - /* 300 */ 717, 704, 892, 892, 892, 700, 718, 720, 706, 892, - /* 310 */ 700, 695, 696, 892, 892, 697, 810, 892, 756, 892, - /* 320 */ 769, 892, 770, 892, 672, 639, 892, 828, 645, 640, - /* 330 */ 646, 892, 647, 892, 892, 648, 892, 651, 652, 653, - /* 340 */ 654, 892, 649, 892, 650, 892, 892, 829, 892, 729, - /* 350 */ 728, 830, 832, 729, 728, 831, 641, 892, 642, 657, - /* 360 */ 656, 629, 892, 630, 892, 892, 631, 892, 632, 764, - /* 370 */ 892, 633, 634, 618, 610, 892, 892, 662, 892, 665, - /* 380 */ 892, 892, 892, 892, 892, 672, 666, 892, 892, 892, - /* 390 */ 672, 667, 892, 672, 668, 892, 892, 892, 892, 892, - /* 400 */ 892, 828, 645, 670, 892, 669, 671, 663, 664, 608, - /* 410 */ 892, 892, 604, 892, 892, 709, 602, 892, 892, 892, - /* 420 */ 892, 892, 892, 709, 853, 892, 892, 892, 709, 711, - /* 430 */ 858, 892, 892, 892, 892, 892, 892, 859, 860, 892, - /* 440 */ 892, 892, 892, 892, 850, 851, 892, 852, 603, 892, - /* 450 */ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, - /* 460 */ 892, 892, 892, 892, 892, 675, 892, 892, 892, 892, - /* 470 */ 892, 892, 892, 674, 892, 892, 892, 892, 892, 892, - /* 480 */ 892, 743, 892, 892, 892, 744, 892, 892, 751, 892, - /* 490 */ 892, 752, 892, 892, 892, 892, 892, 892, 749, 892, - /* 500 */ 750, 892, 892, 892, 892, 892, 892, 892, 892, 892, - /* 510 */ 892, 892, 892, 892, 892, 892, 892, 892, 892, 674, - /* 520 */ 892, 892, 892, 892, 892, 892, 892, 751, 892, 892, - /* 530 */ 892, 892, 892, 892, 892, 892, 892, 709, 892, 847, - /* 540 */ 892, 892, 892, 892, 892, 892, 892, 881, 892, 892, - /* 550 */ 892, 892, 892, 892, 892, 892, 880, 881, 892, 892, - /* 560 */ 892, 892, 892, 892, 892, 892, 892, 892, 892, 892, - /* 570 */ 892, 892, 892, 890, 892, 892, 891, 588, 892, 589, - /* 580 */ 583, + /* 0 */ 567, 791, 856, 682, 856, 856, 791, 791, 856, 829, + /* 10 */ 829, 686, 842, 856, 791, 856, 856, 787, 762, 813, + /* 20 */ 856, 813, 598, 813, 717, 856, 856, 856, 856, 856, + /* 30 */ 856, 856, 856, 724, 782, 784, 846, 783, 718, 719, + /* 40 */ 725, 843, 856, 706, 827, 715, 730, 722, 731, 786, + /* 50 */ 698, 790, 752, 768, 751, 856, 856, 856, 856, 856, + /* 60 */ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, + /* 70 */ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, + /* 80 */ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, + /* 90 */ 856, 856, 856, 856, 773, 754, 591, 761, 753, 755, + /* 100 */ 756, 651, 586, 856, 856, 856, 856, 856, 856, 856, + /* 110 */ 856, 757, 769, 770, 758, 856, 856, 856, 856, 856, + /* 120 */ 856, 856, 856, 856, 856, 856, 856, 856, 567, 856, + /* 130 */ 856, 856, 856, 682, 856, 682, 856, 856, 856, 856, + /* 140 */ 856, 686, 676, 856, 642, 856, 856, 856, 856, 856, + /* 150 */ 856, 856, 856, 856, 856, 856, 572, 856, 856, 856, + /* 160 */ 574, 856, 856, 856, 684, 600, 856, 847, 856, 689, + /* 170 */ 849, 801, 674, 588, 856, 727, 690, 832, 819, 856, + /* 180 */ 856, 856, 834, 856, 856, 856, 856, 856, 856, 856, + /* 190 */ 856, 663, 856, 856, 665, 856, 856, 856, 856, 856, + /* 200 */ 856, 709, 856, 709, 624, 709, 683, 709, 674, 856, + /* 210 */ 709, 721, 785, 621, 721, 721, 655, 662, 662, 691, + /* 220 */ 571, 721, 795, 856, 662, 691, 710, 571, 638, 856, + /* 230 */ 571, 691, 583, 710, 716, 795, 856, 732, 854, 653, + /* 240 */ 721, 653, 710, 712, 691, 714, 653, 641, 702, 732, + /* 250 */ 653, 653, 691, 583, 845, 691, 823, 655, 691, 653, + /* 260 */ 699, 701, 710, 826, 653, 624, 571, 845, 691, 653, + /* 270 */ 638, 655, 701, 691, 699, 691, 856, 626, 626, 608, + /* 280 */ 856, 856, 856, 856, 856, 808, 856, 856, 856, 739, + /* 290 */ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, + /* 300 */ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856, + /* 310 */ 822, 856, 856, 856, 821, 856, 856, 856, 856, 856, + /* 320 */ 856, 856, 856, 856, 713, 856, 856, 856, 744, 856, + /* 330 */ 740, 703, 856, 856, 856, 856, 856, 856, 856, 856, + /* 340 */ 856, 856, 856, 856, 856, 856, 741, 856, 856, 856, + /* 350 */ 856, 856, 856, 668, 856, 856, 856, 856, 856, 856, + /* 360 */ 856, 856, 856, 853, 856, 856, 856, 856, 856, 568, + /* 370 */ 856, 856, 838, 649, 839, 837, 648, 650, 652, 644, + /* 380 */ 645, 590, 647, 617, 659, 646, 750, 592, 599, 582, + /* 390 */ 615, 614, 584, 744, 613, 612, 636, 611, 610, 637, + /* 400 */ 623, 622, 798, 658, 799, 693, 797, 639, 815, 657, + /* 410 */ 654, 796, 640, 824, 825, 820, 631, 630, 635, 816, + /* 420 */ 817, 634, 818, 585, 633, 632, 629, 628, 627, 620, + /* 430 */ 749, 616, 748, 737, 792, 793, 777, 679, 678, 677, + /* 440 */ 609, 656, 728, 729, 688, 814, 618, 625, 828, 707, + /* 450 */ 708, 735, 607, 734, 700, 687, 681, 589, 830, 680, + /* 460 */ 587, 619, 697, 696, 695, 694, 685, 733, 675, 672, + /* 470 */ 673, 581, 705, 711, 580, 831, 593, 704, 736, 666, + /* 480 */ 833, 763, 779, 579, 660, 692, 661, 789, 788, 664, + /* 490 */ 667, 578, 800, 776, 840, 836, 835, 577, 671, 720, + /* 500 */ 738, 576, 781, 575, 780, 723, 742, 597, 743, 745, + /* 510 */ 746, 778, 596, 670, 726, 669, 802, 594, 774, 601, + /* 520 */ 595, 803, 804, 805, 806, 771, 767, 807, 765, 573, + /* 530 */ 764, 570, 602, 841, 605, 566, 844, 606, 775, 564, + /* 540 */ 772, 766, 848, 760, 759, 850, 809, 565, 811, 810, + /* 550 */ 812, 851, 604, 603, 562, 852, 855, 747, 643, 569, + /* 560 */ 563, }; #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0])) /* The next table maps tokens into fallback tokens. If a construct ** like the following: @@ -668,79 +580,70 @@ ** the parse is retried before an error is thrown. */ #ifdef YYFALLBACK static const YYCODETYPE yyFallback[] = { 0, /* $ => nothing */ - 0, /* END_OF_FILE => nothing */ - 0, /* ILLEGAL => nothing */ - 0, /* SPACE => nothing */ - 0, /* UNCLOSED_STRING => nothing */ - 0, /* COMMENT => nothing */ - 0, /* FUNCTION => nothing */ - 0, /* COLUMN => nothing */ - 0, /* AGG_FUNCTION => nothing */ - 0, /* AGG_COLUMN => nothing */ - 0, /* CONST_FUNC => nothing */ 0, /* SEMI => nothing */ - 30, /* EXPLAIN => ID */ - 30, /* QUERY => ID */ - 30, /* PLAN => ID */ - 30, /* BEGIN => ID */ + 23, /* EXPLAIN => ID */ + 23, /* QUERY => ID */ + 23, /* PLAN => ID */ + 23, /* BEGIN => ID */ 0, /* TRANSACTION => nothing */ - 30, /* DEFERRED => ID */ - 30, /* IMMEDIATE => ID */ - 30, /* EXCLUSIVE => ID */ + 23, /* DEFERRED => ID */ + 23, /* IMMEDIATE => ID */ + 23, /* EXCLUSIVE => ID */ 0, /* COMMIT => nothing */ - 30, /* END => ID */ + 23, /* END => ID */ 0, /* ROLLBACK => nothing */ 0, /* CREATE => nothing */ 0, /* TABLE => nothing */ - 30, /* TEMP => ID */ + 23, /* IF => ID */ + 0, /* NOT => nothing */ + 0, /* EXISTS => nothing */ + 23, /* TEMP => ID */ 0, /* LP => nothing */ 0, /* RP => nothing */ 0, /* AS => nothing */ 0, /* COMMA => nothing */ 0, /* ID => nothing */ - 30, /* ABORT => ID */ - 30, /* AFTER => ID */ - 30, /* ANALYZE => ID */ - 30, /* ASC => ID */ - 30, /* ATTACH => ID */ - 30, /* BEFORE => ID */ - 30, /* CASCADE => ID */ - 30, /* CAST => ID */ - 30, /* CONFLICT => ID */ - 30, /* DATABASE => ID */ - 30, /* DESC => ID */ - 30, /* DETACH => ID */ - 30, /* EACH => ID */ - 30, /* FAIL => ID */ - 30, /* FOR => ID */ - 30, /* IGNORE => ID */ - 30, /* INITIALLY => ID */ - 30, /* INSTEAD => ID */ - 30, /* LIKE_KW => ID */ - 30, /* MATCH => ID */ - 30, /* KEY => ID */ - 30, /* OF => ID */ - 30, /* OFFSET => ID */ - 30, /* PRAGMA => ID */ - 30, /* RAISE => ID */ - 30, /* REPLACE => ID */ - 30, /* RESTRICT => ID */ - 30, /* ROW => ID */ - 30, /* STATEMENT => ID */ - 30, /* TRIGGER => ID */ - 30, /* VACUUM => ID */ - 30, /* VIEW => ID */ - 30, /* REINDEX => ID */ - 30, /* RENAME => ID */ - 30, /* CTIME_KW => ID */ - 30, /* ALTER => ID */ + 23, /* ABORT => ID */ + 23, /* AFTER => ID */ + 23, /* ANALYZE => ID */ + 23, /* ASC => ID */ + 23, /* ATTACH => ID */ + 23, /* BEFORE => ID */ + 23, /* CASCADE => ID */ + 23, /* CAST => ID */ + 23, /* CONFLICT => ID */ + 23, /* DATABASE => ID */ + 23, /* DESC => ID */ + 23, /* DETACH => ID */ + 23, /* EACH => ID */ + 23, /* FAIL => ID */ + 23, /* FOR => ID */ + 23, /* IGNORE => ID */ + 23, /* INITIALLY => ID */ + 23, /* INSTEAD => ID */ + 23, /* LIKE_KW => ID */ + 23, /* MATCH => ID */ + 23, /* KEY => ID */ + 23, /* OF => ID */ + 23, /* OFFSET => ID */ + 23, /* PRAGMA => ID */ + 23, /* RAISE => ID */ + 23, /* REPLACE => ID */ + 23, /* RESTRICT => ID */ + 23, /* ROW => ID */ + 23, /* STATEMENT => ID */ + 23, /* TRIGGER => ID */ + 23, /* VACUUM => ID */ + 23, /* VIEW => ID */ + 23, /* REINDEX => ID */ + 23, /* RENAME => ID */ + 23, /* CTIME_KW => ID */ 0, /* OR => nothing */ 0, /* AND => nothing */ - 0, /* NOT => nothing */ 0, /* IS => nothing */ 0, /* BETWEEN => nothing */ 0, /* IN => nothing */ 0, /* ISNULL => nothing */ 0, /* NOTNULL => nothing */ @@ -783,12 +686,12 @@ 0, /* DEFERRABLE => nothing */ 0, /* FOREIGN => nothing */ 0, /* DROP => nothing */ 0, /* UNION => nothing */ 0, /* ALL => nothing */ - 0, /* INTERSECT => nothing */ 0, /* EXCEPT => nothing */ + 0, /* INTERSECT => nothing */ 0, /* SELECT => nothing */ 0, /* DISTINCT => nothing */ 0, /* DOT => nothing */ 0, /* FROM => nothing */ 0, /* JOIN => nothing */ @@ -804,16 +707,16 @@ 0, /* INTEGER => nothing */ 0, /* FLOAT => nothing */ 0, /* BLOB => nothing */ 0, /* REGISTER => nothing */ 0, /* VARIABLE => nothing */ - 0, /* EXISTS => nothing */ 0, /* CASE => nothing */ 0, /* WHEN => nothing */ 0, /* THEN => nothing */ 0, /* ELSE => nothing */ 0, /* INDEX => nothing */ + 0, /* ALTER => nothing */ 0, /* TO => nothing */ 0, /* ADD => nothing */ 0, /* COLUMNKW => nothing */ }; #endif /* YYFALLBACK */ @@ -883,72 +786,70 @@ #ifndef NDEBUG /* For tracing shifts, the names of all terminals and nonterminals ** are required. The following table supplies these names */ static const char *const yyTokenName[] = { - "$", "END_OF_FILE", "ILLEGAL", "SPACE", - "UNCLOSED_STRING", "COMMENT", "FUNCTION", "COLUMN", - "AGG_FUNCTION", "AGG_COLUMN", "CONST_FUNC", "SEMI", - "EXPLAIN", "QUERY", "PLAN", "BEGIN", - "TRANSACTION", "DEFERRED", "IMMEDIATE", "EXCLUSIVE", - "COMMIT", "END", "ROLLBACK", "CREATE", - "TABLE", "TEMP", "LP", "RP", - "AS", "COMMA", "ID", "ABORT", - "AFTER", "ANALYZE", "ASC", "ATTACH", - "BEFORE", "CASCADE", "CAST", "CONFLICT", - "DATABASE", "DESC", "DETACH", "EACH", - "FAIL", "FOR", "IGNORE", "INITIALLY", - "INSTEAD", "LIKE_KW", "MATCH", "KEY", - "OF", "OFFSET", "PRAGMA", "RAISE", - "REPLACE", "RESTRICT", "ROW", "STATEMENT", - "TRIGGER", "VACUUM", "VIEW", "REINDEX", - "RENAME", "CTIME_KW", "ALTER", "OR", - "AND", "NOT", "IS", "BETWEEN", - "IN", "ISNULL", "NOTNULL", "NE", - "EQ", "GT", "LE", "LT", - "GE", "ESCAPE", "BITAND", "BITOR", - "LSHIFT", "RSHIFT", "PLUS", "MINUS", - "STAR", "SLASH", "REM", "CONCAT", - "UMINUS", "UPLUS", "BITNOT", "STRING", - "JOIN_KW", "CONSTRAINT", "DEFAULT", "NULL", - "PRIMARY", "UNIQUE", "CHECK", "REFERENCES", - "COLLATE", "AUTOINCR", "ON", "DELETE", - "UPDATE", "INSERT", "SET", "DEFERRABLE", - "FOREIGN", "DROP", "UNION", "ALL", - "INTERSECT", "EXCEPT", "SELECT", "DISTINCT", - "DOT", "FROM", "JOIN", "USING", - "ORDER", "BY", "GROUP", "HAVING", - "LIMIT", "WHERE", "INTO", "VALUES", - "INTEGER", "FLOAT", "BLOB", "REGISTER", - "VARIABLE", "EXISTS", "CASE", "WHEN", - "THEN", "ELSE", "INDEX", "TO", - "ADD", "COLUMNKW", "error", "input", - "cmdlist", "ecmd", "cmdx", "cmd", - "explain", "transtype", "trans_opt", "nm", - "create_table", "create_table_args", "temp", "dbnm", + "$", "SEMI", "EXPLAIN", "QUERY", + "PLAN", "BEGIN", "TRANSACTION", "DEFERRED", + "IMMEDIATE", "EXCLUSIVE", "COMMIT", "END", + "ROLLBACK", "CREATE", "TABLE", "IF", + "NOT", "EXISTS", "TEMP", "LP", + "RP", "AS", "COMMA", "ID", + "ABORT", "AFTER", "ANALYZE", "ASC", + "ATTACH", "BEFORE", "CASCADE", "CAST", + "CONFLICT", "DATABASE", "DESC", "DETACH", + "EACH", "FAIL", "FOR", "IGNORE", + "INITIALLY", "INSTEAD", "LIKE_KW", "MATCH", + "KEY", "OF", "OFFSET", "PRAGMA", + "RAISE", "REPLACE", "RESTRICT", "ROW", + "STATEMENT", "TRIGGER", "VACUUM", "VIEW", + "REINDEX", "RENAME", "CTIME_KW", "OR", + "AND", "IS", "BETWEEN", "IN", + "ISNULL", "NOTNULL", "NE", "EQ", + "GT", "LE", "LT", "GE", + "ESCAPE", "BITAND", "BITOR", "LSHIFT", + "RSHIFT", "PLUS", "MINUS", "STAR", + "SLASH", "REM", "CONCAT", "UMINUS", + "UPLUS", "BITNOT", "STRING", "JOIN_KW", + "CONSTRAINT", "DEFAULT", "NULL", "PRIMARY", + "UNIQUE", "CHECK", "REFERENCES", "COLLATE", + "AUTOINCR", "ON", "DELETE", "UPDATE", + "INSERT", "SET", "DEFERRABLE", "FOREIGN", + "DROP", "UNION", "ALL", "EXCEPT", + "INTERSECT", "SELECT", "DISTINCT", "DOT", + "FROM", "JOIN", "USING", "ORDER", + "BY", "GROUP", "HAVING", "LIMIT", + "WHERE", "INTO", "VALUES", "INTEGER", + "FLOAT", "BLOB", "REGISTER", "VARIABLE", + "CASE", "WHEN", "THEN", "ELSE", + "INDEX", "ALTER", "TO", "ADD", + "COLUMNKW", "error", "input", "cmdlist", + "ecmd", "cmdx", "cmd", "explain", + "transtype", "trans_opt", "nm", "create_table", + "create_table_args", "temp", "ifnotexists", "dbnm", "columnlist", "conslist_opt", "select", "column", "columnid", "type", "carglist", "id", "ids", "typetoken", "typename", "signed", "plus_num", "minus_num", "carg", "ccons", "term", "expr", "onconf", "sortorder", "autoinc", "idxlist_opt", "refargs", "defer_subclause", "refarg", "refact", "init_deferred_pred_opt", "conslist", "tcons", "idxlist", "defer_subclause_opt", "orconf", - "resolvetype", "raisetype", "fullname", "oneselect", - "multiselect_op", "distinct", "selcollist", "from", - "where_opt", "groupby_opt", "having_opt", "orderby_opt", - "limit_opt", "sclp", "as", "seltablist", - "stl_prefix", "joinop", "on_opt", "using_opt", - "seltablist_paren", "joinop2", "inscollist", "sortlist", - "sortitem", "collate", "exprlist", "setlist", - "insert_cmd", "inscollist_opt", "itemlist", "likeop", - "escape", "between_op", "in_op", "case_operand", - "case_exprlist", "case_else", "expritem", "uniqueflag", - "idxitem", "plus_opt", "number", "trigger_decl", - "trigger_cmd_list", "trigger_time", "trigger_event", "foreach_clause", - "when_clause", "trigger_cmd", "database_kw_opt", "key_opt", - "add_column_fullname", "kwcolumn_opt", + "resolvetype", "raisetype", "ifexists", "fullname", + "oneselect", "multiselect_op", "distinct", "selcollist", + "from", "where_opt", "groupby_opt", "having_opt", + "orderby_opt", "limit_opt", "sclp", "as", + "seltablist", "stl_prefix", "joinop", "on_opt", + "using_opt", "seltablist_paren", "joinop2", "inscollist", + "sortlist", "sortitem", "collate", "exprlist", + "setlist", "insert_cmd", "inscollist_opt", "itemlist", + "likeop", "escape", "between_op", "in_op", + "case_operand", "case_exprlist", "case_else", "expritem", + "uniqueflag", "idxitem", "plus_opt", "number", + "trigger_decl", "trigger_cmd_list", "trigger_time", "trigger_event", + "foreach_clause", "when_clause", "trigger_cmd", "database_kw_opt", + "key_opt", "add_column_fullname", "kwcolumn_opt", }; #endif /* NDEBUG */ #ifndef NDEBUG /* For tracing reduce actions, the names of all rules are required. @@ -973,300 +874,284 @@ /* 16 */ "transtype ::= EXCLUSIVE", /* 17 */ "cmd ::= COMMIT trans_opt", /* 18 */ "cmd ::= END trans_opt", /* 19 */ "cmd ::= ROLLBACK trans_opt", /* 20 */ "cmd ::= create_table create_table_args", - /* 21 */ "create_table ::= CREATE temp TABLE nm dbnm", - /* 22 */ "temp ::= TEMP", - /* 23 */ "temp ::=", - /* 24 */ "create_table_args ::= LP columnlist conslist_opt RP", - /* 25 */ "create_table_args ::= AS select", - /* 26 */ "columnlist ::= columnlist COMMA column", - /* 27 */ "columnlist ::= column", - /* 28 */ "column ::= columnid type carglist", - /* 29 */ "columnid ::= nm", - /* 30 */ "id ::= ID", - /* 31 */ "ids ::= ID", - /* 32 */ "ids ::= STRING", - /* 33 */ "nm ::= ID", - /* 34 */ "nm ::= STRING", - /* 35 */ "nm ::= JOIN_KW", - /* 36 */ "type ::=", - /* 37 */ "type ::= typetoken", - /* 38 */ "typetoken ::= typename", - /* 39 */ "typetoken ::= typename LP signed RP", - /* 40 */ "typetoken ::= typename LP signed COMMA signed RP", - /* 41 */ "typename ::= ids", - /* 42 */ "typename ::= typename ids", - /* 43 */ "signed ::= plus_num", - /* 44 */ "signed ::= minus_num", - /* 45 */ "carglist ::= carglist carg", - /* 46 */ "carglist ::=", - /* 47 */ "carg ::= CONSTRAINT nm ccons", - /* 48 */ "carg ::= ccons", - /* 49 */ "carg ::= DEFAULT term", - /* 50 */ "carg ::= DEFAULT LP expr RP", - /* 51 */ "carg ::= DEFAULT PLUS term", - /* 52 */ "carg ::= DEFAULT MINUS term", - /* 53 */ "carg ::= DEFAULT id", - /* 54 */ "ccons ::= NULL onconf", - /* 55 */ "ccons ::= NOT NULL onconf", - /* 56 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", - /* 57 */ "ccons ::= UNIQUE onconf", - /* 58 */ "ccons ::= CHECK LP expr RP onconf", - /* 59 */ "ccons ::= REFERENCES nm idxlist_opt refargs", - /* 60 */ "ccons ::= defer_subclause", - /* 61 */ "ccons ::= COLLATE id", - /* 62 */ "autoinc ::=", - /* 63 */ "autoinc ::= AUTOINCR", - /* 64 */ "refargs ::=", - /* 65 */ "refargs ::= refargs refarg", - /* 66 */ "refarg ::= MATCH nm", - /* 67 */ "refarg ::= ON DELETE refact", - /* 68 */ "refarg ::= ON UPDATE refact", - /* 69 */ "refarg ::= ON INSERT refact", - /* 70 */ "refact ::= SET NULL", - /* 71 */ "refact ::= SET DEFAULT", - /* 72 */ "refact ::= CASCADE", - /* 73 */ "refact ::= RESTRICT", - /* 74 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", - /* 75 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", - /* 76 */ "init_deferred_pred_opt ::=", - /* 77 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", - /* 78 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", - /* 79 */ "conslist_opt ::=", - /* 80 */ "conslist_opt ::= COMMA conslist", - /* 81 */ "conslist ::= conslist COMMA tcons", - /* 82 */ "conslist ::= conslist tcons", - /* 83 */ "conslist ::= tcons", - /* 84 */ "tcons ::= CONSTRAINT nm", - /* 85 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf", - /* 86 */ "tcons ::= UNIQUE LP idxlist RP onconf", - /* 87 */ "tcons ::= CHECK expr onconf", - /* 88 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt", - /* 89 */ "defer_subclause_opt ::=", - /* 90 */ "defer_subclause_opt ::= defer_subclause", - /* 91 */ "onconf ::=", - /* 92 */ "onconf ::= ON CONFLICT resolvetype", - /* 93 */ "orconf ::=", - /* 94 */ "orconf ::= OR resolvetype", - /* 95 */ "resolvetype ::= raisetype", - /* 96 */ "resolvetype ::= IGNORE", - /* 97 */ "resolvetype ::= REPLACE", - /* 98 */ "cmd ::= DROP TABLE fullname", - /* 99 */ "cmd ::= CREATE temp VIEW nm dbnm AS select", - /* 100 */ "cmd ::= DROP VIEW fullname", - /* 101 */ "cmd ::= select", - /* 102 */ "select ::= oneselect", - /* 103 */ "select ::= select multiselect_op oneselect", - /* 104 */ "multiselect_op ::= UNION", - /* 105 */ "multiselect_op ::= UNION ALL", - /* 106 */ "multiselect_op ::= INTERSECT", - /* 107 */ "multiselect_op ::= EXCEPT", - /* 108 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", - /* 109 */ "distinct ::= DISTINCT", - /* 110 */ "distinct ::= ALL", - /* 111 */ "distinct ::=", - /* 112 */ "sclp ::= selcollist COMMA", - /* 113 */ "sclp ::=", - /* 114 */ "selcollist ::= sclp expr as", - /* 115 */ "selcollist ::= sclp STAR", - /* 116 */ "selcollist ::= sclp nm DOT STAR", - /* 117 */ "as ::= AS nm", - /* 118 */ "as ::= ids", - /* 119 */ "as ::=", - /* 120 */ "from ::=", - /* 121 */ "from ::= FROM seltablist", - /* 122 */ "stl_prefix ::= seltablist joinop", - /* 123 */ "stl_prefix ::=", - /* 124 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt", - /* 125 */ "seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt", - /* 126 */ "seltablist_paren ::= select", - /* 127 */ "seltablist_paren ::= seltablist", - /* 128 */ "dbnm ::=", - /* 129 */ "dbnm ::= DOT nm", - /* 130 */ "fullname ::= nm dbnm", - /* 131 */ "joinop ::= COMMA", - /* 132 */ "joinop ::= JOIN", - /* 133 */ "joinop ::= JOIN_KW JOIN", - /* 134 */ "joinop ::= JOIN_KW nm JOIN", - /* 135 */ "joinop ::= JOIN_KW nm nm JOIN", - /* 136 */ "on_opt ::= ON expr", - /* 137 */ "on_opt ::=", - /* 138 */ "using_opt ::= USING LP inscollist RP", - /* 139 */ "using_opt ::=", - /* 140 */ "orderby_opt ::=", - /* 141 */ "orderby_opt ::= ORDER BY sortlist", - /* 142 */ "sortlist ::= sortlist COMMA sortitem collate sortorder", - /* 143 */ "sortlist ::= sortitem collate sortorder", - /* 144 */ "sortitem ::= expr", - /* 145 */ "sortorder ::= ASC", - /* 146 */ "sortorder ::= DESC", - /* 147 */ "sortorder ::=", - /* 148 */ "collate ::=", - /* 149 */ "collate ::= COLLATE id", - /* 150 */ "groupby_opt ::=", - /* 151 */ "groupby_opt ::= GROUP BY exprlist", - /* 152 */ "having_opt ::=", - /* 153 */ "having_opt ::= HAVING expr", - /* 154 */ "limit_opt ::=", - /* 155 */ "limit_opt ::= LIMIT expr", - /* 156 */ "limit_opt ::= LIMIT expr OFFSET expr", - /* 157 */ "limit_opt ::= LIMIT expr COMMA expr", - /* 158 */ "cmd ::= DELETE FROM fullname where_opt", - /* 159 */ "where_opt ::=", - /* 160 */ "where_opt ::= WHERE expr", - /* 161 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt", - /* 162 */ "setlist ::= setlist COMMA nm EQ expr", - /* 163 */ "setlist ::= nm EQ expr", - /* 164 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP", - /* 165 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select", - /* 166 */ "insert_cmd ::= INSERT orconf", - /* 167 */ "insert_cmd ::= REPLACE", - /* 168 */ "itemlist ::= itemlist COMMA expr", - /* 169 */ "itemlist ::= expr", - /* 170 */ "inscollist_opt ::=", - /* 171 */ "inscollist_opt ::= LP inscollist RP", - /* 172 */ "inscollist ::= inscollist COMMA nm", - /* 173 */ "inscollist ::= nm", - /* 174 */ "expr ::= term", - /* 175 */ "expr ::= LP expr RP", - /* 176 */ "term ::= NULL", - /* 177 */ "expr ::= ID", - /* 178 */ "expr ::= JOIN_KW", - /* 179 */ "expr ::= nm DOT nm", - /* 180 */ "expr ::= nm DOT nm DOT nm", - /* 181 */ "term ::= INTEGER", - /* 182 */ "term ::= FLOAT", + /* 21 */ "create_table ::= CREATE temp TABLE ifnotexists nm dbnm", + /* 22 */ "ifnotexists ::=", + /* 23 */ "ifnotexists ::= IF NOT EXISTS", + /* 24 */ "temp ::= TEMP", + /* 25 */ "temp ::=", + /* 26 */ "create_table_args ::= LP columnlist conslist_opt RP", + /* 27 */ "create_table_args ::= AS select", + /* 28 */ "columnlist ::= columnlist COMMA column", + /* 29 */ "columnlist ::= column", + /* 30 */ "column ::= columnid type carglist", + /* 31 */ "columnid ::= nm", + /* 32 */ "id ::= ID", + /* 33 */ "ids ::= ID|STRING", + /* 34 */ "nm ::= ID", + /* 35 */ "nm ::= STRING", + /* 36 */ "nm ::= JOIN_KW", + /* 37 */ "type ::=", + /* 38 */ "type ::= typetoken", + /* 39 */ "typetoken ::= typename", + /* 40 */ "typetoken ::= typename LP signed RP", + /* 41 */ "typetoken ::= typename LP signed COMMA signed RP", + /* 42 */ "typename ::= ids", + /* 43 */ "typename ::= typename ids", + /* 44 */ "signed ::= plus_num", + /* 45 */ "signed ::= minus_num", + /* 46 */ "carglist ::= carglist carg", + /* 47 */ "carglist ::=", + /* 48 */ "carg ::= CONSTRAINT nm ccons", + /* 49 */ "carg ::= ccons", + /* 50 */ "carg ::= DEFAULT term", + /* 51 */ "carg ::= DEFAULT LP expr RP", + /* 52 */ "carg ::= DEFAULT PLUS term", + /* 53 */ "carg ::= DEFAULT MINUS term", + /* 54 */ "carg ::= DEFAULT id", + /* 55 */ "ccons ::= NULL onconf", + /* 56 */ "ccons ::= NOT NULL onconf", + /* 57 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc", + /* 58 */ "ccons ::= UNIQUE onconf", + /* 59 */ "ccons ::= CHECK LP expr RP", + /* 60 */ "ccons ::= REFERENCES nm idxlist_opt refargs", + /* 61 */ "ccons ::= defer_subclause", + /* 62 */ "ccons ::= COLLATE id", + /* 63 */ "autoinc ::=", + /* 64 */ "autoinc ::= AUTOINCR", + /* 65 */ "refargs ::=", + /* 66 */ "refargs ::= refargs refarg", + /* 67 */ "refarg ::= MATCH nm", + /* 68 */ "refarg ::= ON DELETE refact", + /* 69 */ "refarg ::= ON UPDATE refact", + /* 70 */ "refarg ::= ON INSERT refact", + /* 71 */ "refact ::= SET NULL", + /* 72 */ "refact ::= SET DEFAULT", + /* 73 */ "refact ::= CASCADE", + /* 74 */ "refact ::= RESTRICT", + /* 75 */ "defer_subclause ::= NOT DEFERRABLE init_deferred_pred_opt", + /* 76 */ "defer_subclause ::= DEFERRABLE init_deferred_pred_opt", + /* 77 */ "init_deferred_pred_opt ::=", + /* 78 */ "init_deferred_pred_opt ::= INITIALLY DEFERRED", + /* 79 */ "init_deferred_pred_opt ::= INITIALLY IMMEDIATE", + /* 80 */ "conslist_opt ::=", + /* 81 */ "conslist_opt ::= COMMA conslist", + /* 82 */ "conslist ::= conslist COMMA tcons", + /* 83 */ "conslist ::= conslist tcons", + /* 84 */ "conslist ::= tcons", + /* 85 */ "tcons ::= CONSTRAINT nm", + /* 86 */ "tcons ::= PRIMARY KEY LP idxlist autoinc RP onconf", + /* 87 */ "tcons ::= UNIQUE LP idxlist RP onconf", + /* 88 */ "tcons ::= CHECK LP expr RP onconf", + /* 89 */ "tcons ::= FOREIGN KEY LP idxlist RP REFERENCES nm idxlist_opt refargs defer_subclause_opt", + /* 90 */ "defer_subclause_opt ::=", + /* 91 */ "defer_subclause_opt ::= defer_subclause", + /* 92 */ "onconf ::=", + /* 93 */ "onconf ::= ON CONFLICT resolvetype", + /* 94 */ "orconf ::=", + /* 95 */ "orconf ::= OR resolvetype", + /* 96 */ "resolvetype ::= raisetype", + /* 97 */ "resolvetype ::= IGNORE", + /* 98 */ "resolvetype ::= REPLACE", + /* 99 */ "cmd ::= DROP TABLE ifexists fullname", + /* 100 */ "ifexists ::= IF EXISTS", + /* 101 */ "ifexists ::=", + /* 102 */ "cmd ::= CREATE temp VIEW nm dbnm AS select", + /* 103 */ "cmd ::= DROP VIEW ifexists fullname", + /* 104 */ "cmd ::= select", + /* 105 */ "select ::= oneselect", + /* 106 */ "select ::= select multiselect_op oneselect", + /* 107 */ "multiselect_op ::= UNION", + /* 108 */ "multiselect_op ::= UNION ALL", + /* 109 */ "multiselect_op ::= EXCEPT|INTERSECT", + /* 110 */ "oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt", + /* 111 */ "distinct ::= DISTINCT", + /* 112 */ "distinct ::= ALL", + /* 113 */ "distinct ::=", + /* 114 */ "sclp ::= selcollist COMMA", + /* 115 */ "sclp ::=", + /* 116 */ "selcollist ::= sclp expr as", + /* 117 */ "selcollist ::= sclp STAR", + /* 118 */ "selcollist ::= sclp nm DOT STAR", + /* 119 */ "as ::= AS nm", + /* 120 */ "as ::= ids", + /* 121 */ "as ::=", + /* 122 */ "from ::=", + /* 123 */ "from ::= FROM seltablist", + /* 124 */ "stl_prefix ::= seltablist joinop", + /* 125 */ "stl_prefix ::=", + /* 126 */ "seltablist ::= stl_prefix nm dbnm as on_opt using_opt", + /* 127 */ "seltablist ::= stl_prefix LP seltablist_paren RP as on_opt using_opt", + /* 128 */ "seltablist_paren ::= select", + /* 129 */ "seltablist_paren ::= seltablist", + /* 130 */ "dbnm ::=", + /* 131 */ "dbnm ::= DOT nm", + /* 132 */ "fullname ::= nm dbnm", + /* 133 */ "joinop ::= COMMA|JOIN", + /* 134 */ "joinop ::= JOIN_KW JOIN", + /* 135 */ "joinop ::= JOIN_KW nm JOIN", + /* 136 */ "joinop ::= JOIN_KW nm nm JOIN", + /* 137 */ "on_opt ::= ON expr", + /* 138 */ "on_opt ::=", + /* 139 */ "using_opt ::= USING LP inscollist RP", + /* 140 */ "using_opt ::=", + /* 141 */ "orderby_opt ::=", + /* 142 */ "orderby_opt ::= ORDER BY sortlist", + /* 143 */ "sortlist ::= sortlist COMMA sortitem collate sortorder", + /* 144 */ "sortlist ::= sortitem collate sortorder", + /* 145 */ "sortitem ::= expr", + /* 146 */ "sortorder ::= ASC", + /* 147 */ "sortorder ::= DESC", + /* 148 */ "sortorder ::=", + /* 149 */ "collate ::=", + /* 150 */ "collate ::= COLLATE id", + /* 151 */ "groupby_opt ::=", + /* 152 */ "groupby_opt ::= GROUP BY exprlist", + /* 153 */ "having_opt ::=", + /* 154 */ "having_opt ::= HAVING expr", + /* 155 */ "limit_opt ::=", + /* 156 */ "limit_opt ::= LIMIT expr", + /* 157 */ "limit_opt ::= LIMIT expr OFFSET expr", + /* 158 */ "limit_opt ::= LIMIT expr COMMA expr", + /* 159 */ "cmd ::= DELETE FROM fullname where_opt", + /* 160 */ "where_opt ::=", + /* 161 */ "where_opt ::= WHERE expr", + /* 162 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt", + /* 163 */ "setlist ::= setlist COMMA nm EQ expr", + /* 164 */ "setlist ::= nm EQ expr", + /* 165 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP", + /* 166 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select", + /* 167 */ "insert_cmd ::= INSERT orconf", + /* 168 */ "insert_cmd ::= REPLACE", + /* 169 */ "itemlist ::= itemlist COMMA expr", + /* 170 */ "itemlist ::= expr", + /* 171 */ "inscollist_opt ::=", + /* 172 */ "inscollist_opt ::= LP inscollist RP", + /* 173 */ "inscollist ::= inscollist COMMA nm", + /* 174 */ "inscollist ::= nm", + /* 175 */ "expr ::= term", + /* 176 */ "expr ::= LP expr RP", + /* 177 */ "term ::= NULL", + /* 178 */ "expr ::= ID", + /* 179 */ "expr ::= JOIN_KW", + /* 180 */ "expr ::= nm DOT nm", + /* 181 */ "expr ::= nm DOT nm DOT nm", + /* 182 */ "term ::= INTEGER|FLOAT|BLOB", /* 183 */ "term ::= STRING", - /* 184 */ "term ::= BLOB", - /* 185 */ "expr ::= REGISTER", - /* 186 */ "expr ::= VARIABLE", - /* 187 */ "expr ::= CAST LP expr AS typetoken RP", - /* 188 */ "expr ::= ID LP distinct exprlist RP", - /* 189 */ "expr ::= ID LP STAR RP", - /* 190 */ "term ::= CTIME_KW", - /* 191 */ "expr ::= expr AND expr", - /* 192 */ "expr ::= expr OR expr", - /* 193 */ "expr ::= expr LT expr", - /* 194 */ "expr ::= expr GT expr", - /* 195 */ "expr ::= expr LE expr", - /* 196 */ "expr ::= expr GE expr", - /* 197 */ "expr ::= expr NE expr", - /* 198 */ "expr ::= expr EQ expr", - /* 199 */ "expr ::= expr BITAND expr", - /* 200 */ "expr ::= expr BITOR expr", - /* 201 */ "expr ::= expr LSHIFT expr", - /* 202 */ "expr ::= expr RSHIFT expr", - /* 203 */ "expr ::= expr PLUS expr", - /* 204 */ "expr ::= expr MINUS expr", - /* 205 */ "expr ::= expr STAR expr", - /* 206 */ "expr ::= expr SLASH expr", - /* 207 */ "expr ::= expr REM expr", - /* 208 */ "expr ::= expr CONCAT expr", - /* 209 */ "likeop ::= LIKE_KW", - /* 210 */ "likeop ::= NOT LIKE_KW", - /* 211 */ "escape ::= ESCAPE expr", - /* 212 */ "escape ::=", - /* 213 */ "expr ::= expr likeop expr escape", - /* 214 */ "expr ::= expr ISNULL", - /* 215 */ "expr ::= expr IS NULL", - /* 216 */ "expr ::= expr NOTNULL", - /* 217 */ "expr ::= expr NOT NULL", - /* 218 */ "expr ::= expr IS NOT NULL", - /* 219 */ "expr ::= NOT expr", - /* 220 */ "expr ::= BITNOT expr", - /* 221 */ "expr ::= MINUS expr", - /* 222 */ "expr ::= PLUS expr", - /* 223 */ "between_op ::= BETWEEN", - /* 224 */ "between_op ::= NOT BETWEEN", - /* 225 */ "expr ::= expr between_op expr AND expr", - /* 226 */ "in_op ::= IN", - /* 227 */ "in_op ::= NOT IN", - /* 228 */ "expr ::= expr in_op LP exprlist RP", - /* 229 */ "expr ::= LP select RP", - /* 230 */ "expr ::= expr in_op LP select RP", - /* 231 */ "expr ::= expr in_op nm dbnm", - /* 232 */ "expr ::= EXISTS LP select RP", - /* 233 */ "expr ::= CASE case_operand case_exprlist case_else END", - /* 234 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", - /* 235 */ "case_exprlist ::= WHEN expr THEN expr", - /* 236 */ "case_else ::= ELSE expr", - /* 237 */ "case_else ::=", - /* 238 */ "case_operand ::= expr", - /* 239 */ "case_operand ::=", - /* 240 */ "exprlist ::= exprlist COMMA expritem", - /* 241 */ "exprlist ::= expritem", - /* 242 */ "expritem ::= expr", - /* 243 */ "expritem ::=", - /* 244 */ "cmd ::= CREATE uniqueflag INDEX nm dbnm ON nm LP idxlist RP onconf", - /* 245 */ "uniqueflag ::= UNIQUE", - /* 246 */ "uniqueflag ::=", - /* 247 */ "idxlist_opt ::=", - /* 248 */ "idxlist_opt ::= LP idxlist RP", - /* 249 */ "idxlist ::= idxlist COMMA idxitem collate sortorder", - /* 250 */ "idxlist ::= idxitem collate sortorder", - /* 251 */ "idxitem ::= nm", - /* 252 */ "cmd ::= DROP INDEX fullname", - /* 253 */ "cmd ::= VACUUM", - /* 254 */ "cmd ::= VACUUM nm", - /* 255 */ "cmd ::= PRAGMA nm dbnm EQ nm", - /* 256 */ "cmd ::= PRAGMA nm dbnm EQ ON", - /* 257 */ "cmd ::= PRAGMA nm dbnm EQ plus_num", - /* 258 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", - /* 259 */ "cmd ::= PRAGMA nm dbnm LP nm RP", - /* 260 */ "cmd ::= PRAGMA nm dbnm", - /* 261 */ "plus_num ::= plus_opt number", - /* 262 */ "minus_num ::= MINUS number", - /* 263 */ "number ::= INTEGER", - /* 264 */ "number ::= FLOAT", - /* 265 */ "plus_opt ::= PLUS", - /* 266 */ "plus_opt ::=", - /* 267 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END", - /* 268 */ "trigger_decl ::= temp TRIGGER nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", - /* 269 */ "trigger_time ::= BEFORE", - /* 270 */ "trigger_time ::= AFTER", - /* 271 */ "trigger_time ::= INSTEAD OF", - /* 272 */ "trigger_time ::=", - /* 273 */ "trigger_event ::= DELETE", - /* 274 */ "trigger_event ::= INSERT", - /* 275 */ "trigger_event ::= UPDATE", - /* 276 */ "trigger_event ::= UPDATE OF inscollist", - /* 277 */ "foreach_clause ::=", - /* 278 */ "foreach_clause ::= FOR EACH ROW", - /* 279 */ "foreach_clause ::= FOR EACH STATEMENT", - /* 280 */ "when_clause ::=", - /* 281 */ "when_clause ::= WHEN expr", - /* 282 */ "trigger_cmd_list ::= trigger_cmd SEMI trigger_cmd_list", - /* 283 */ "trigger_cmd_list ::=", - /* 284 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt", - /* 285 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP", - /* 286 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select", - /* 287 */ "trigger_cmd ::= DELETE FROM nm where_opt", - /* 288 */ "trigger_cmd ::= select", - /* 289 */ "expr ::= RAISE LP IGNORE RP", - /* 290 */ "expr ::= RAISE LP raisetype COMMA nm RP", - /* 291 */ "raisetype ::= ROLLBACK", - /* 292 */ "raisetype ::= ABORT", - /* 293 */ "raisetype ::= FAIL", - /* 294 */ "cmd ::= DROP TRIGGER fullname", - /* 295 */ "cmd ::= ATTACH database_kw_opt ids AS nm key_opt", - /* 296 */ "key_opt ::=", - /* 297 */ "key_opt ::= KEY ids", - /* 298 */ "key_opt ::= KEY BLOB", - /* 299 */ "database_kw_opt ::= DATABASE", - /* 300 */ "database_kw_opt ::=", - /* 301 */ "cmd ::= DETACH database_kw_opt nm", - /* 302 */ "cmd ::= REINDEX", - /* 303 */ "cmd ::= REINDEX nm dbnm", - /* 304 */ "cmd ::= ANALYZE", - /* 305 */ "cmd ::= ANALYZE nm dbnm", - /* 306 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", - /* 307 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column", - /* 308 */ "add_column_fullname ::= fullname", - /* 309 */ "kwcolumn_opt ::=", - /* 310 */ "kwcolumn_opt ::= COLUMNKW", + /* 184 */ "expr ::= REGISTER", + /* 185 */ "expr ::= VARIABLE", + /* 186 */ "expr ::= CAST LP expr AS typetoken RP", + /* 187 */ "expr ::= ID LP distinct exprlist RP", + /* 188 */ "expr ::= ID LP STAR RP", + /* 189 */ "term ::= CTIME_KW", + /* 190 */ "expr ::= expr AND expr", + /* 191 */ "expr ::= expr OR expr", + /* 192 */ "expr ::= expr LT|GT|GE|LE expr", + /* 193 */ "expr ::= expr EQ|NE expr", + /* 194 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr", + /* 195 */ "expr ::= expr PLUS|MINUS expr", + /* 196 */ "expr ::= expr STAR|SLASH|REM expr", + /* 197 */ "expr ::= expr CONCAT expr", + /* 198 */ "likeop ::= LIKE_KW", + /* 199 */ "likeop ::= NOT LIKE_KW", + /* 200 */ "escape ::= ESCAPE expr", + /* 201 */ "escape ::=", + /* 202 */ "expr ::= expr likeop expr escape", + /* 203 */ "expr ::= expr ISNULL|NOTNULL", + /* 204 */ "expr ::= expr IS NULL", + /* 205 */ "expr ::= expr NOT NULL", + /* 206 */ "expr ::= expr IS NOT NULL", + /* 207 */ "expr ::= NOT|BITNOT expr", + /* 208 */ "expr ::= MINUS expr", + /* 209 */ "expr ::= PLUS expr", + /* 210 */ "between_op ::= BETWEEN", + /* 211 */ "between_op ::= NOT BETWEEN", + /* 212 */ "expr ::= expr between_op expr AND expr", + /* 213 */ "in_op ::= IN", + /* 214 */ "in_op ::= NOT IN", + /* 215 */ "expr ::= expr in_op LP exprlist RP", + /* 216 */ "expr ::= LP select RP", + /* 217 */ "expr ::= expr in_op LP select RP", + /* 218 */ "expr ::= expr in_op nm dbnm", + /* 219 */ "expr ::= EXISTS LP select RP", + /* 220 */ "expr ::= CASE case_operand case_exprlist case_else END", + /* 221 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr", + /* 222 */ "case_exprlist ::= WHEN expr THEN expr", + /* 223 */ "case_else ::= ELSE expr", + /* 224 */ "case_else ::=", + /* 225 */ "case_operand ::= expr", + /* 226 */ "case_operand ::=", + /* 227 */ "exprlist ::= exprlist COMMA expritem", + /* 228 */ "exprlist ::= expritem", + /* 229 */ "expritem ::= expr", + /* 230 */ "expritem ::=", + /* 231 */ "cmd ::= CREATE uniqueflag INDEX ifnotexists nm dbnm ON nm LP idxlist RP onconf", + /* 232 */ "uniqueflag ::= UNIQUE", + /* 233 */ "uniqueflag ::=", + /* 234 */ "idxlist_opt ::=", + /* 235 */ "idxlist_opt ::= LP idxlist RP", + /* 236 */ "idxlist ::= idxlist COMMA idxitem collate sortorder", + /* 237 */ "idxlist ::= idxitem collate sortorder", + /* 238 */ "idxitem ::= nm", + /* 239 */ "cmd ::= DROP INDEX ifexists fullname", + /* 240 */ "cmd ::= VACUUM", + /* 241 */ "cmd ::= VACUUM nm", + /* 242 */ "cmd ::= PRAGMA nm dbnm EQ nm", + /* 243 */ "cmd ::= PRAGMA nm dbnm EQ ON", + /* 244 */ "cmd ::= PRAGMA nm dbnm EQ plus_num", + /* 245 */ "cmd ::= PRAGMA nm dbnm EQ minus_num", + /* 246 */ "cmd ::= PRAGMA nm dbnm LP nm RP", + /* 247 */ "cmd ::= PRAGMA nm dbnm", + /* 248 */ "plus_num ::= plus_opt number", + /* 249 */ "minus_num ::= MINUS number", + /* 250 */ "number ::= INTEGER|FLOAT", + /* 251 */ "plus_opt ::= PLUS", + /* 252 */ "plus_opt ::=", + /* 253 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END", + /* 254 */ "trigger_decl ::= temp TRIGGER nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause", + /* 255 */ "trigger_time ::= BEFORE", + /* 256 */ "trigger_time ::= AFTER", + /* 257 */ "trigger_time ::= INSTEAD OF", + /* 258 */ "trigger_time ::=", + /* 259 */ "trigger_event ::= DELETE|INSERT", + /* 260 */ "trigger_event ::= UPDATE", + /* 261 */ "trigger_event ::= UPDATE OF inscollist", + /* 262 */ "foreach_clause ::=", + /* 263 */ "foreach_clause ::= FOR EACH ROW", + /* 264 */ "foreach_clause ::= FOR EACH STATEMENT", + /* 265 */ "when_clause ::=", + /* 266 */ "when_clause ::= WHEN expr", + /* 267 */ "trigger_cmd_list ::= trigger_cmd SEMI trigger_cmd_list", + /* 268 */ "trigger_cmd_list ::=", + /* 269 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt", + /* 270 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP", + /* 271 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select", + /* 272 */ "trigger_cmd ::= DELETE FROM nm where_opt", + /* 273 */ "trigger_cmd ::= select", + /* 274 */ "expr ::= RAISE LP IGNORE RP", + /* 275 */ "expr ::= RAISE LP raisetype COMMA nm RP", + /* 276 */ "raisetype ::= ROLLBACK", + /* 277 */ "raisetype ::= ABORT", + /* 278 */ "raisetype ::= FAIL", + /* 279 */ "cmd ::= DROP TRIGGER fullname", + /* 280 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt", + /* 281 */ "key_opt ::=", + /* 282 */ "key_opt ::= KEY expr", + /* 283 */ "database_kw_opt ::= DATABASE", + /* 284 */ "database_kw_opt ::=", + /* 285 */ "cmd ::= DETACH database_kw_opt expr", + /* 286 */ "cmd ::= REINDEX", + /* 287 */ "cmd ::= REINDEX nm dbnm", + /* 288 */ "cmd ::= ANALYZE", + /* 289 */ "cmd ::= ANALYZE nm dbnm", + /* 290 */ "cmd ::= ALTER TABLE fullname RENAME TO nm", + /* 291 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column", + /* 292 */ "add_column_fullname ::= fullname", + /* 293 */ "kwcolumn_opt ::=", + /* 294 */ "kwcolumn_opt ::= COLUMNKW", }; #endif /* NDEBUG */ /* ** This function returns the symbolic name associated with a token @@ -1320,76 +1205,85 @@ ** ** Note: during a reduce, the only symbols destroyed are those ** which appear on the RHS of the rule, but which are not used ** inside the C code. */ - case 162: + case 154: + case 188: + case 205: +#line 368 "parse.y" +{sqlite3SelectDelete((yypminor->yy239));} +#line 1217 "parse.c" + break; + case 168: + case 169: + case 193: case 195: - case 212: -#line 370 "parse.y" -{sqlite3SelectDelete((yypminor->yy375));} -#line 1332 "parse.c" - break; - case 176: - case 177: - case 200: - case 202: - case 210: - case 216: - case 230: -#line 629 "parse.y" -{sqlite3ExprDelete((yypminor->yy62));} -#line 1343 "parse.c" - break; + case 203: + case 209: + case 217: + case 220: + case 222: + case 223: + case 233: +#line 625 "parse.y" +{sqlite3ExprDelete((yypminor->yy178));} +#line 1232 "parse.c" + break; + case 173: case 181: - case 189: + case 191: + case 194: + case 196: case 198: - case 201: - case 203: - case 205: + case 208: + case 211: + case 212: case 215: - case 218: - case 219: - case 222: - case 228: -#line 876 "parse.y" -{sqlite3ExprListDelete((yypminor->yy418));} -#line 1358 "parse.c" + case 221: +#line 857 "parse.y" +{sqlite3ExprListDelete((yypminor->yy462));} +#line 1247 "parse.c" + break; + case 187: + case 192: + case 200: + case 201: +#line 496 "parse.y" +{sqlite3SrcListDelete((yypminor->yy285));} +#line 1255 "parse.c" break; - case 194: - case 199: - case 207: - case 208: -#line 499 "parse.y" -{sqlite3SrcListDelete((yypminor->yy151));} -#line 1366 "parse.c" + case 197: +#line 557 "parse.y" +{ + sqlite3ExprDelete((yypminor->yy270).pLimit); + sqlite3ExprDelete((yypminor->yy270).pOffset); +} +#line 1263 "parse.c" break; case 204: -#line 561 "parse.y" -{ - sqlite3ExprDelete((yypminor->yy220).pLimit); - sqlite3ExprDelete((yypminor->yy220).pOffset); -} -#line 1374 "parse.c" + case 207: + case 214: +#line 513 "parse.y" +{sqlite3IdListDelete((yypminor->yy160));} +#line 1270 "parse.c" + break; + case 229: + case 234: +#line 951 "parse.y" +{sqlite3DeleteTriggerStep((yypminor->yy247));} +#line 1276 "parse.c" break; - case 211: - case 214: - case 221: -#line 517 "parse.y" -{sqlite3IdListDelete((yypminor->yy240));} -#line 1381 "parse.c" + case 231: +#line 935 "parse.y" +{sqlite3IdListDelete((yypminor->yy132).b);} +#line 1281 "parse.c" break; case 236: - case 241: -#line 969 "parse.y" -{sqlite3DeleteTriggerStep((yypminor->yy360));} -#line 1387 "parse.c" - break; - case 238: -#line 953 "parse.y" -{sqlite3IdListDelete((yypminor->yy30).b);} -#line 1392 "parse.c" +#line 1010 "parse.y" +{sqlite3ExprDelete((yypminor->yy292));} +#line 1286 "parse.c" break; default: break; /* If no destructor action specified: do nothing */ } } @@ -1454,13 +1348,11 @@ int iLookAhead /* The look-ahead token */ ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; - /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */ - i = yy_shift_ofst[stateno]; - if( i==YY_SHIFT_USE_DFLT ){ + if( stateno>YY_SHIFT_MAX || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ return yy_default[stateno]; } if( iLookAhead==YYNOCODE ){ return YY_NO_ACTION; } @@ -1498,12 +1390,12 @@ int iLookAhead /* The look-ahead token */ ){ int i; /* int stateno = pParser->yystack[pParser->yyidx].stateno; */ - i = yy_reduce_ofst[stateno]; - if( i==YY_REDUCE_USE_DFLT ){ + if( stateno>YY_REDUCE_MAX || + (i = yy_reduce_ofst[stateno])==YY_REDUCE_USE_DFLT ){ return yy_default[stateno]; } if( iLookAhead==YYNOCODE ){ return YY_NO_ACTION; } @@ -1561,321 +1453,305 @@ */ static const struct { YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */ unsigned char nrhs; /* Number of right-hand side symbols in the rule */ } yyRuleInfo[] = { - { 147, 1 }, - { 148, 2 }, - { 148, 1 }, - { 150, 1 }, - { 149, 1 }, - { 149, 3 }, - { 152, 0 }, - { 152, 1 }, - { 152, 3 }, - { 151, 3 }, - { 154, 0 }, - { 154, 1 }, - { 154, 2 }, - { 153, 0 }, - { 153, 1 }, - { 153, 1 }, - { 153, 1 }, - { 151, 2 }, - { 151, 2 }, - { 151, 2 }, - { 151, 2 }, - { 156, 5 }, - { 158, 1 }, - { 158, 0 }, - { 157, 4 }, - { 157, 2 }, - { 160, 3 }, - { 160, 1 }, - { 163, 3 }, - { 164, 1 }, - { 167, 1 }, - { 168, 1 }, - { 168, 1 }, - { 155, 1 }, - { 155, 1 }, - { 155, 1 }, - { 165, 0 }, - { 165, 1 }, - { 169, 1 }, - { 169, 4 }, - { 169, 6 }, - { 170, 1 }, - { 170, 2 }, - { 171, 1 }, - { 171, 1 }, - { 166, 2 }, - { 166, 0 }, - { 174, 3 }, - { 174, 1 }, - { 174, 2 }, - { 174, 4 }, - { 174, 3 }, - { 174, 3 }, - { 174, 2 }, - { 175, 2 }, - { 175, 3 }, - { 175, 5 }, - { 175, 2 }, - { 175, 5 }, - { 175, 4 }, - { 175, 1 }, - { 175, 2 }, - { 180, 0 }, - { 180, 1 }, - { 182, 0 }, - { 182, 2 }, - { 184, 2 }, - { 184, 3 }, - { 184, 3 }, - { 184, 3 }, - { 185, 2 }, - { 185, 2 }, - { 185, 1 }, - { 185, 1 }, - { 183, 3 }, - { 183, 2 }, - { 186, 0 }, - { 186, 2 }, - { 186, 2 }, - { 161, 0 }, - { 161, 2 }, - { 187, 3 }, - { 187, 2 }, - { 187, 1 }, - { 188, 2 }, - { 188, 7 }, - { 188, 5 }, - { 188, 3 }, - { 188, 10 }, - { 190, 0 }, - { 190, 1 }, - { 178, 0 }, - { 178, 3 }, - { 191, 0 }, - { 191, 2 }, - { 192, 1 }, - { 192, 1 }, - { 192, 1 }, - { 151, 3 }, - { 151, 7 }, - { 151, 3 }, - { 151, 1 }, - { 162, 1 }, - { 162, 3 }, - { 196, 1 }, - { 196, 2 }, - { 196, 1 }, - { 196, 1 }, - { 195, 9 }, - { 197, 1 }, - { 197, 1 }, - { 197, 0 }, - { 205, 2 }, - { 205, 0 }, - { 198, 3 }, - { 198, 2 }, - { 198, 4 }, - { 206, 2 }, - { 206, 1 }, - { 206, 0 }, - { 199, 0 }, - { 199, 2 }, - { 208, 2 }, - { 208, 0 }, - { 207, 6 }, - { 207, 7 }, - { 212, 1 }, - { 212, 1 }, - { 159, 0 }, - { 159, 2 }, - { 194, 2 }, - { 209, 1 }, - { 209, 1 }, - { 209, 2 }, - { 209, 3 }, - { 209, 4 }, - { 210, 2 }, - { 210, 0 }, - { 211, 4 }, - { 211, 0 }, - { 203, 0 }, - { 203, 3 }, - { 215, 5 }, - { 215, 3 }, - { 216, 1 }, - { 179, 1 }, - { 179, 1 }, - { 179, 0 }, - { 217, 0 }, - { 217, 2 }, - { 201, 0 }, - { 201, 3 }, - { 202, 0 }, - { 202, 2 }, - { 204, 0 }, - { 204, 2 }, - { 204, 4 }, - { 204, 4 }, - { 151, 4 }, - { 200, 0 }, - { 200, 2 }, - { 151, 6 }, - { 219, 5 }, - { 219, 3 }, - { 151, 8 }, - { 151, 5 }, - { 220, 2 }, - { 220, 1 }, - { 222, 3 }, - { 222, 1 }, - { 221, 0 }, - { 221, 3 }, - { 214, 3 }, - { 214, 1 }, - { 177, 1 }, - { 177, 3 }, - { 176, 1 }, - { 177, 1 }, - { 177, 1 }, - { 177, 3 }, - { 177, 5 }, - { 176, 1 }, - { 176, 1 }, - { 176, 1 }, - { 176, 1 }, - { 177, 1 }, - { 177, 1 }, - { 177, 6 }, - { 177, 5 }, - { 177, 4 }, - { 176, 1 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 177, 3 }, - { 223, 1 }, - { 223, 2 }, - { 224, 2 }, - { 224, 0 }, - { 177, 4 }, - { 177, 2 }, - { 177, 3 }, - { 177, 2 }, - { 177, 3 }, - { 177, 4 }, - { 177, 2 }, - { 177, 2 }, - { 177, 2 }, - { 177, 2 }, - { 225, 1 }, - { 225, 2 }, - { 177, 5 }, - { 226, 1 }, - { 226, 2 }, - { 177, 5 }, - { 177, 3 }, - { 177, 5 }, - { 177, 4 }, - { 177, 4 }, - { 177, 5 }, - { 228, 5 }, - { 228, 4 }, - { 229, 2 }, - { 229, 0 }, - { 227, 1 }, - { 227, 0 }, - { 218, 3 }, - { 218, 1 }, - { 230, 1 }, - { 230, 0 }, - { 151, 11 }, - { 231, 1 }, - { 231, 0 }, - { 181, 0 }, - { 181, 3 }, - { 189, 5 }, - { 189, 3 }, - { 232, 1 }, - { 151, 3 }, - { 151, 1 }, - { 151, 2 }, - { 151, 5 }, - { 151, 5 }, - { 151, 5 }, - { 151, 5 }, - { 151, 6 }, - { 151, 3 }, - { 172, 2 }, - { 173, 2 }, - { 234, 1 }, - { 234, 1 }, - { 233, 1 }, - { 233, 0 }, - { 151, 5 }, - { 235, 10 }, - { 237, 1 }, - { 237, 1 }, - { 237, 2 }, - { 237, 0 }, - { 238, 1 }, - { 238, 1 }, - { 238, 1 }, - { 238, 3 }, - { 239, 0 }, - { 239, 3 }, - { 239, 3 }, - { 240, 0 }, - { 240, 2 }, - { 236, 3 }, - { 236, 0 }, - { 241, 6 }, - { 241, 8 }, - { 241, 5 }, - { 241, 4 }, - { 241, 1 }, - { 177, 4 }, - { 177, 6 }, - { 193, 1 }, - { 193, 1 }, - { 193, 1 }, - { 151, 3 }, - { 151, 6 }, - { 243, 0 }, - { 243, 2 }, - { 243, 2 }, - { 242, 1 }, - { 242, 0 }, - { 151, 3 }, - { 151, 1 }, - { 151, 3 }, - { 151, 1 }, - { 151, 3 }, - { 151, 6 }, - { 151, 6 }, - { 244, 1 }, - { 245, 0 }, - { 245, 1 }, + { 138, 1 }, + { 139, 2 }, + { 139, 1 }, + { 141, 1 }, + { 140, 1 }, + { 140, 3 }, + { 143, 0 }, + { 143, 1 }, + { 143, 3 }, + { 142, 3 }, + { 145, 0 }, + { 145, 1 }, + { 145, 2 }, + { 144, 0 }, + { 144, 1 }, + { 144, 1 }, + { 144, 1 }, + { 142, 2 }, + { 142, 2 }, + { 142, 2 }, + { 142, 2 }, + { 147, 6 }, + { 150, 0 }, + { 150, 3 }, + { 149, 1 }, + { 149, 0 }, + { 148, 4 }, + { 148, 2 }, + { 152, 3 }, + { 152, 1 }, + { 155, 3 }, + { 156, 1 }, + { 159, 1 }, + { 160, 1 }, + { 146, 1 }, + { 146, 1 }, + { 146, 1 }, + { 157, 0 }, + { 157, 1 }, + { 161, 1 }, + { 161, 4 }, + { 161, 6 }, + { 162, 1 }, + { 162, 2 }, + { 163, 1 }, + { 163, 1 }, + { 158, 2 }, + { 158, 0 }, + { 166, 3 }, + { 166, 1 }, + { 166, 2 }, + { 166, 4 }, + { 166, 3 }, + { 166, 3 }, + { 166, 2 }, + { 167, 2 }, + { 167, 3 }, + { 167, 5 }, + { 167, 2 }, + { 167, 4 }, + { 167, 4 }, + { 167, 1 }, + { 167, 2 }, + { 172, 0 }, + { 172, 1 }, + { 174, 0 }, + { 174, 2 }, + { 176, 2 }, + { 176, 3 }, + { 176, 3 }, + { 176, 3 }, + { 177, 2 }, + { 177, 2 }, + { 177, 1 }, + { 177, 1 }, + { 175, 3 }, + { 175, 2 }, + { 178, 0 }, + { 178, 2 }, + { 178, 2 }, + { 153, 0 }, + { 153, 2 }, + { 179, 3 }, + { 179, 2 }, + { 179, 1 }, + { 180, 2 }, + { 180, 7 }, + { 180, 5 }, + { 180, 5 }, + { 180, 10 }, + { 182, 0 }, + { 182, 1 }, + { 170, 0 }, + { 170, 3 }, + { 183, 0 }, + { 183, 2 }, + { 184, 1 }, + { 184, 1 }, + { 184, 1 }, + { 142, 4 }, + { 186, 2 }, + { 186, 0 }, + { 142, 7 }, + { 142, 4 }, + { 142, 1 }, + { 154, 1 }, + { 154, 3 }, + { 189, 1 }, + { 189, 2 }, + { 189, 1 }, + { 188, 9 }, + { 190, 1 }, + { 190, 1 }, + { 190, 0 }, + { 198, 2 }, + { 198, 0 }, + { 191, 3 }, + { 191, 2 }, + { 191, 4 }, + { 199, 2 }, + { 199, 1 }, + { 199, 0 }, + { 192, 0 }, + { 192, 2 }, + { 201, 2 }, + { 201, 0 }, + { 200, 6 }, + { 200, 7 }, + { 205, 1 }, + { 205, 1 }, + { 151, 0 }, + { 151, 2 }, + { 187, 2 }, + { 202, 1 }, + { 202, 2 }, + { 202, 3 }, + { 202, 4 }, + { 203, 2 }, + { 203, 0 }, + { 204, 4 }, + { 204, 0 }, + { 196, 0 }, + { 196, 3 }, + { 208, 5 }, + { 208, 3 }, + { 209, 1 }, + { 171, 1 }, + { 171, 1 }, + { 171, 0 }, + { 210, 0 }, + { 210, 2 }, + { 194, 0 }, + { 194, 3 }, + { 195, 0 }, + { 195, 2 }, + { 197, 0 }, + { 197, 2 }, + { 197, 4 }, + { 197, 4 }, + { 142, 4 }, + { 193, 0 }, + { 193, 2 }, + { 142, 6 }, + { 212, 5 }, + { 212, 3 }, + { 142, 8 }, + { 142, 5 }, + { 213, 2 }, + { 213, 1 }, + { 215, 3 }, + { 215, 1 }, + { 214, 0 }, + { 214, 3 }, + { 207, 3 }, + { 207, 1 }, + { 169, 1 }, + { 169, 3 }, + { 168, 1 }, + { 169, 1 }, + { 169, 1 }, + { 169, 3 }, + { 169, 5 }, + { 168, 1 }, + { 168, 1 }, + { 169, 1 }, + { 169, 1 }, + { 169, 6 }, + { 169, 5 }, + { 169, 4 }, + { 168, 1 }, + { 169, 3 }, + { 169, 3 }, + { 169, 3 }, + { 169, 3 }, + { 169, 3 }, + { 169, 3 }, + { 169, 3 }, + { 169, 3 }, + { 216, 1 }, + { 216, 2 }, + { 217, 2 }, + { 217, 0 }, + { 169, 4 }, + { 169, 2 }, + { 169, 3 }, + { 169, 3 }, + { 169, 4 }, + { 169, 2 }, + { 169, 2 }, + { 169, 2 }, + { 218, 1 }, + { 218, 2 }, + { 169, 5 }, + { 219, 1 }, + { 219, 2 }, + { 169, 5 }, + { 169, 3 }, + { 169, 5 }, + { 169, 4 }, + { 169, 4 }, + { 169, 5 }, + { 221, 5 }, + { 221, 4 }, + { 222, 2 }, + { 222, 0 }, + { 220, 1 }, + { 220, 0 }, + { 211, 3 }, + { 211, 1 }, + { 223, 1 }, + { 223, 0 }, + { 142, 12 }, + { 224, 1 }, + { 224, 0 }, + { 173, 0 }, + { 173, 3 }, + { 181, 5 }, + { 181, 3 }, + { 225, 1 }, + { 142, 4 }, + { 142, 1 }, + { 142, 2 }, + { 142, 5 }, + { 142, 5 }, + { 142, 5 }, + { 142, 5 }, + { 142, 6 }, + { 142, 3 }, + { 164, 2 }, + { 165, 2 }, + { 227, 1 }, + { 226, 1 }, + { 226, 0 }, + { 142, 5 }, + { 228, 10 }, + { 230, 1 }, + { 230, 1 }, + { 230, 2 }, + { 230, 0 }, + { 231, 1 }, + { 231, 1 }, + { 231, 3 }, + { 232, 0 }, + { 232, 3 }, + { 232, 3 }, + { 233, 0 }, + { 233, 2 }, + { 229, 3 }, + { 229, 0 }, + { 234, 6 }, + { 234, 8 }, + { 234, 5 }, + { 234, 4 }, + { 234, 1 }, + { 169, 4 }, + { 169, 6 }, + { 185, 1 }, + { 185, 1 }, + { 185, 1 }, + { 142, 3 }, + { 142, 6 }, + { 236, 0 }, + { 236, 2 }, + { 235, 1 }, + { 235, 0 }, + { 142, 3 }, + { 142, 1 }, + { 142, 3 }, + { 142, 1 }, + { 142, 3 }, + { 142, 6 }, + { 142, 6 }, + { 237, 1 }, + { 238, 0 }, + { 238, 1 }, }; static void yy_accept(yyParser*); /* Forward Declaration */ /* @@ -1921,1298 +1797,1279 @@ ** { ... } // User supplied code ** #line ** break; */ case 3: -#line 102 "parse.y" +#line 95 "parse.y" { sqlite3FinishCoding(pParse); } -#line 1930 "parse.c" +#line 1806 "parse.c" break; case 6: -#line 105 "parse.y" +#line 98 "parse.y" { sqlite3BeginParse(pParse, 0); } -#line 1935 "parse.c" +#line 1811 "parse.c" break; case 7: -#line 107 "parse.y" +#line 100 "parse.y" { sqlite3BeginParse(pParse, 1); } -#line 1940 "parse.c" +#line 1816 "parse.c" break; case 8: -#line 108 "parse.y" +#line 101 "parse.y" { sqlite3BeginParse(pParse, 2); } -#line 1945 "parse.c" +#line 1821 "parse.c" break; case 9: -#line 114 "parse.y" -{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy280);} -#line 1950 "parse.c" +#line 107 "parse.y" +{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy230);} +#line 1826 "parse.c" break; case 13: -#line 119 "parse.y" -{yygotominor.yy280 = TK_DEFERRED;} -#line 1955 "parse.c" +#line 112 "parse.y" +{yygotominor.yy230 = TK_DEFERRED;} +#line 1831 "parse.c" break; case 14: case 15: case 16: - case 104: - case 106: case 107: -#line 120 "parse.y" -{yygotominor.yy280 = yymsp[0].major;} -#line 1965 "parse.c" + case 109: +#line 113 "parse.y" +{yygotominor.yy230 = yymsp[0].major;} +#line 1840 "parse.c" break; case 17: case 18: -#line 123 "parse.y" +#line 116 "parse.y" {sqlite3CommitTransaction(pParse);} -#line 1971 "parse.c" +#line 1846 "parse.c" break; case 19: -#line 125 "parse.y" +#line 118 "parse.y" {sqlite3RollbackTransaction(pParse);} -#line 1976 "parse.c" +#line 1851 "parse.c" break; case 21: -#line 130 "parse.y" +#line 123 "parse.y" { - sqlite3StartTable(pParse,&yymsp[-4].minor.yy0,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198,yymsp[-3].minor.yy280,0); + sqlite3StartTable(pParse,&yymsp[-5].minor.yy0,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384,yymsp[-4].minor.yy230,0,yymsp[-2].minor.yy230); } -#line 1983 "parse.c" +#line 1858 "parse.c" break; case 22: + case 25: case 63: case 77: - case 109: - case 224: - case 227: -#line 135 "parse.y" -{yygotominor.yy280 = 1;} -#line 1993 "parse.c" + case 79: + case 90: + case 101: + case 112: + case 113: + case 210: + case 213: +#line 127 "parse.y" +{yygotominor.yy230 = 0;} +#line 1873 "parse.c" break; case 23: - case 62: - case 76: + case 24: + case 64: case 78: - case 89: - case 110: + case 100: case 111: - case 223: - case 226: + case 211: + case 214: +#line 128 "parse.y" +{yygotominor.yy230 = 1;} +#line 1885 "parse.c" + break; + case 26: +#line 134 "parse.y" +{ + sqlite3EndTable(pParse,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy0,0); +} +#line 1892 "parse.c" + break; + case 27: #line 137 "parse.y" -{yygotominor.yy280 = 0;} -#line 2006 "parse.c" - break; - case 24: -#line 138 "parse.y" -{ - sqlite3EndTable(pParse,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy0,0); -} -#line 2013 "parse.c" - break; - case 25: -#line 141 "parse.y" -{ - sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy375); - sqlite3SelectDelete(yymsp[0].minor.yy375); -} -#line 2021 "parse.c" - break; - case 28: +{ + sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy239); + sqlite3SelectDelete(yymsp[0].minor.yy239); +} +#line 1900 "parse.c" + break; + case 30: +#line 149 "parse.y" +{ + yygotominor.yy384.z = yymsp[-2].minor.yy384.z; + yygotominor.yy384.n = (pParse->sLastToken.z-yymsp[-2].minor.yy384.z) + pParse->sLastToken.n; +} +#line 1908 "parse.c" + break; + case 31: #line 153 "parse.y" { - yygotominor.yy198.z = yymsp[-2].minor.yy198.z; - yygotominor.yy198.n = (pParse->sLastToken.z-yymsp[-2].minor.yy198.z) + pParse->sLastToken.n; -} -#line 2029 "parse.c" - break; - case 29: -#line 157 "parse.y" -{ - sqlite3AddColumn(pParse,&yymsp[0].minor.yy198); - yygotominor.yy198 = yymsp[0].minor.yy198; -} -#line 2037 "parse.c" - break; - case 30: - case 31: + sqlite3AddColumn(pParse,&yymsp[0].minor.yy384); + yygotominor.yy384 = yymsp[0].minor.yy384; +} +#line 1916 "parse.c" + break; case 32: case 33: case 34: case 35: - case 263: - case 264: -#line 167 "parse.y" -{yygotominor.yy198 = yymsp[0].minor.yy0;} -#line 2049 "parse.c" - break; - case 37: -#line 227 "parse.y" -{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy198);} -#line 2054 "parse.c" + case 36: + case 250: +#line 163 "parse.y" +{yygotominor.yy384 = yymsp[0].minor.yy0;} +#line 1926 "parse.c" break; case 38: - case 41: - case 117: - case 118: - case 129: - case 149: - case 251: - case 261: - case 262: -#line 228 "parse.y" -{yygotominor.yy198 = yymsp[0].minor.yy198;} -#line 2067 "parse.c" +#line 222 "parse.y" +{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy384);} +#line 1931 "parse.c" break; case 39: -#line 229 "parse.y" -{ - yygotominor.yy198.z = yymsp[-3].minor.yy198.z; - yygotominor.yy198.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy198.z; -} -#line 2075 "parse.c" + case 42: + case 119: + case 120: + case 131: + case 150: + case 238: + case 248: + case 249: +#line 223 "parse.y" +{yygotominor.yy384 = yymsp[0].minor.yy384;} +#line 1944 "parse.c" break; case 40: -#line 233 "parse.y" -{ - yygotominor.yy198.z = yymsp[-5].minor.yy198.z; - yygotominor.yy198.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy198.z; -} -#line 2083 "parse.c" - break; - case 42: -#line 239 "parse.y" -{yygotominor.yy198.z=yymsp[-1].minor.yy198.z; yygotominor.yy198.n=yymsp[0].minor.yy198.n+(yymsp[0].minor.yy198.z-yymsp[-1].minor.yy198.z);} -#line 2088 "parse.c" +#line 224 "parse.y" +{ + yygotominor.yy384.z = yymsp[-3].minor.yy384.z; + yygotominor.yy384.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy384.z; +} +#line 1952 "parse.c" + break; + case 41: +#line 228 "parse.y" +{ + yygotominor.yy384.z = yymsp[-5].minor.yy384.z; + yygotominor.yy384.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy384.z; +} +#line 1960 "parse.c" break; case 43: -#line 241 "parse.y" -{ yygotominor.yy280 = atoi(yymsp[0].minor.yy198.z); } -#line 2093 "parse.c" +#line 234 "parse.y" +{yygotominor.yy384.z=yymsp[-1].minor.yy384.z; yygotominor.yy384.n=yymsp[0].minor.yy384.n+(yymsp[0].minor.yy384.z-yymsp[-1].minor.yy384.z);} +#line 1965 "parse.c" break; case 44: -#line 242 "parse.y" -{ yygotominor.yy280 = -atoi(yymsp[0].minor.yy198.z); } -#line 2098 "parse.c" +#line 236 "parse.y" +{ yygotominor.yy230 = atoi((char*)yymsp[0].minor.yy384.z); } +#line 1970 "parse.c" break; - case 49: - case 51: -#line 251 "parse.y" -{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy62);} -#line 2104 "parse.c" + case 45: +#line 237 "parse.y" +{ yygotominor.yy230 = -atoi((char*)yymsp[0].minor.yy384.z); } +#line 1975 "parse.c" break; case 50: -#line 252 "parse.y" -{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy62);} -#line 2109 "parse.c" - break; case 52: -#line 254 "parse.y" -{ - Expr *p = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy62, 0, 0); - sqlite3AddDefaultValue(pParse,p); -} -#line 2117 "parse.c" +#line 246 "parse.y" +{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy178);} +#line 1981 "parse.c" + break; + case 51: +#line 247 "parse.y" +{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy178);} +#line 1986 "parse.c" break; case 53: -#line 258 "parse.y" +#line 249 "parse.y" +{ + Expr *p = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy178, 0, 0); + sqlite3AddDefaultValue(pParse,p); +} +#line 1994 "parse.c" + break; + case 54: +#line 253 "parse.y" { - Expr *p = sqlite3Expr(TK_STRING, 0, 0, &yymsp[0].minor.yy198); + Expr *p = sqlite3Expr(TK_STRING, 0, 0, &yymsp[0].minor.yy384); sqlite3AddDefaultValue(pParse,p); } -#line 2125 "parse.c" - break; - case 55: -#line 267 "parse.y" -{sqlite3AddNotNull(pParse, yymsp[0].minor.yy280);} -#line 2130 "parse.c" +#line 2002 "parse.c" break; case 56: -#line 269 "parse.y" -{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy280,yymsp[0].minor.yy280);} -#line 2135 "parse.c" +#line 262 "parse.y" +{sqlite3AddNotNull(pParse, yymsp[0].minor.yy230);} +#line 2007 "parse.c" break; case 57: -#line 270 "parse.y" -{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy280,0,0);} -#line 2140 "parse.c" +#line 264 "parse.y" +{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy230,yymsp[0].minor.yy230,yymsp[-2].minor.yy230);} +#line 2012 "parse.c" break; case 58: -#line 271 "parse.y" -{sqlite3ExprDelete(yymsp[-2].minor.yy62);} -#line 2145 "parse.c" +#line 265 "parse.y" +{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy230,0,0,0,0);} +#line 2017 "parse.c" break; case 59: -#line 273 "parse.y" -{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy198,yymsp[-1].minor.yy418,yymsp[0].minor.yy280);} -#line 2150 "parse.c" +#line 266 "parse.y" +{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy178);} +#line 2022 "parse.c" break; case 60: -#line 274 "parse.y" -{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy280);} -#line 2155 "parse.c" +#line 268 "parse.y" +{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy384,yymsp[-1].minor.yy462,yymsp[0].minor.yy230);} +#line 2027 "parse.c" break; case 61: -#line 275 "parse.y" -{sqlite3AddCollateType(pParse, yymsp[0].minor.yy198.z, yymsp[0].minor.yy198.n);} -#line 2160 "parse.c" +#line 269 "parse.y" +{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy230);} +#line 2032 "parse.c" break; - case 64: -#line 288 "parse.y" -{ yygotominor.yy280 = OE_Restrict * 0x010101; } -#line 2165 "parse.c" + case 62: +#line 270 "parse.y" +{sqlite3AddCollateType(pParse, (char*)yymsp[0].minor.yy384.z, yymsp[0].minor.yy384.n);} +#line 2037 "parse.c" break; case 65: -#line 289 "parse.y" -{ yygotominor.yy280 = (yymsp[-1].minor.yy280 & yymsp[0].minor.yy359.mask) | yymsp[0].minor.yy359.value; } -#line 2170 "parse.c" +#line 283 "parse.y" +{ yygotominor.yy230 = OE_Restrict * 0x010101; } +#line 2042 "parse.c" break; case 66: -#line 291 "parse.y" -{ yygotominor.yy359.value = 0; yygotominor.yy359.mask = 0x000000; } -#line 2175 "parse.c" +#line 284 "parse.y" +{ yygotominor.yy230 = (yymsp[-1].minor.yy230 & yymsp[0].minor.yy13.mask) | yymsp[0].minor.yy13.value; } +#line 2047 "parse.c" break; case 67: -#line 292 "parse.y" -{ yygotominor.yy359.value = yymsp[0].minor.yy280; yygotominor.yy359.mask = 0x0000ff; } -#line 2180 "parse.c" +#line 286 "parse.y" +{ yygotominor.yy13.value = 0; yygotominor.yy13.mask = 0x000000; } +#line 2052 "parse.c" break; case 68: -#line 293 "parse.y" -{ yygotominor.yy359.value = yymsp[0].minor.yy280<<8; yygotominor.yy359.mask = 0x00ff00; } -#line 2185 "parse.c" +#line 287 "parse.y" +{ yygotominor.yy13.value = yymsp[0].minor.yy230; yygotominor.yy13.mask = 0x0000ff; } +#line 2057 "parse.c" break; case 69: -#line 294 "parse.y" -{ yygotominor.yy359.value = yymsp[0].minor.yy280<<16; yygotominor.yy359.mask = 0xff0000; } -#line 2190 "parse.c" +#line 288 "parse.y" +{ yygotominor.yy13.value = yymsp[0].minor.yy230<<8; yygotominor.yy13.mask = 0x00ff00; } +#line 2062 "parse.c" break; case 70: -#line 296 "parse.y" -{ yygotominor.yy280 = OE_SetNull; } -#line 2195 "parse.c" +#line 289 "parse.y" +{ yygotominor.yy13.value = yymsp[0].minor.yy230<<16; yygotominor.yy13.mask = 0xff0000; } +#line 2067 "parse.c" break; case 71: -#line 297 "parse.y" -{ yygotominor.yy280 = OE_SetDflt; } -#line 2200 "parse.c" +#line 291 "parse.y" +{ yygotominor.yy230 = OE_SetNull; } +#line 2072 "parse.c" break; case 72: -#line 298 "parse.y" -{ yygotominor.yy280 = OE_Cascade; } -#line 2205 "parse.c" +#line 292 "parse.y" +{ yygotominor.yy230 = OE_SetDflt; } +#line 2077 "parse.c" break; case 73: -#line 299 "parse.y" -{ yygotominor.yy280 = OE_Restrict; } -#line 2210 "parse.c" +#line 293 "parse.y" +{ yygotominor.yy230 = OE_Cascade; } +#line 2082 "parse.c" break; case 74: +#line 294 "parse.y" +{ yygotominor.yy230 = OE_Restrict; } +#line 2087 "parse.c" + break; case 75: - case 90: - case 92: - case 94: + case 76: + case 91: + case 93: case 95: - case 166: -#line 301 "parse.y" -{yygotominor.yy280 = yymsp[0].minor.yy280;} -#line 2221 "parse.c" - break; - case 79: -#line 311 "parse.y" -{yygotominor.yy198.n = 0; yygotominor.yy198.z = 0;} -#line 2226 "parse.c" + case 96: + case 167: +#line 296 "parse.y" +{yygotominor.yy230 = yymsp[0].minor.yy230;} +#line 2098 "parse.c" break; case 80: -#line 312 "parse.y" -{yygotominor.yy198 = yymsp[-1].minor.yy0;} -#line 2231 "parse.c" +#line 306 "parse.y" +{yygotominor.yy384.n = 0; yygotominor.yy384.z = 0;} +#line 2103 "parse.c" break; - case 85: -#line 318 "parse.y" -{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy418,yymsp[0].minor.yy280,yymsp[-2].minor.yy280);} -#line 2236 "parse.c" + case 81: +#line 307 "parse.y" +{yygotominor.yy384 = yymsp[-1].minor.yy0;} +#line 2108 "parse.c" break; case 86: -#line 320 "parse.y" -{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy418,yymsp[0].minor.yy280,0,0);} -#line 2241 "parse.c" +#line 313 "parse.y" +{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy462,yymsp[0].minor.yy230,yymsp[-2].minor.yy230,0);} +#line 2113 "parse.c" + break; + case 87: +#line 315 "parse.y" +{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy462,yymsp[0].minor.yy230,0,0,0,0);} +#line 2118 "parse.c" break; case 88: -#line 323 "parse.y" -{ - sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy418, &yymsp[-3].minor.yy198, yymsp[-2].minor.yy418, yymsp[-1].minor.yy280); - sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy280); -} -#line 2249 "parse.c" - break; - case 91: - case 93: -#line 337 "parse.y" -{yygotominor.yy280 = OE_Default;} -#line 2255 "parse.c" - break; - case 96: -#line 342 "parse.y" -{yygotominor.yy280 = OE_Ignore;} -#line 2260 "parse.c" +#line 316 "parse.y" +{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy178);} +#line 2123 "parse.c" + break; + case 89: +#line 318 "parse.y" +{ + sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy462, &yymsp[-3].minor.yy384, yymsp[-2].minor.yy462, yymsp[-1].minor.yy230); + sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy230); +} +#line 2131 "parse.c" + break; + case 92: + case 94: +#line 332 "parse.y" +{yygotominor.yy230 = OE_Default;} +#line 2137 "parse.c" break; case 97: - case 167: -#line 343 "parse.y" -{yygotominor.yy280 = OE_Replace;} -#line 2266 "parse.c" +#line 337 "parse.y" +{yygotominor.yy230 = OE_Ignore;} +#line 2142 "parse.c" break; case 98: -#line 347 "parse.y" -{ - sqlite3DropTable(pParse, yymsp[0].minor.yy151, 0); -} -#line 2273 "parse.c" + case 168: +#line 338 "parse.y" +{yygotominor.yy230 = OE_Replace;} +#line 2148 "parse.c" break; case 99: -#line 354 "parse.y" -{ - sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy198, &yymsp[-2].minor.yy198, yymsp[0].minor.yy375, yymsp[-5].minor.yy280); -} -#line 2280 "parse.c" - break; - case 100: -#line 357 "parse.y" -{ - sqlite3DropTable(pParse, yymsp[0].minor.yy151, 1); +#line 342 "parse.y" +{ + sqlite3DropTable(pParse, yymsp[0].minor.yy285, 0, yymsp[-1].minor.yy230); +} +#line 2155 "parse.c" + break; + case 102: +#line 352 "parse.y" +{ + sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy384, &yymsp[-2].minor.yy384, yymsp[0].minor.yy239, yymsp[-5].minor.yy230); +} +#line 2162 "parse.c" + break; + case 103: +#line 355 "parse.y" +{ + sqlite3DropTable(pParse, yymsp[0].minor.yy285, 1, yymsp[-1].minor.yy230); +} +#line 2169 "parse.c" + break; + case 104: +#line 362 "parse.y" +{ + sqlite3Select(pParse, yymsp[0].minor.yy239, SRT_Callback, 0, 0, 0, 0, 0); + sqlite3SelectDelete(yymsp[0].minor.yy239); +} +#line 2177 "parse.c" + break; + case 105: + case 128: +#line 372 "parse.y" +{yygotominor.yy239 = yymsp[0].minor.yy239;} +#line 2183 "parse.c" + break; + case 106: +#line 374 "parse.y" +{ + if( yymsp[0].minor.yy239 ){ + yymsp[0].minor.yy239->op = yymsp[-1].minor.yy230; + yymsp[0].minor.yy239->pPrior = yymsp[-2].minor.yy239; + } + yygotominor.yy239 = yymsp[0].minor.yy239; +} +#line 2194 "parse.c" + break; + case 108: +#line 383 "parse.y" +{yygotominor.yy230 = TK_ALL;} +#line 2199 "parse.c" + break; + case 110: +#line 387 "parse.y" +{ + yygotominor.yy239 = sqlite3SelectNew(yymsp[-6].minor.yy462,yymsp[-5].minor.yy285,yymsp[-4].minor.yy178,yymsp[-3].minor.yy462,yymsp[-2].minor.yy178,yymsp[-1].minor.yy462,yymsp[-7].minor.yy230,yymsp[0].minor.yy270.pLimit,yymsp[0].minor.yy270.pOffset); +} +#line 2206 "parse.c" + break; + case 114: + case 235: +#line 408 "parse.y" +{yygotominor.yy462 = yymsp[-1].minor.yy462;} +#line 2212 "parse.c" + break; + case 115: + case 141: + case 151: + case 234: +#line 409 "parse.y" +{yygotominor.yy462 = 0;} +#line 2220 "parse.c" + break; + case 116: +#line 410 "parse.y" +{ + yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-2].minor.yy462,yymsp[-1].minor.yy178,yymsp[0].minor.yy384.n?&yymsp[0].minor.yy384:0); +} +#line 2227 "parse.c" + break; + case 117: +#line 413 "parse.y" +{ + yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-1].minor.yy462, sqlite3Expr(TK_ALL, 0, 0, 0), 0); +} +#line 2234 "parse.c" + break; + case 118: +#line 416 "parse.y" +{ + Expr *pRight = sqlite3Expr(TK_ALL, 0, 0, 0); + Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy384); + yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-3].minor.yy462, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0); +} +#line 2243 "parse.c" + break; + case 121: +#line 428 "parse.y" +{yygotominor.yy384.n = 0;} +#line 2248 "parse.c" + break; + case 122: +#line 440 "parse.y" +{yygotominor.yy285 = sqliteMalloc(sizeof(*yygotominor.yy285));} +#line 2253 "parse.c" + break; + case 123: +#line 441 "parse.y" +{yygotominor.yy285 = yymsp[0].minor.yy285;} +#line 2258 "parse.c" + break; + case 124: +#line 446 "parse.y" +{ + yygotominor.yy285 = yymsp[-1].minor.yy285; + if( yygotominor.yy285 && yygotominor.yy285->nSrc>0 ) yygotominor.yy285->a[yygotominor.yy285->nSrc-1].jointype = yymsp[0].minor.yy230; +} +#line 2266 "parse.c" + break; + case 125: +#line 450 "parse.y" +{yygotominor.yy285 = 0;} +#line 2271 "parse.c" + break; + case 126: +#line 451 "parse.y" +{ + yygotominor.yy285 = sqlite3SrcListAppend(yymsp[-5].minor.yy285,&yymsp[-4].minor.yy384,&yymsp[-3].minor.yy384); + if( yymsp[-2].minor.yy384.n ) sqlite3SrcListAddAlias(yygotominor.yy285,&yymsp[-2].minor.yy384); + if( yymsp[-1].minor.yy178 ){ + if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pOn = yymsp[-1].minor.yy178; } + else { sqlite3ExprDelete(yymsp[-1].minor.yy178); } + } + if( yymsp[0].minor.yy160 ){ + if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pUsing = yymsp[0].minor.yy160; } + else { sqlite3IdListDelete(yymsp[0].minor.yy160); } + } } #line 2287 "parse.c" break; - case 101: -#line 364 "parse.y" -{ - sqlite3Select(pParse, yymsp[0].minor.yy375, SRT_Callback, 0, 0, 0, 0, 0); - sqlite3SelectDelete(yymsp[0].minor.yy375); -} -#line 2295 "parse.c" - break; - case 102: - case 126: -#line 374 "parse.y" -{yygotominor.yy375 = yymsp[0].minor.yy375;} -#line 2301 "parse.c" - break; - case 103: -#line 376 "parse.y" -{ - if( yymsp[0].minor.yy375 ){ - yymsp[0].minor.yy375->op = yymsp[-1].minor.yy280; - yymsp[0].minor.yy375->pPrior = yymsp[-2].minor.yy375; - } - yygotominor.yy375 = yymsp[0].minor.yy375; -} -#line 2312 "parse.c" - break; - case 105: -#line 385 "parse.y" -{yygotominor.yy280 = TK_ALL;} -#line 2317 "parse.c" - break; - case 108: -#line 390 "parse.y" -{ - yygotominor.yy375 = sqlite3SelectNew(yymsp[-6].minor.yy418,yymsp[-5].minor.yy151,yymsp[-4].minor.yy62,yymsp[-3].minor.yy418,yymsp[-2].minor.yy62,yymsp[-1].minor.yy418,yymsp[-7].minor.yy280,yymsp[0].minor.yy220.pLimit,yymsp[0].minor.yy220.pOffset); -} -#line 2324 "parse.c" - break; - case 112: - case 248: -#line 411 "parse.y" -{yygotominor.yy418 = yymsp[-1].minor.yy418;} -#line 2330 "parse.c" - break; - case 113: - case 140: - case 150: - case 247: -#line 412 "parse.y" -{yygotominor.yy418 = 0;} -#line 2338 "parse.c" - break; - case 114: -#line 413 "parse.y" -{ - yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-2].minor.yy418,yymsp[-1].minor.yy62,yymsp[0].minor.yy198.n?&yymsp[0].minor.yy198:0); -} -#line 2345 "parse.c" - break; - case 115: -#line 416 "parse.y" -{ - yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-1].minor.yy418, sqlite3Expr(TK_ALL, 0, 0, 0), 0); -} -#line 2352 "parse.c" - break; - case 116: -#line 419 "parse.y" -{ - Expr *pRight = sqlite3Expr(TK_ALL, 0, 0, 0); - Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy198); - yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-3].minor.yy418, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0); -} -#line 2361 "parse.c" - break; - case 119: -#line 431 "parse.y" -{yygotominor.yy198.n = 0;} -#line 2366 "parse.c" - break; - case 120: -#line 443 "parse.y" -{yygotominor.yy151 = sqliteMalloc(sizeof(*yygotominor.yy151));} + case 127: +#line 465 "parse.y" +{ + yygotominor.yy285 = sqlite3SrcListAppend(yymsp[-6].minor.yy285,0,0); + yygotominor.yy285->a[yygotominor.yy285->nSrc-1].pSelect = yymsp[-4].minor.yy239; + if( yymsp[-2].minor.yy384.n ) sqlite3SrcListAddAlias(yygotominor.yy285,&yymsp[-2].minor.yy384); + if( yymsp[-1].minor.yy178 ){ + if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pOn = yymsp[-1].minor.yy178; } + else { sqlite3ExprDelete(yymsp[-1].minor.yy178); } + } + if( yymsp[0].minor.yy160 ){ + if( yygotominor.yy285 && yygotominor.yy285->nSrc>1 ){ yygotominor.yy285->a[yygotominor.yy285->nSrc-2].pUsing = yymsp[0].minor.yy160; } + else { sqlite3IdListDelete(yymsp[0].minor.yy160); } + } + } +#line 2304 "parse.c" + break; + case 129: +#line 486 "parse.y" +{ + yygotominor.yy239 = sqlite3SelectNew(0,yymsp[0].minor.yy285,0,0,0,0,0,0,0); + } +#line 2311 "parse.c" + break; + case 130: +#line 492 "parse.y" +{yygotominor.yy384.z=0; yygotominor.yy384.n=0;} +#line 2316 "parse.c" + break; + case 132: +#line 497 "parse.y" +{yygotominor.yy285 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384);} +#line 2321 "parse.c" + break; + case 133: +#line 501 "parse.y" +{ yygotominor.yy230 = JT_INNER; } +#line 2326 "parse.c" + break; + case 134: +#line 502 "parse.y" +{ yygotominor.yy230 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); } +#line 2331 "parse.c" + break; + case 135: +#line 503 "parse.y" +{ yygotominor.yy230 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy384,0); } +#line 2336 "parse.c" + break; + case 136: +#line 505 "parse.y" +{ yygotominor.yy230 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy384,&yymsp[-1].minor.yy384); } +#line 2341 "parse.c" + break; + case 137: + case 145: + case 154: + case 161: + case 175: + case 200: + case 223: + case 225: + case 229: +#line 509 "parse.y" +{yygotominor.yy178 = yymsp[0].minor.yy178;} +#line 2354 "parse.c" + break; + case 138: + case 153: + case 160: + case 201: + case 224: + case 226: + case 230: +#line 510 "parse.y" +{yygotominor.yy178 = 0;} +#line 2365 "parse.c" + break; + case 139: + case 172: +#line 514 "parse.y" +{yygotominor.yy160 = yymsp[-1].minor.yy160;} #line 2371 "parse.c" break; - case 121: -#line 444 "parse.y" -{yygotominor.yy151 = yymsp[0].minor.yy151;} -#line 2376 "parse.c" - break; - case 122: -#line 449 "parse.y" -{ - yygotominor.yy151 = yymsp[-1].minor.yy151; - if( yygotominor.yy151 && yygotominor.yy151->nSrc>0 ) yygotominor.yy151->a[yygotominor.yy151->nSrc-1].jointype = yymsp[0].minor.yy280; -} -#line 2384 "parse.c" - break; - case 123: -#line 453 "parse.y" -{yygotominor.yy151 = 0;} -#line 2389 "parse.c" - break; - case 124: -#line 454 "parse.y" -{ - yygotominor.yy151 = sqlite3SrcListAppend(yymsp[-5].minor.yy151,&yymsp[-4].minor.yy198,&yymsp[-3].minor.yy198); - if( yymsp[-2].minor.yy198.n ) sqlite3SrcListAddAlias(yygotominor.yy151,&yymsp[-2].minor.yy198); - if( yymsp[-1].minor.yy62 ){ - if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pOn = yymsp[-1].minor.yy62; } - else { sqlite3ExprDelete(yymsp[-1].minor.yy62); } - } - if( yymsp[0].minor.yy240 ){ - if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pUsing = yymsp[0].minor.yy240; } - else { sqlite3IdListDelete(yymsp[0].minor.yy240); } - } -} + case 140: + case 171: +#line 515 "parse.y" +{yygotominor.yy160 = 0;} +#line 2377 "parse.c" + break; + case 142: + case 152: +#line 526 "parse.y" +{yygotominor.yy462 = yymsp[0].minor.yy462;} +#line 2383 "parse.c" + break; + case 143: +#line 527 "parse.y" +{ + yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462,yymsp[-2].minor.yy178,yymsp[-1].minor.yy384.n>0?&yymsp[-1].minor.yy384:0); + if( yygotominor.yy462 ) yygotominor.yy462->a[yygotominor.yy462->nExpr-1].sortOrder = yymsp[0].minor.yy230; +} +#line 2391 "parse.c" + break; + case 144: +#line 531 "parse.y" +{ + yygotominor.yy462 = sqlite3ExprListAppend(0,yymsp[-2].minor.yy178,yymsp[-1].minor.yy384.n>0?&yymsp[-1].minor.yy384:0); + if( yygotominor.yy462 && yygotominor.yy462->a ) yygotominor.yy462->a[0].sortOrder = yymsp[0].minor.yy230; +} +#line 2399 "parse.c" + break; + case 146: + case 148: +#line 540 "parse.y" +{yygotominor.yy230 = SQLITE_SO_ASC;} #line 2405 "parse.c" break; - case 125: -#line 468 "parse.y" -{ - yygotominor.yy151 = sqlite3SrcListAppend(yymsp[-6].minor.yy151,0,0); - yygotominor.yy151->a[yygotominor.yy151->nSrc-1].pSelect = yymsp[-4].minor.yy375; - if( yymsp[-2].minor.yy198.n ) sqlite3SrcListAddAlias(yygotominor.yy151,&yymsp[-2].minor.yy198); - if( yymsp[-1].minor.yy62 ){ - if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pOn = yymsp[-1].minor.yy62; } - else { sqlite3ExprDelete(yymsp[-1].minor.yy62); } - } - if( yymsp[0].minor.yy240 ){ - if( yygotominor.yy151 && yygotominor.yy151->nSrc>1 ){ yygotominor.yy151->a[yygotominor.yy151->nSrc-2].pUsing = yymsp[0].minor.yy240; } - else { sqlite3IdListDelete(yymsp[0].minor.yy240); } - } - } -#line 2422 "parse.c" - break; - case 127: -#line 489 "parse.y" -{ - yygotominor.yy375 = sqlite3SelectNew(0,yymsp[0].minor.yy151,0,0,0,0,0,0,0); - } -#line 2429 "parse.c" - break; - case 128: -#line 495 "parse.y" -{yygotominor.yy198.z=0; yygotominor.yy198.n=0;} -#line 2434 "parse.c" - break; - case 130: -#line 500 "parse.y" -{yygotominor.yy151 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198);} -#line 2439 "parse.c" - break; - case 131: - case 132: -#line 504 "parse.y" -{ yygotominor.yy280 = JT_INNER; } + case 147: +#line 541 "parse.y" +{yygotominor.yy230 = SQLITE_SO_DESC;} +#line 2410 "parse.c" + break; + case 149: +#line 543 "parse.y" +{yygotominor.yy384.z = 0; yygotominor.yy384.n = 0;} +#line 2415 "parse.c" + break; + case 155: +#line 561 "parse.y" +{yygotominor.yy270.pLimit = 0; yygotominor.yy270.pOffset = 0;} +#line 2420 "parse.c" + break; + case 156: +#line 562 "parse.y" +{yygotominor.yy270.pLimit = yymsp[0].minor.yy178; yygotominor.yy270.pOffset = 0;} +#line 2425 "parse.c" + break; + case 157: +#line 564 "parse.y" +{yygotominor.yy270.pLimit = yymsp[-2].minor.yy178; yygotominor.yy270.pOffset = yymsp[0].minor.yy178;} +#line 2430 "parse.c" + break; + case 158: +#line 566 "parse.y" +{yygotominor.yy270.pOffset = yymsp[-2].minor.yy178; yygotominor.yy270.pLimit = yymsp[0].minor.yy178;} +#line 2435 "parse.c" + break; + case 159: +#line 570 "parse.y" +{sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy285,yymsp[0].minor.yy178);} +#line 2440 "parse.c" + break; + case 162: +#line 581 "parse.y" +{sqlite3Update(pParse,yymsp[-3].minor.yy285,yymsp[-1].minor.yy462,yymsp[0].minor.yy178,yymsp[-4].minor.yy230);} #line 2445 "parse.c" break; - case 133: -#line 506 "parse.y" -{ yygotominor.yy280 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); } + case 163: +#line 587 "parse.y" +{yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462,yymsp[0].minor.yy178,&yymsp[-2].minor.yy384);} #line 2450 "parse.c" break; - case 134: -#line 507 "parse.y" -{ yygotominor.yy280 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy198,0); } + case 164: +#line 588 "parse.y" +{yygotominor.yy462 = sqlite3ExprListAppend(0,yymsp[0].minor.yy178,&yymsp[-2].minor.yy384);} #line 2455 "parse.c" break; - case 135: -#line 509 "parse.y" -{ yygotominor.yy280 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy198,&yymsp[-1].minor.yy198); } + case 165: +#line 594 "parse.y" +{sqlite3Insert(pParse, yymsp[-5].minor.yy285, yymsp[-1].minor.yy462, 0, yymsp[-4].minor.yy160, yymsp[-7].minor.yy230);} #line 2460 "parse.c" break; - case 136: - case 144: - case 153: - case 160: - case 174: - case 211: - case 236: - case 238: - case 242: -#line 513 "parse.y" -{yygotominor.yy62 = yymsp[0].minor.yy62;} -#line 2473 "parse.c" - break; - case 137: - case 152: - case 159: - case 212: - case 237: - case 239: - case 243: -#line 514 "parse.y" -{yygotominor.yy62 = 0;} -#line 2484 "parse.c" - break; - case 138: - case 171: -#line 518 "parse.y" -{yygotominor.yy240 = yymsp[-1].minor.yy240;} -#line 2490 "parse.c" - break; - case 139: - case 170: -#line 519 "parse.y" -{yygotominor.yy240 = 0;} -#line 2496 "parse.c" - break; - case 141: - case 151: -#line 530 "parse.y" -{yygotominor.yy418 = yymsp[0].minor.yy418;} -#line 2502 "parse.c" - break; - case 142: -#line 531 "parse.y" -{ - yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418,yymsp[-2].minor.yy62,yymsp[-1].minor.yy198.n>0?&yymsp[-1].minor.yy198:0); - if( yygotominor.yy418 ) yygotominor.yy418->a[yygotominor.yy418->nExpr-1].sortOrder = yymsp[0].minor.yy280; -} -#line 2510 "parse.c" - break; - case 143: -#line 535 "parse.y" -{ - yygotominor.yy418 = sqlite3ExprListAppend(0,yymsp[-2].minor.yy62,yymsp[-1].minor.yy198.n>0?&yymsp[-1].minor.yy198:0); - if( yygotominor.yy418 && yygotominor.yy418->a ) yygotominor.yy418->a[0].sortOrder = yymsp[0].minor.yy280; -} -#line 2518 "parse.c" - break; - case 145: - case 147: -#line 544 "parse.y" -{yygotominor.yy280 = SQLITE_SO_ASC;} -#line 2524 "parse.c" - break; - case 146: -#line 545 "parse.y" -{yygotominor.yy280 = SQLITE_SO_DESC;} -#line 2529 "parse.c" - break; - case 148: -#line 547 "parse.y" -{yygotominor.yy198.z = 0; yygotominor.yy198.n = 0;} -#line 2534 "parse.c" - break; - case 154: -#line 565 "parse.y" -{yygotominor.yy220.pLimit = 0; yygotominor.yy220.pOffset = 0;} -#line 2539 "parse.c" - break; - case 155: -#line 566 "parse.y" -{yygotominor.yy220.pLimit = yymsp[0].minor.yy62; yygotominor.yy220.pOffset = 0;} -#line 2544 "parse.c" - break; - case 156: -#line 568 "parse.y" -{yygotominor.yy220.pLimit = yymsp[-2].minor.yy62; yygotominor.yy220.pOffset = yymsp[0].minor.yy62;} -#line 2549 "parse.c" - break; - case 157: -#line 570 "parse.y" -{yygotominor.yy220.pOffset = yymsp[-2].minor.yy62; yygotominor.yy220.pLimit = yymsp[0].minor.yy62;} -#line 2554 "parse.c" - break; - case 158: -#line 574 "parse.y" -{sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy151,yymsp[0].minor.yy62);} -#line 2559 "parse.c" - break; - case 161: -#line 585 "parse.y" -{sqlite3Update(pParse,yymsp[-3].minor.yy151,yymsp[-1].minor.yy418,yymsp[0].minor.yy62,yymsp[-4].minor.yy280);} -#line 2564 "parse.c" - break; - case 162: -#line 591 "parse.y" -{yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418,yymsp[0].minor.yy62,&yymsp[-2].minor.yy198);} -#line 2569 "parse.c" - break; - case 163: -#line 592 "parse.y" -{yygotominor.yy418 = sqlite3ExprListAppend(0,yymsp[0].minor.yy62,&yymsp[-2].minor.yy198);} -#line 2574 "parse.c" - break; - case 164: -#line 598 "parse.y" -{sqlite3Insert(pParse, yymsp[-5].minor.yy151, yymsp[-1].minor.yy418, 0, yymsp[-4].minor.yy240, yymsp[-7].minor.yy280);} -#line 2579 "parse.c" - break; - case 165: -#line 600 "parse.y" -{sqlite3Insert(pParse, yymsp[-2].minor.yy151, 0, yymsp[0].minor.yy375, yymsp[-1].minor.yy240, yymsp[-4].minor.yy280);} -#line 2584 "parse.c" - break; - case 168: - case 240: -#line 610 "parse.y" -{yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-2].minor.yy418,yymsp[0].minor.yy62,0);} -#line 2590 "parse.c" + case 166: +#line 596 "parse.y" +{sqlite3Insert(pParse, yymsp[-2].minor.yy285, 0, yymsp[0].minor.yy239, yymsp[-1].minor.yy160, yymsp[-4].minor.yy230);} +#line 2465 "parse.c" break; case 169: - case 241: -#line 611 "parse.y" -{yygotominor.yy418 = sqlite3ExprListAppend(0,yymsp[0].minor.yy62,0);} -#line 2596 "parse.c" + case 227: +#line 606 "parse.y" +{yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-2].minor.yy462,yymsp[0].minor.yy178,0);} +#line 2471 "parse.c" break; - case 172: -#line 620 "parse.y" -{yygotominor.yy240 = sqlite3IdListAppend(yymsp[-2].minor.yy240,&yymsp[0].minor.yy198);} -#line 2601 "parse.c" + case 170: + case 228: +#line 607 "parse.y" +{yygotominor.yy462 = sqlite3ExprListAppend(0,yymsp[0].minor.yy178,0);} +#line 2477 "parse.c" break; case 173: -#line 621 "parse.y" -{yygotominor.yy240 = sqlite3IdListAppend(0,&yymsp[0].minor.yy198);} -#line 2606 "parse.c" +#line 616 "parse.y" +{yygotominor.yy160 = sqlite3IdListAppend(yymsp[-2].minor.yy160,&yymsp[0].minor.yy384);} +#line 2482 "parse.c" break; - case 175: -#line 632 "parse.y" -{yygotominor.yy62 = yymsp[-1].minor.yy62; sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); } -#line 2611 "parse.c" + case 174: +#line 617 "parse.y" +{yygotominor.yy160 = sqlite3IdListAppend(0,&yymsp[0].minor.yy384);} +#line 2487 "parse.c" break; case 176: - case 181: - case 182: - case 183: - case 184: -#line 633 "parse.y" -{yygotominor.yy62 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);} -#line 2620 "parse.c" +#line 628 "parse.y" +{yygotominor.yy178 = yymsp[-1].minor.yy178; sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); } +#line 2492 "parse.c" break; case 177: + case 182: + case 183: +#line 629 "parse.y" +{yygotominor.yy178 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);} +#line 2499 "parse.c" + break; case 178: -#line 634 "parse.y" -{yygotominor.yy62 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);} -#line 2626 "parse.c" - break; case 179: -#line 636 "parse.y" -{ - Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy198); - Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy198); - yygotominor.yy62 = sqlite3Expr(TK_DOT, temp1, temp2, 0); -} -#line 2635 "parse.c" +#line 630 "parse.y" +{yygotominor.yy178 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);} +#line 2505 "parse.c" break; case 180: -#line 641 "parse.y" +#line 632 "parse.y" +{ + Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy384); + Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy384); + yygotominor.yy178 = sqlite3Expr(TK_DOT, temp1, temp2, 0); +} +#line 2514 "parse.c" + break; + case 181: +#line 637 "parse.y" { - Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-4].minor.yy198); - Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy198); - Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy198); + Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-4].minor.yy384); + Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy384); + Expr *temp3 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy384); Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0); - yygotominor.yy62 = sqlite3Expr(TK_DOT, temp1, temp4, 0); + yygotominor.yy178 = sqlite3Expr(TK_DOT, temp1, temp4, 0); } -#line 2646 "parse.c" +#line 2525 "parse.c" + break; + case 184: +#line 646 "parse.y" +{yygotominor.yy178 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);} +#line 2530 "parse.c" break; case 185: -#line 652 "parse.y" -{yygotominor.yy62 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);} -#line 2651 "parse.c" +#line 647 "parse.y" +{ + Token *pToken = &yymsp[0].minor.yy0; + Expr *pExpr = yygotominor.yy178 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken); + sqlite3ExprAssignVarNumber(pParse, pExpr); +} +#line 2539 "parse.c" break; case 186: #line 653 "parse.y" { - Token *pToken = &yymsp[0].minor.yy0; - Expr *pExpr = yygotominor.yy62 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken); - sqlite3ExprAssignVarNumber(pParse, pExpr); + yygotominor.yy178 = sqlite3Expr(TK_CAST, yymsp[-3].minor.yy178, 0, &yymsp[-1].minor.yy384); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); } -#line 2660 "parse.c" +#line 2547 "parse.c" break; case 187: -#line 659 "parse.y" +#line 658 "parse.y" { - yygotominor.yy62 = sqlite3Expr(TK_CAST, yymsp[-3].minor.yy62, 0, &yymsp[-1].minor.yy198); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); + yygotominor.yy178 = sqlite3ExprFunction(yymsp[-1].minor.yy462, &yymsp[-4].minor.yy0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); + if( yymsp[-2].minor.yy230 ){ + yygotominor.yy178->flags |= EP_Distinct; + } } -#line 2668 "parse.c" +#line 2558 "parse.c" break; case 188: -#line 664 "parse.y" -{ - yygotominor.yy62 = sqlite3ExprFunction(yymsp[-1].minor.yy418, &yymsp[-4].minor.yy0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0); - if( yymsp[-2].minor.yy280 ){ - yygotominor.yy62->flags |= EP_Distinct; - } -} -#line 2679 "parse.c" +#line 665 "parse.y" +{ + yygotominor.yy178 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); +} +#line 2566 "parse.c" break; case 189: -#line 671 "parse.y" -{ - yygotominor.yy62 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); -} -#line 2687 "parse.c" - break; - case 190: -#line 675 "parse.y" +#line 669 "parse.y" { /* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are ** treated as functions that return constants */ - yygotominor.yy62 = sqlite3ExprFunction(0,&yymsp[0].minor.yy0); - if( yygotominor.yy62 ) yygotominor.yy62->op = TK_CONST_FUNC; + yygotominor.yy178 = sqlite3ExprFunction(0,&yymsp[0].minor.yy0); + if( yygotominor.yy178 ) yygotominor.yy178->op = TK_CONST_FUNC; } -#line 2697 "parse.c" +#line 2576 "parse.c" break; + case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: +#line 675 "parse.y" +{yygotominor.yy178 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy178, yymsp[0].minor.yy178, 0);} +#line 2588 "parse.c" + break; case 198: +#line 685 "parse.y" +{yygotominor.yy440.operator = yymsp[0].minor.yy0; yygotominor.yy440.not = 0;} +#line 2593 "parse.c" + break; case 199: - case 200: - case 201: +#line 686 "parse.y" +{yygotominor.yy440.operator = yymsp[0].minor.yy0; yygotominor.yy440.not = 1;} +#line 2598 "parse.c" + break; case 202: +#line 691 "parse.y" +{ + ExprList *pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy178, 0); + pList = sqlite3ExprListAppend(pList, yymsp[-3].minor.yy178, 0); + if( yymsp[0].minor.yy178 ){ + pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy178, 0); + } + yygotominor.yy178 = sqlite3ExprFunction(pList, &yymsp[-2].minor.yy440.operator); + if( yymsp[-2].minor.yy440.not ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178, &yymsp[-3].minor.yy178->span, &yymsp[-1].minor.yy178->span); +} +#line 2612 "parse.c" + break; case 203: +#line 702 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(yymsp[0].major, yymsp[-1].minor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy178->span,&yymsp[0].minor.yy0); +} +#line 2620 "parse.c" + break; case 204: +#line 706 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy178->span,&yymsp[0].minor.yy0); +} +#line 2628 "parse.c" + break; case 205: +#line 710 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy178->span,&yymsp[0].minor.yy0); +} +#line 2636 "parse.c" + break; case 206: +#line 714 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-3].minor.yy178->span,&yymsp[0].minor.yy0); +} +#line 2644 "parse.c" + break; case 207: +#line 718 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy178->span); +} +#line 2652 "parse.c" + break; case 208: -#line 681 "parse.y" -{yygotominor.yy62 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy62, yymsp[0].minor.yy62, 0);} -#line 2719 "parse.c" +#line 722 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy178->span); +} +#line 2660 "parse.c" break; case 209: -#line 700 "parse.y" -{yygotominor.yy222.operator = yymsp[0].minor.yy0; yygotominor.yy222.not = 0;} -#line 2724 "parse.c" - break; - case 210: -#line 701 "parse.y" -{yygotominor.yy222.operator = yymsp[0].minor.yy0; yygotominor.yy222.not = 1;} -#line 2729 "parse.c" - break; - case 213: -#line 705 "parse.y" -{ - ExprList *pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy62, 0); - pList = sqlite3ExprListAppend(pList, yymsp[-3].minor.yy62, 0); - if( yymsp[0].minor.yy62 ){ - pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy62, 0); - } - yygotominor.yy62 = sqlite3ExprFunction(pList, &yymsp[-2].minor.yy222.operator); - if( yymsp[-2].minor.yy222.not ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62, &yymsp[-3].minor.yy62->span, &yymsp[-1].minor.yy62->span); -} -#line 2743 "parse.c" - break; - case 214: -#line 716 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_ISNULL, yymsp[-1].minor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy62->span,&yymsp[0].minor.yy0); -} -#line 2751 "parse.c" - break; - case 215: -#line 720 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy62->span,&yymsp[0].minor.yy0); -} -#line 2759 "parse.c" - break; - case 216: -#line 724 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_NOTNULL, yymsp[-1].minor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy62->span,&yymsp[0].minor.yy0); -} -#line 2767 "parse.c" - break; - case 217: -#line 728 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy62->span,&yymsp[0].minor.yy0); -} -#line 2775 "parse.c" - break; - case 218: -#line 732 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-3].minor.yy62->span,&yymsp[0].minor.yy0); -} -#line 2783 "parse.c" - break; - case 219: - case 220: -#line 736 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy62->span); -} -#line 2792 "parse.c" - break; - case 221: -#line 744 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy62->span); -} -#line 2800 "parse.c" - break; - case 222: -#line 748 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy62->span); -} -#line 2808 "parse.c" - break; - case 225: -#line 755 "parse.y" -{ - ExprList *pList = sqlite3ExprListAppend(0, yymsp[-2].minor.yy62, 0); - pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy62, 0); - yygotominor.yy62 = sqlite3Expr(TK_BETWEEN, yymsp[-4].minor.yy62, 0, 0); - if( yygotominor.yy62 ){ - yygotominor.yy62->pList = pList; +#line 726 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy178->span); +} +#line 2668 "parse.c" + break; + case 212: +#line 733 "parse.y" +{ + ExprList *pList = sqlite3ExprListAppend(0, yymsp[-2].minor.yy178, 0); + pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy178, 0); + yygotominor.yy178 = sqlite3Expr(TK_BETWEEN, yymsp[-4].minor.yy178, 0, 0); + if( yygotominor.yy178 ){ + yygotominor.yy178->pList = pList; }else{ sqlite3ExprListDelete(pList); } - if( yymsp[-3].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy62->span,&yymsp[0].minor.yy62->span); -} -#line 2824 "parse.c" - break; - case 228: -#line 771 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy62, 0, 0); - if( yygotominor.yy62 ){ - yygotominor.yy62->pList = yymsp[-1].minor.yy418; - }else{ - sqlite3ExprListDelete(yymsp[-1].minor.yy418); - } - if( yymsp[-3].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy62->span,&yymsp[0].minor.yy0); - } -#line 2838 "parse.c" - break; - case 229: -#line 781 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_SELECT, 0, 0, 0); - if( yygotominor.yy62 ){ - yygotominor.yy62->pSelect = yymsp[-1].minor.yy375; - }else{ - sqlite3SelectDelete(yymsp[-1].minor.yy375); - } - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); - } -#line 2851 "parse.c" - break; - case 230: -#line 790 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy62, 0, 0); - if( yygotominor.yy62 ){ - yygotominor.yy62->pSelect = yymsp[-1].minor.yy375; - }else{ - sqlite3SelectDelete(yymsp[-1].minor.yy375); - } - if( yymsp[-3].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-4].minor.yy62->span,&yymsp[0].minor.yy0); - } -#line 2865 "parse.c" - break; - case 231: -#line 800 "parse.y" -{ - SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198); - yygotominor.yy62 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy62, 0, 0); - if( yygotominor.yy62 ){ - yygotominor.yy62->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0); + if( yymsp[-3].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy178->span,&yymsp[0].minor.yy178->span); +} +#line 2684 "parse.c" + break; + case 215: +#line 749 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy178, 0, 0); + if( yygotominor.yy178 ){ + yygotominor.yy178->pList = yymsp[-1].minor.yy462; + }else{ + sqlite3ExprListDelete(yymsp[-1].minor.yy462); + } + if( yymsp[-3].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy178->span,&yymsp[0].minor.yy0); + } +#line 2698 "parse.c" + break; + case 216: +#line 759 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(TK_SELECT, 0, 0, 0); + if( yygotominor.yy178 ){ + yygotominor.yy178->pSelect = yymsp[-1].minor.yy239; + }else{ + sqlite3SelectDelete(yymsp[-1].minor.yy239); + } + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); + } +#line 2711 "parse.c" + break; + case 217: +#line 768 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy178, 0, 0); + if( yygotominor.yy178 ){ + yygotominor.yy178->pSelect = yymsp[-1].minor.yy239; + }else{ + sqlite3SelectDelete(yymsp[-1].minor.yy239); + } + if( yymsp[-3].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-4].minor.yy178->span,&yymsp[0].minor.yy0); + } +#line 2725 "parse.c" + break; + case 218: +#line 778 "parse.y" +{ + SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384); + yygotominor.yy178 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy178, 0, 0); + if( yygotominor.yy178 ){ + yygotominor.yy178->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0); }else{ sqlite3SrcListDelete(pSrc); } - if( yymsp[-2].minor.yy280 ) yygotominor.yy62 = sqlite3Expr(TK_NOT, yygotominor.yy62, 0, 0); - sqlite3ExprSpan(yygotominor.yy62,&yymsp[-3].minor.yy62->span,yymsp[0].minor.yy198.z?&yymsp[0].minor.yy198:&yymsp[-1].minor.yy198); - } -#line 2880 "parse.c" - break; - case 232: -#line 811 "parse.y" -{ - Expr *p = yygotominor.yy62 = sqlite3Expr(TK_EXISTS, 0, 0, 0); - if( p ){ - p->pSelect = yymsp[-1].minor.yy375; - sqlite3ExprSpan(p,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); - }else{ - sqlite3SelectDelete(yymsp[-1].minor.yy375); - } - } -#line 2893 "parse.c" - break; - case 233: -#line 823 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy62, yymsp[-1].minor.yy62, 0); - if( yygotominor.yy62 ){ - yygotominor.yy62->pList = yymsp[-2].minor.yy418; - }else{ - sqlite3ExprListDelete(yymsp[-2].minor.yy418); - } - sqlite3ExprSpan(yygotominor.yy62, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0); -} -#line 2906 "parse.c" - break; - case 234: -#line 834 "parse.y" -{ - yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418, yymsp[-2].minor.yy62, 0); - yygotominor.yy418 = sqlite3ExprListAppend(yygotominor.yy418, yymsp[0].minor.yy62, 0); -} -#line 2914 "parse.c" - break; - case 235: -#line 838 "parse.y" -{ - yygotominor.yy418 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy62, 0); - yygotominor.yy418 = sqlite3ExprListAppend(yygotominor.yy418, yymsp[0].minor.yy62, 0); -} -#line 2922 "parse.c" - break; - case 244: -#line 863 "parse.y" -{ - if( yymsp[-9].minor.yy280!=OE_None ) yymsp[-9].minor.yy280 = yymsp[0].minor.yy280; - if( yymsp[-9].minor.yy280==OE_Default) yymsp[-9].minor.yy280 = OE_Abort; - sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy198, &yymsp[-6].minor.yy198, sqlite3SrcListAppend(0,&yymsp[-4].minor.yy198,0),yymsp[-2].minor.yy418,yymsp[-9].minor.yy280, &yymsp[-10].minor.yy0, &yymsp[-1].minor.yy0); -} -#line 2931 "parse.c" - break; - case 245: - case 292: -#line 870 "parse.y" -{yygotominor.yy280 = OE_Abort;} -#line 2937 "parse.c" - break; - case 246: -#line 871 "parse.y" -{yygotominor.yy280 = OE_None;} -#line 2942 "parse.c" - break; - case 249: -#line 881 "parse.y" -{ - Expr *p = 0; - if( yymsp[-1].minor.yy198.n>0 ){ - p = sqlite3Expr(TK_COLUMN, 0, 0, 0); - if( p ) p->pColl = sqlite3LocateCollSeq(pParse, yymsp[-1].minor.yy198.z, yymsp[-1].minor.yy198.n); - } - yygotominor.yy418 = sqlite3ExprListAppend(yymsp[-4].minor.yy418, p, &yymsp[-2].minor.yy198); -} -#line 2954 "parse.c" - break; - case 250: -#line 889 "parse.y" -{ - Expr *p = 0; - if( yymsp[-1].minor.yy198.n>0 ){ - p = sqlite3Expr(TK_COLUMN, 0, 0, 0); - if( p ) p->pColl = sqlite3LocateCollSeq(pParse, yymsp[-1].minor.yy198.z, yymsp[-1].minor.yy198.n); - } - yygotominor.yy418 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy198); -} -#line 2966 "parse.c" - break; - case 252: -#line 902 "parse.y" -{sqlite3DropIndex(pParse, yymsp[0].minor.yy151);} -#line 2971 "parse.c" - break; - case 253: - case 254: -#line 906 "parse.y" -{sqlite3Vacuum(pParse,0);} -#line 2977 "parse.c" - break; - case 255: - case 257: -#line 912 "parse.y" -{sqlite3Pragma(pParse,&yymsp[-3].minor.yy198,&yymsp[-2].minor.yy198,&yymsp[0].minor.yy198,0);} -#line 2983 "parse.c" - break; - case 256: -#line 913 "parse.y" -{sqlite3Pragma(pParse,&yymsp[-3].minor.yy198,&yymsp[-2].minor.yy198,&yymsp[0].minor.yy0,0);} -#line 2988 "parse.c" - break; - case 258: -#line 915 "parse.y" -{ - sqlite3Pragma(pParse,&yymsp[-3].minor.yy198,&yymsp[-2].minor.yy198,&yymsp[0].minor.yy198,1); -} -#line 2995 "parse.c" - break; - case 259: -#line 918 "parse.y" -{sqlite3Pragma(pParse,&yymsp[-4].minor.yy198,&yymsp[-3].minor.yy198,&yymsp[-1].minor.yy198,0);} -#line 3000 "parse.c" - break; - case 260: -#line 919 "parse.y" -{sqlite3Pragma(pParse,&yymsp[-1].minor.yy198,&yymsp[0].minor.yy198,0,0);} -#line 3005 "parse.c" - break; - case 267: -#line 932 "parse.y" + if( yymsp[-2].minor.yy230 ) yygotominor.yy178 = sqlite3Expr(TK_NOT, yygotominor.yy178, 0, 0); + sqlite3ExprSpan(yygotominor.yy178,&yymsp[-3].minor.yy178->span,yymsp[0].minor.yy384.z?&yymsp[0].minor.yy384:&yymsp[-1].minor.yy384); + } +#line 2740 "parse.c" + break; + case 219: +#line 789 "parse.y" +{ + Expr *p = yygotominor.yy178 = sqlite3Expr(TK_EXISTS, 0, 0, 0); + if( p ){ + p->pSelect = yymsp[-1].minor.yy239; + sqlite3ExprSpan(p,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); + }else{ + sqlite3SelectDelete(yymsp[-1].minor.yy239); + } + } +#line 2753 "parse.c" + break; + case 220: +#line 801 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy178, yymsp[-1].minor.yy178, 0); + if( yygotominor.yy178 ){ + yygotominor.yy178->pList = yymsp[-2].minor.yy462; + }else{ + sqlite3ExprListDelete(yymsp[-2].minor.yy462); + } + sqlite3ExprSpan(yygotominor.yy178, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0); +} +#line 2766 "parse.c" + break; + case 221: +#line 812 "parse.y" +{ + yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462, yymsp[-2].minor.yy178, 0); + yygotominor.yy462 = sqlite3ExprListAppend(yygotominor.yy462, yymsp[0].minor.yy178, 0); +} +#line 2774 "parse.c" + break; + case 222: +#line 816 "parse.y" +{ + yygotominor.yy462 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy178, 0); + yygotominor.yy462 = sqlite3ExprListAppend(yygotominor.yy462, yymsp[0].minor.yy178, 0); +} +#line 2782 "parse.c" + break; + case 231: +#line 843 "parse.y" +{ + if( yymsp[-10].minor.yy230!=OE_None ) yymsp[-10].minor.yy230 = yymsp[0].minor.yy230; + if( yymsp[-10].minor.yy230==OE_Default) yymsp[-10].minor.yy230 = OE_Abort; + sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy384, &yymsp[-6].minor.yy384, sqlite3SrcListAppend(0,&yymsp[-4].minor.yy384,0), yymsp[-2].minor.yy462, yymsp[-10].minor.yy230, + &yymsp[-11].minor.yy0, &yymsp[-1].minor.yy0, SQLITE_SO_ASC, yymsp[-8].minor.yy230); +} +#line 2792 "parse.c" + break; + case 232: + case 277: +#line 851 "parse.y" +{yygotominor.yy230 = OE_Abort;} +#line 2798 "parse.c" + break; + case 233: +#line 852 "parse.y" +{yygotominor.yy230 = OE_None;} +#line 2803 "parse.c" + break; + case 236: +#line 862 "parse.y" +{ + Expr *p = 0; + if( yymsp[-1].minor.yy384.n>0 ){ + p = sqlite3Expr(TK_COLUMN, 0, 0, 0); + if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy384.z, yymsp[-1].minor.yy384.n); + } + yygotominor.yy462 = sqlite3ExprListAppend(yymsp[-4].minor.yy462, p, &yymsp[-2].minor.yy384); + if( yygotominor.yy462 ) yygotominor.yy462->a[yygotominor.yy462->nExpr-1].sortOrder = yymsp[0].minor.yy230; +} +#line 2816 "parse.c" + break; + case 237: +#line 871 "parse.y" +{ + Expr *p = 0; + if( yymsp[-1].minor.yy384.n>0 ){ + p = sqlite3Expr(TK_COLUMN, 0, 0, 0); + if( p ) p->pColl = sqlite3LocateCollSeq(pParse, (char*)yymsp[-1].minor.yy384.z, yymsp[-1].minor.yy384.n); + } + yygotominor.yy462 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy384); + if( yygotominor.yy462 ) yygotominor.yy462->a[yygotominor.yy462->nExpr-1].sortOrder = yymsp[0].minor.yy230; +} +#line 2829 "parse.c" + break; + case 239: +#line 885 "parse.y" +{sqlite3DropIndex(pParse, yymsp[0].minor.yy285, yymsp[-1].minor.yy230);} +#line 2834 "parse.c" + break; + case 240: + case 241: +#line 889 "parse.y" +{sqlite3Vacuum(pParse,0);} +#line 2840 "parse.c" + break; + case 242: + case 244: +#line 895 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-3].minor.yy384,&yymsp[-2].minor.yy384,&yymsp[0].minor.yy384,0);} +#line 2846 "parse.c" + break; + case 243: +#line 896 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-3].minor.yy384,&yymsp[-2].minor.yy384,&yymsp[0].minor.yy0,0);} +#line 2851 "parse.c" + break; + case 245: +#line 898 "parse.y" +{ + sqlite3Pragma(pParse,&yymsp[-3].minor.yy384,&yymsp[-2].minor.yy384,&yymsp[0].minor.yy384,1); +} +#line 2858 "parse.c" + break; + case 246: +#line 901 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-4].minor.yy384,&yymsp[-3].minor.yy384,&yymsp[-1].minor.yy384,0);} +#line 2863 "parse.c" + break; + case 247: +#line 902 "parse.y" +{sqlite3Pragma(pParse,&yymsp[-1].minor.yy384,&yymsp[0].minor.yy384,0,0);} +#line 2868 "parse.c" + break; + case 253: +#line 914 "parse.y" { Token all; - all.z = yymsp[-3].minor.yy198.z; - all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy198.z) + yymsp[0].minor.yy0.n; - sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy360, &all); + all.z = yymsp[-3].minor.yy384.z; + all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy384.z) + yymsp[0].minor.yy0.n; + sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy247, &all); +} +#line 2878 "parse.c" + break; + case 254: +#line 923 "parse.y" +{ + sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy384, &yymsp[-6].minor.yy384, yymsp[-5].minor.yy230, yymsp[-4].minor.yy132.a, yymsp[-4].minor.yy132.b, yymsp[-2].minor.yy285, yymsp[-1].minor.yy230, yymsp[0].minor.yy178, yymsp[-9].minor.yy230); + yygotominor.yy384 = (yymsp[-6].minor.yy384.n==0?yymsp[-7].minor.yy384:yymsp[-6].minor.yy384); +} +#line 2886 "parse.c" + break; + case 255: + case 258: +#line 929 "parse.y" +{ yygotominor.yy230 = TK_BEFORE; } +#line 2892 "parse.c" + break; + case 256: +#line 930 "parse.y" +{ yygotominor.yy230 = TK_AFTER; } +#line 2897 "parse.c" + break; + case 257: +#line 931 "parse.y" +{ yygotominor.yy230 = TK_INSTEAD;} +#line 2902 "parse.c" + break; + case 259: + case 260: +#line 936 "parse.y" +{yygotominor.yy132.a = yymsp[0].major; yygotominor.yy132.b = 0;} +#line 2908 "parse.c" + break; + case 261: +#line 938 "parse.y" +{yygotominor.yy132.a = TK_UPDATE; yygotominor.yy132.b = yymsp[0].minor.yy160;} +#line 2913 "parse.c" + break; + case 262: + case 263: +#line 941 "parse.y" +{ yygotominor.yy230 = TK_ROW; } +#line 2919 "parse.c" + break; + case 264: +#line 943 "parse.y" +{ yygotominor.yy230 = TK_STATEMENT; } +#line 2924 "parse.c" + break; + case 265: +#line 947 "parse.y" +{ yygotominor.yy178 = 0; } +#line 2929 "parse.c" + break; + case 266: +#line 948 "parse.y" +{ yygotominor.yy178 = yymsp[0].minor.yy178; } +#line 2934 "parse.c" + break; + case 267: +#line 952 "parse.y" +{ + yymsp[-2].minor.yy247->pNext = yymsp[0].minor.yy247; + yygotominor.yy247 = yymsp[-2].minor.yy247; } -#line 3015 "parse.c" +#line 2942 "parse.c" break; case 268: -#line 941 "parse.y" -{ - sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy198, &yymsp[-6].minor.yy198, yymsp[-5].minor.yy280, yymsp[-4].minor.yy30.a, yymsp[-4].minor.yy30.b, yymsp[-2].minor.yy151, yymsp[-1].minor.yy280, yymsp[0].minor.yy62, yymsp[-9].minor.yy280); - yygotominor.yy198 = (yymsp[-6].minor.yy198.n==0?yymsp[-7].minor.yy198:yymsp[-6].minor.yy198); -} -#line 3023 "parse.c" +#line 956 "parse.y" +{ yygotominor.yy247 = 0; } +#line 2947 "parse.c" break; case 269: - case 272: -#line 947 "parse.y" -{ yygotominor.yy280 = TK_BEFORE; } -#line 3029 "parse.c" +#line 962 "parse.y" +{ yygotominor.yy247 = sqlite3TriggerUpdateStep(&yymsp[-3].minor.yy384, yymsp[-1].minor.yy462, yymsp[0].minor.yy178, yymsp[-4].minor.yy230); } +#line 2952 "parse.c" break; case 270: -#line 948 "parse.y" -{ yygotominor.yy280 = TK_AFTER; } -#line 3034 "parse.c" +#line 967 "parse.y" +{yygotominor.yy247 = sqlite3TriggerInsertStep(&yymsp[-5].minor.yy384, yymsp[-4].minor.yy160, yymsp[-1].minor.yy462, 0, yymsp[-7].minor.yy230);} +#line 2957 "parse.c" break; case 271: -#line 949 "parse.y" -{ yygotominor.yy280 = TK_INSTEAD;} -#line 3039 "parse.c" +#line 970 "parse.y" +{yygotominor.yy247 = sqlite3TriggerInsertStep(&yymsp[-2].minor.yy384, yymsp[-1].minor.yy160, 0, yymsp[0].minor.yy239, yymsp[-4].minor.yy230);} +#line 2962 "parse.c" + break; + case 272: +#line 974 "parse.y" +{yygotominor.yy247 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy384, yymsp[0].minor.yy178);} +#line 2967 "parse.c" break; case 273: +#line 977 "parse.y" +{yygotominor.yy247 = sqlite3TriggerSelectStep(yymsp[0].minor.yy239); } +#line 2972 "parse.c" + break; case 274: +#line 980 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(TK_RAISE, 0, 0, 0); + yygotominor.yy178->iColumn = OE_Ignore; + sqlite3ExprSpan(yygotominor.yy178, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0); +} +#line 2981 "parse.c" + break; case 275: -#line 954 "parse.y" -{yygotominor.yy30.a = yymsp[0].major; yygotominor.yy30.b = 0;} -#line 3046 "parse.c" +#line 985 "parse.y" +{ + yygotominor.yy178 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy384); + yygotominor.yy178->iColumn = yymsp[-3].minor.yy230; + sqlite3ExprSpan(yygotominor.yy178, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0); +} +#line 2990 "parse.c" break; case 276: -#line 957 "parse.y" -{yygotominor.yy30.a = TK_UPDATE; yygotominor.yy30.b = yymsp[0].minor.yy240;} -#line 3051 "parse.c" +#line 993 "parse.y" +{yygotominor.yy230 = OE_Rollback;} +#line 2995 "parse.c" break; - case 277: case 278: -#line 960 "parse.y" -{ yygotominor.yy280 = TK_ROW; } -#line 3057 "parse.c" +#line 995 "parse.y" +{yygotominor.yy230 = OE_Fail;} +#line 3000 "parse.c" break; case 279: -#line 962 "parse.y" -{ yygotominor.yy280 = TK_STATEMENT; } -#line 3062 "parse.c" +#line 1000 "parse.y" +{ + sqlite3DropTrigger(pParse,yymsp[0].minor.yy285); +} +#line 3007 "parse.c" break; case 280: -#line 965 "parse.y" -{ yygotominor.yy62 = 0; } -#line 3067 "parse.c" +#line 1006 "parse.y" +{ + sqlite3Attach(pParse, yymsp[-3].minor.yy178, yymsp[-1].minor.yy178, yymsp[0].minor.yy292); +} +#line 3014 "parse.c" break; case 281: -#line 966 "parse.y" -{ yygotominor.yy62 = yymsp[0].minor.yy62; } -#line 3072 "parse.c" +#line 1011 "parse.y" +{ yygotominor.yy292 = 0; } +#line 3019 "parse.c" break; case 282: -#line 970 "parse.y" -{ - yymsp[-2].minor.yy360->pNext = yymsp[0].minor.yy360; - yygotominor.yy360 = yymsp[-2].minor.yy360; -} -#line 3080 "parse.c" - break; - case 283: -#line 974 "parse.y" -{ yygotominor.yy360 = 0; } -#line 3085 "parse.c" - break; - case 284: -#line 980 "parse.y" -{ yygotominor.yy360 = sqlite3TriggerUpdateStep(&yymsp[-3].minor.yy198, yymsp[-1].minor.yy418, yymsp[0].minor.yy62, yymsp[-4].minor.yy280); } -#line 3090 "parse.c" +#line 1012 "parse.y" +{ yygotominor.yy292 = yymsp[0].minor.yy178; } +#line 3024 "parse.c" break; case 285: -#line 985 "parse.y" -{yygotominor.yy360 = sqlite3TriggerInsertStep(&yymsp[-5].minor.yy198, yymsp[-4].minor.yy240, yymsp[-1].minor.yy418, 0, yymsp[-7].minor.yy280);} -#line 3095 "parse.c" - break; - case 286: -#line 988 "parse.y" -{yygotominor.yy360 = sqlite3TriggerInsertStep(&yymsp[-2].minor.yy198, yymsp[-1].minor.yy240, 0, yymsp[0].minor.yy375, yymsp[-4].minor.yy280);} -#line 3100 "parse.c" - break; - case 287: -#line 992 "parse.y" -{yygotominor.yy360 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy198, yymsp[0].minor.yy62);} -#line 3105 "parse.c" - break; - case 288: -#line 995 "parse.y" -{yygotominor.yy360 = sqlite3TriggerSelectStep(yymsp[0].minor.yy375); } -#line 3110 "parse.c" - break; - case 289: -#line 998 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_RAISE, 0, 0, 0); - yygotominor.yy62->iColumn = OE_Ignore; - sqlite3ExprSpan(yygotominor.yy62, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0); -} -#line 3119 "parse.c" - break; - case 290: -#line 1003 "parse.y" -{ - yygotominor.yy62 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy198); - yygotominor.yy62->iColumn = yymsp[-3].minor.yy280; - sqlite3ExprSpan(yygotominor.yy62, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0); -} -#line 3128 "parse.c" - break; - case 291: -#line 1011 "parse.y" -{yygotominor.yy280 = OE_Rollback;} -#line 3133 "parse.c" - break; - case 293: -#line 1013 "parse.y" -{yygotominor.yy280 = OE_Fail;} -#line 3138 "parse.c" - break; - case 294: #line 1018 "parse.y" { - sqlite3DropTrigger(pParse,yymsp[0].minor.yy151); + sqlite3Detach(pParse, yymsp[0].minor.yy178); } -#line 3145 "parse.c" +#line 3031 "parse.c" break; - case 295: + case 286: #line 1024 "parse.y" -{ - sqlite3Attach(pParse, &yymsp[-3].minor.yy198, &yymsp[-1].minor.yy198, yymsp[0].minor.yy361.type, &yymsp[0].minor.yy361.key); -} -#line 3152 "parse.c" - break; - case 296: -#line 1028 "parse.y" -{ yygotominor.yy361.type = 0; } -#line 3157 "parse.c" - break; - case 297: -#line 1029 "parse.y" -{ yygotominor.yy361.type=1; yygotominor.yy361.key = yymsp[0].minor.yy198; } -#line 3162 "parse.c" - break; - case 298: -#line 1030 "parse.y" -{ yygotominor.yy361.type=2; yygotominor.yy361.key = yymsp[0].minor.yy0; } -#line 3167 "parse.c" - break; - case 301: +{sqlite3Reindex(pParse, 0, 0);} +#line 3036 "parse.c" + break; + case 287: +#line 1025 "parse.y" +{sqlite3Reindex(pParse, &yymsp[-1].minor.yy384, &yymsp[0].minor.yy384);} +#line 3041 "parse.c" + break; + case 288: +#line 1030 "parse.y" +{sqlite3Analyze(pParse, 0, 0);} +#line 3046 "parse.c" + break; + case 289: +#line 1031 "parse.y" +{sqlite3Analyze(pParse, &yymsp[-1].minor.yy384, &yymsp[0].minor.yy384);} +#line 3051 "parse.c" + break; + case 290: #line 1036 "parse.y" { - sqlite3Detach(pParse, &yymsp[0].minor.yy198); -} -#line 3174 "parse.c" - break; - case 302: -#line 1042 "parse.y" -{sqlite3Reindex(pParse, 0, 0);} -#line 3179 "parse.c" - break; - case 303: -#line 1043 "parse.y" -{sqlite3Reindex(pParse, &yymsp[-1].minor.yy198, &yymsp[0].minor.yy198);} -#line 3184 "parse.c" - break; - case 304: -#line 1048 "parse.y" -{sqlite3Analyze(pParse, 0, 0);} -#line 3189 "parse.c" - break; - case 305: -#line 1049 "parse.y" -{sqlite3Analyze(pParse, &yymsp[-1].minor.yy198, &yymsp[0].minor.yy198);} -#line 3194 "parse.c" - break; - case 306: -#line 1054 "parse.y" -{ - sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy151,&yymsp[0].minor.yy198); -} -#line 3201 "parse.c" - break; - case 307: -#line 1057 "parse.y" -{ - sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy198); -} -#line 3208 "parse.c" - break; - case 308: -#line 1060 "parse.y" -{ - sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy151); -} -#line 3215 "parse.c" + sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy285,&yymsp[0].minor.yy384); +} +#line 3058 "parse.c" + break; + case 291: +#line 1039 "parse.y" +{ + sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy384); +} +#line 3065 "parse.c" + break; + case 292: +#line 1042 "parse.y" +{ + sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy285); +} +#line 3072 "parse.c" break; }; yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yypParser->yyidx -= yysize; @@ -3274,11 +3131,11 @@ sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); }else{ sqlite3ErrorMsg(pParse, "incomplete SQL statement"); } } -#line 3282 "parse.c" +#line 3139 "parse.c" sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */ } /* ** The following is executed when the parser accepts Index: SQLite.Interop/src/parse.h ================================================================== --- SQLite.Interop/src/parse.h +++ SQLite.Interop/src/parse.h @@ -1,145 +1,151 @@ -#define TK_END_OF_FILE 1 -#define TK_ILLEGAL 2 -#define TK_SPACE 3 -#define TK_UNCLOSED_STRING 4 -#define TK_COMMENT 5 -#define TK_FUNCTION 6 -#define TK_COLUMN 7 -#define TK_AGG_FUNCTION 8 -#define TK_AGG_COLUMN 9 -#define TK_CONST_FUNC 10 -#define TK_SEMI 11 -#define TK_EXPLAIN 12 -#define TK_QUERY 13 -#define TK_PLAN 14 -#define TK_BEGIN 15 -#define TK_TRANSACTION 16 -#define TK_DEFERRED 17 -#define TK_IMMEDIATE 18 -#define TK_EXCLUSIVE 19 -#define TK_COMMIT 20 -#define TK_END 21 -#define TK_ROLLBACK 22 -#define TK_CREATE 23 -#define TK_TABLE 24 -#define TK_TEMP 25 -#define TK_LP 26 -#define TK_RP 27 -#define TK_AS 28 -#define TK_COMMA 29 -#define TK_ID 30 -#define TK_ABORT 31 -#define TK_AFTER 32 -#define TK_ANALYZE 33 -#define TK_ASC 34 -#define TK_ATTACH 35 -#define TK_BEFORE 36 -#define TK_CASCADE 37 -#define TK_CAST 38 -#define TK_CONFLICT 39 -#define TK_DATABASE 40 -#define TK_DESC 41 -#define TK_DETACH 42 -#define TK_EACH 43 -#define TK_FAIL 44 -#define TK_FOR 45 -#define TK_IGNORE 46 -#define TK_INITIALLY 47 -#define TK_INSTEAD 48 -#define TK_LIKE_KW 49 -#define TK_MATCH 50 -#define TK_KEY 51 -#define TK_OF 52 -#define TK_OFFSET 53 -#define TK_PRAGMA 54 -#define TK_RAISE 55 -#define TK_REPLACE 56 -#define TK_RESTRICT 57 -#define TK_ROW 58 -#define TK_STATEMENT 59 -#define TK_TRIGGER 60 -#define TK_VACUUM 61 -#define TK_VIEW 62 -#define TK_REINDEX 63 -#define TK_RENAME 64 -#define TK_CTIME_KW 65 -#define TK_ALTER 66 -#define TK_OR 67 -#define TK_AND 68 -#define TK_NOT 69 -#define TK_IS 70 -#define TK_BETWEEN 71 -#define TK_IN 72 -#define TK_ISNULL 73 -#define TK_NOTNULL 74 -#define TK_NE 75 -#define TK_EQ 76 -#define TK_GT 77 -#define TK_LE 78 -#define TK_LT 79 -#define TK_GE 80 -#define TK_ESCAPE 81 -#define TK_BITAND 82 -#define TK_BITOR 83 -#define TK_LSHIFT 84 -#define TK_RSHIFT 85 -#define TK_PLUS 86 -#define TK_MINUS 87 -#define TK_STAR 88 -#define TK_SLASH 89 -#define TK_REM 90 -#define TK_CONCAT 91 -#define TK_UMINUS 92 -#define TK_UPLUS 93 -#define TK_BITNOT 94 -#define TK_STRING 95 -#define TK_JOIN_KW 96 -#define TK_CONSTRAINT 97 -#define TK_DEFAULT 98 -#define TK_NULL 99 -#define TK_PRIMARY 100 -#define TK_UNIQUE 101 -#define TK_CHECK 102 -#define TK_REFERENCES 103 -#define TK_COLLATE 104 -#define TK_AUTOINCR 105 -#define TK_ON 106 -#define TK_DELETE 107 -#define TK_UPDATE 108 -#define TK_INSERT 109 -#define TK_SET 110 -#define TK_DEFERRABLE 111 -#define TK_FOREIGN 112 -#define TK_DROP 113 -#define TK_UNION 114 -#define TK_ALL 115 -#define TK_INTERSECT 116 -#define TK_EXCEPT 117 -#define TK_SELECT 118 -#define TK_DISTINCT 119 -#define TK_DOT 120 -#define TK_FROM 121 -#define TK_JOIN 122 -#define TK_USING 123 -#define TK_ORDER 124 -#define TK_BY 125 -#define TK_GROUP 126 -#define TK_HAVING 127 -#define TK_LIMIT 128 -#define TK_WHERE 129 -#define TK_INTO 130 -#define TK_VALUES 131 -#define TK_INTEGER 132 -#define TK_FLOAT 133 -#define TK_BLOB 134 -#define TK_REGISTER 135 -#define TK_VARIABLE 136 -#define TK_EXISTS 137 -#define TK_CASE 138 -#define TK_WHEN 139 -#define TK_THEN 140 -#define TK_ELSE 141 -#define TK_INDEX 142 -#define TK_TO 143 -#define TK_ADD 144 -#define TK_COLUMNKW 145 +#define TK_SEMI 1 +#define TK_EXPLAIN 2 +#define TK_QUERY 3 +#define TK_PLAN 4 +#define TK_BEGIN 5 +#define TK_TRANSACTION 6 +#define TK_DEFERRED 7 +#define TK_IMMEDIATE 8 +#define TK_EXCLUSIVE 9 +#define TK_COMMIT 10 +#define TK_END 11 +#define TK_ROLLBACK 12 +#define TK_CREATE 13 +#define TK_TABLE 14 +#define TK_IF 15 +#define TK_NOT 16 +#define TK_EXISTS 17 +#define TK_TEMP 18 +#define TK_LP 19 +#define TK_RP 20 +#define TK_AS 21 +#define TK_COMMA 22 +#define TK_ID 23 +#define TK_ABORT 24 +#define TK_AFTER 25 +#define TK_ANALYZE 26 +#define TK_ASC 27 +#define TK_ATTACH 28 +#define TK_BEFORE 29 +#define TK_CASCADE 30 +#define TK_CAST 31 +#define TK_CONFLICT 32 +#define TK_DATABASE 33 +#define TK_DESC 34 +#define TK_DETACH 35 +#define TK_EACH 36 +#define TK_FAIL 37 +#define TK_FOR 38 +#define TK_IGNORE 39 +#define TK_INITIALLY 40 +#define TK_INSTEAD 41 +#define TK_LIKE_KW 42 +#define TK_MATCH 43 +#define TK_KEY 44 +#define TK_OF 45 +#define TK_OFFSET 46 +#define TK_PRAGMA 47 +#define TK_RAISE 48 +#define TK_REPLACE 49 +#define TK_RESTRICT 50 +#define TK_ROW 51 +#define TK_STATEMENT 52 +#define TK_TRIGGER 53 +#define TK_VACUUM 54 +#define TK_VIEW 55 +#define TK_REINDEX 56 +#define TK_RENAME 57 +#define TK_CTIME_KW 58 +#define TK_OR 59 +#define TK_AND 60 +#define TK_IS 61 +#define TK_BETWEEN 62 +#define TK_IN 63 +#define TK_ISNULL 64 +#define TK_NOTNULL 65 +#define TK_NE 66 +#define TK_EQ 67 +#define TK_GT 68 +#define TK_LE 69 +#define TK_LT 70 +#define TK_GE 71 +#define TK_ESCAPE 72 +#define TK_BITAND 73 +#define TK_BITOR 74 +#define TK_LSHIFT 75 +#define TK_RSHIFT 76 +#define TK_PLUS 77 +#define TK_MINUS 78 +#define TK_STAR 79 +#define TK_SLASH 80 +#define TK_REM 81 +#define TK_CONCAT 82 +#define TK_UMINUS 83 +#define TK_UPLUS 84 +#define TK_BITNOT 85 +#define TK_STRING 86 +#define TK_JOIN_KW 87 +#define TK_CONSTRAINT 88 +#define TK_DEFAULT 89 +#define TK_NULL 90 +#define TK_PRIMARY 91 +#define TK_UNIQUE 92 +#define TK_CHECK 93 +#define TK_REFERENCES 94 +#define TK_COLLATE 95 +#define TK_AUTOINCR 96 +#define TK_ON 97 +#define TK_DELETE 98 +#define TK_UPDATE 99 +#define TK_INSERT 100 +#define TK_SET 101 +#define TK_DEFERRABLE 102 +#define TK_FOREIGN 103 +#define TK_DROP 104 +#define TK_UNION 105 +#define TK_ALL 106 +#define TK_EXCEPT 107 +#define TK_INTERSECT 108 +#define TK_SELECT 109 +#define TK_DISTINCT 110 +#define TK_DOT 111 +#define TK_FROM 112 +#define TK_JOIN 113 +#define TK_USING 114 +#define TK_ORDER 115 +#define TK_BY 116 +#define TK_GROUP 117 +#define TK_HAVING 118 +#define TK_LIMIT 119 +#define TK_WHERE 120 +#define TK_INTO 121 +#define TK_VALUES 122 +#define TK_INTEGER 123 +#define TK_FLOAT 124 +#define TK_BLOB 125 +#define TK_REGISTER 126 +#define TK_VARIABLE 127 +#define TK_CASE 128 +#define TK_WHEN 129 +#define TK_THEN 130 +#define TK_ELSE 131 +#define TK_INDEX 132 +#define TK_ALTER 133 +#define TK_TO 134 +#define TK_ADD 135 +#define TK_COLUMNKW 136 +#define TK_TO_TEXT 137 +#define TK_TO_BLOB 138 +#define TK_TO_NUMERIC 139 +#define TK_TO_INT 140 +#define TK_TO_REAL 141 +#define TK_END_OF_FILE 142 +#define TK_ILLEGAL 143 +#define TK_SPACE 144 +#define TK_UNCLOSED_STRING 145 +#define TK_COMMENT 146 +#define TK_FUNCTION 147 +#define TK_COLUMN 148 +#define TK_AGG_FUNCTION 149 +#define TK_AGG_COLUMN 150 +#define TK_CONST_FUNC 151 Index: SQLite.Interop/src/pragma.c ================================================================== --- SQLite.Interop/src/pragma.c +++ SQLite.Interop/src/pragma.c @@ -9,11 +9,11 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.10 2005/12/19 17:57:47 rmsimpson Exp $ +** $Id: pragma.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include @@ -34,11 +34,11 @@ ** Note that the values returned are one less that the values that ** should be passed into sqlite3BtreeSetSafetyLevel(). The is done ** to support legacy SQL code. The safety level used to be boolean ** and older scripts may have used numbers 0 for OFF and 1 for ON. */ -static int getSafetyLevel(const u8 *z){ +static int getSafetyLevel(const char *z){ /* 123456789 123456789 */ static const char zText[] = "onoffalseyestruefull"; static const u8 iOffset[] = {0, 1, 2, 4, 9, 12, 16}; static const u8 iLength[] = {2, 2, 3, 5, 3, 4, 4}; static const u8 iValue[] = {1, 0, 0, 0, 1, 1, 2}; @@ -56,11 +56,11 @@ } /* ** Interpret the given string as a boolean value. */ -static int getBoolean(const u8 *z){ +static int getBoolean(const char *z){ return getSafetyLevel(z)&1; } #ifndef SQLITE_OMIT_PAGER_PRAGMAS /* @@ -149,13 +149,20 @@ { "vdbe_listing", SQLITE_VdbeListing }, { "full_column_names", SQLITE_FullColNames }, { "short_column_names", SQLITE_ShortColNames }, { "count_changes", SQLITE_CountRows }, { "empty_result_callbacks", SQLITE_NullCallback }, +#ifndef SQLITE_OMIT_CHECK + { "ignore_check_constraints", SQLITE_IgnoreChecks }, +#endif /* The following is VERY experimental */ { "writable_schema", SQLITE_WriteSchema }, { "omit_readlock", SQLITE_NoReadlock }, + + /* TODO: Maybe it shouldn't be possible to change the ReadUncommitted + ** flag if there are any active statements. */ + { "read_uncommitted", SQLITE_ReadUncommitted }, }; int i; const struct sPragmaType *p; for(i=0, p=aPragma; izName)==0 ){ @@ -278,12 +285,12 @@ sqlite3VdbeAddOp(v, OP_ReadCookie, iDb, 2); addr = sqlite3VdbeAddOp(v, OP_Integer, 0, 0); sqlite3VdbeAddOp(v, OP_Ge, 0, addr+3); sqlite3VdbeAddOp(v, OP_Negative, 0, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 2); - pDb->cache_size = size; - sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size); + pDb->pSchema->cache_size = size; + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } }else /* ** PRAGMA [database.]page_size @@ -340,16 +347,16 @@ ** N should be a positive integer. */ if( sqlite3StrICmp(zLeft,"cache_size")==0 ){ if( sqlite3ReadSchema(pParse) ) goto pragma_out; if( !zRight ){ - returnSingleInt(pParse, "cache_size", pDb->cache_size); + returnSingleInt(pParse, "cache_size", pDb->pSchema->cache_size); }else{ int size = atoi(zRight); if( size<0 ) size = -size; - pDb->cache_size = size; - sqlite3BtreeSetCacheSize(pDb->pBt, pDb->cache_size); + pDb->pSchema->cache_size = size; + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); } }else /* ** PRAGMA temp_store @@ -645,19 +652,21 @@ sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */ /* Do an integrity check on each database file */ for(i=0; inDb; i++){ HashElem *x; + Hash *pTbls; int cnt = 0; if( OMIT_TEMPDB && i==1 ) continue; sqlite3CodeVerifySchema(pParse, i); /* Do an integrity check of the B-Tree */ - for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){ + pTbls = &db->aDb[i].pSchema->tblHash; + for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; sqlite3VdbeAddOp(v, OP_Integer, pTab->tnum, 0); cnt++; for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ @@ -668,35 +677,36 @@ } assert( cnt>0 ); sqlite3VdbeAddOp(v, OP_IntegrityCk, cnt, i); sqlite3VdbeAddOp(v, OP_Dup, 0, 1); addr = sqlite3VdbeOp3(v, OP_String8, 0, 0, "ok", P3_STATIC); - sqlite3VdbeAddOp(v, OP_Eq, 0, addr+6); + sqlite3VdbeAddOp(v, OP_Eq, 0, addr+7); sqlite3VdbeOp3(v, OP_String8, 0, 0, sqlite3MPrintf("*** in database %s ***\n", db->aDb[i].zName), P3_DYNAMIC); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Concat, 0, 1); sqlite3VdbeAddOp(v, OP_Callback, 1, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0); /* Make sure all the indices are constructed correctly. */ sqlite3CodeVerifySchema(pParse, i); - for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){ + for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){ Table *pTab = sqliteHashData(x); Index *pIdx; int loopTop; if( pTab->pIndex==0 ) continue; sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead); sqlite3VdbeAddOp(v, OP_MemInt, 0, 1); loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0); - sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, 1, 1); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ int jmp2; static const VdbeOpList idxErr[] = { - { OP_MemIncr, 0, 0, 0}, + { OP_MemIncr, 1, 0, 0}, { OP_String8, 0, 0, "rowid "}, { OP_Rowid, 1, 0, 0}, { OP_String8, 0, 0, " missing from index "}, { OP_String8, 0, 0, 0}, /* 4 */ { OP_Concat, 2, 0, 0}, @@ -712,16 +722,16 @@ sqlite3VdbeJumpHere(v, loopTop); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ static const VdbeOpList cntIdx[] = { { OP_MemInt, 0, 2, 0}, { OP_Rewind, 0, 0, 0}, /* 1 */ - { OP_MemIncr, 2, 0, 0}, + { OP_MemIncr, 1, 2, 0}, { OP_Next, 0, 0, 0}, /* 3 */ { OP_MemLoad, 1, 0, 0}, { OP_MemLoad, 2, 0, 0}, { OP_Eq, 0, 0, 0}, /* 6 */ - { OP_MemIncr, 0, 0, 0}, + { OP_MemIncr, 1, 0, 0}, { OP_String8, 0, 0, "wrong # of entries in index "}, { OP_String8, 0, 0, 0}, /* 9 */ { OP_Concat, 0, 0, 0}, { OP_Callback, 1, 0, 0}, }; @@ -785,11 +795,11 @@ if( sqlite3ReadSchema(pParse) ) goto pragma_out; sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, "encoding", P3_STATIC); sqlite3VdbeAddOp(v, OP_String8, 0, 0); for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ - if( pEnc->enc==pParse->db->enc ){ + if( pEnc->enc==ENC(pParse->db) ){ sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC); break; } } sqlite3VdbeAddOp(v, OP_Callback, 1, 0); @@ -800,11 +810,11 @@ ** already exists, it will be created to use the new encoding value. */ if( !(pParse->db->flags&SQLITE_Initialized) ){ for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ - pParse->db->enc = pEnc->enc; + ENC(pParse->db) = pEnc->enc; break; } } if( !pEnc->zName ){ sqlite3ErrorMsg(pParse, "unsupported encoding: %s", zRight); @@ -915,10 +925,16 @@ if( sqlite3StrICmp(zLeft, "create_sqlite_statement_table")==0 ){ extern int sqlite3CreateStatementsTable(Parse*); sqlite3CreateStatementsTable(pParse); }else #endif + +#if SQLITE_HAS_CODEC + if( sqlite3StrICmp(zLeft, "key")==0 ){ + sqlite3_key(db, zRight, strlen(zRight)); + }else +#endif {} if( v ){ /* Code an OP_Expire at the end of each PRAGMA program to cause Index: SQLite.Interop/src/prepare.c ================================================================== --- SQLite.Interop/src/prepare.c +++ SQLite.Interop/src/prepare.c @@ -11,11 +11,11 @@ ************************************************************************* ** This file contains the implementation of the sqlite3_prepare() ** interface, and routines that contribute to loading the database schema ** from disk. ** -** $Id: prepare.c,v 1.6 2005/12/19 17:57:47 rmsimpson Exp $ +** $Id: prepare.c,v 1.7 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" #include @@ -22,11 +22,11 @@ /* ** Fill the InitData structure with an error message that indicates ** that the database is corrupt. */ static void corruptSchema(InitData *pData, const char *zExtra){ - if( !sqlite3_malloc_failed ){ + if( !sqlite3ThreadData()->mallocFailed ){ sqlite3SetString(pData->pzErrMsg, "malformed database schema", zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0); } } @@ -46,10 +46,14 @@ */ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){ InitData *pData = (InitData*)pInit; sqlite3 *db = pData->db; int iDb; + + if( sqlite3ThreadData()->mallocFailed ){ + return SQLITE_NOMEM; + } assert( argc==4 ); if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ if( argv[1]==0 || argv[3]==0 ){ corruptSchema(pData, 0); @@ -69,11 +73,15 @@ db->init.iDb = iDb; db->init.newTnum = atoi(argv[1]); rc = sqlite3_exec(db, argv[2], 0, 0, &zErr); db->init.iDb = 0; if( SQLITE_OK!=rc ){ - corruptSchema(pData, zErr); + if( rc==SQLITE_NOMEM ){ + sqlite3ThreadData()->mallocFailed = 1; + }else{ + corruptSchema(pData, zErr); + } sqlite3_free(zErr); return rc; } }else{ /* If the SQL column is blank it means this is an index that @@ -109,10 +117,11 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){ int rc; BtCursor *curMain; int size; Table *pTab; + Db *pDb; char const *azArg[5]; char zDbNum[30]; int meta[10]; InitData initData; char const *zMasterSchema; @@ -143,10 +152,31 @@ #else #define temp_master_schema 0 #endif assert( iDb>=0 && iDbnDb ); + + assert( db->aDb[iDb].pSchema ); +#if 0 + if( 0==db->aDb[iDb].pSchema ){ + Schema *pS = sqlite3SchemaGet(db->aDb[iDb].pBt); + db->aDb[iDb].pSchema = pS; + if( !pS ){ + return SQLITE_NOMEM; + }else if( pS->file_format!=0 ){ + /* This means that the shared-schema associated with the the btree + ** is already open and populated. + */ + if( pS->enc!=ENC(db) ){ + sqlite3SetString(pzErrMsg, "attached databases must use the same" + " text encoding as main database", (char*)0); + return SQLITE_ERROR; + } + return SQLITE_OK; + } + } +#endif /* zMasterSchema and zInitScript are set to point at the master schema ** and initialisation script appropriate for the database being ** initialised. zMasterName is the name of the master table. */ @@ -178,15 +208,16 @@ } sqlite3SafetyOn(db); /* Create a cursor to hold the database open */ - if( db->aDb[iDb].pBt==0 ){ + pDb = &db->aDb[iDb]; + if( pDb->pBt==0 ){ if( !OMIT_TEMPDB && iDb==1 ) DbSetProperty(db, 1, DB_SchemaLoaded); return SQLITE_OK; } - rc = sqlite3BtreeCursor(db->aDb[iDb].pBt, MASTER_ROOT, 0, 0, 0, &curMain); + rc = sqlite3BtreeCursor(pDb->pBt, MASTER_ROOT, 0, 0, 0, &curMain); if( rc!=SQLITE_OK && rc!=SQLITE_EMPTY ){ sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); return rc; } @@ -208,78 +239,65 @@ ** the possible values of meta[4]. */ if( rc==SQLITE_OK ){ int i; for(i=0; rc==SQLITE_OK && iaDb[iDb].pBt, i+1, (u32 *)&meta[i]); + rc = sqlite3BtreeGetMeta(pDb->pBt, i+1, (u32 *)&meta[i]); } if( rc ){ sqlite3SetString(pzErrMsg, sqlite3ErrStr(rc), (char*)0); sqlite3BtreeCloseCursor(curMain); return rc; } }else{ memset(meta, 0, sizeof(meta)); } - db->aDb[iDb].schema_cookie = meta[0]; + pDb->pSchema->schema_cookie = meta[0]; /* If opening a non-empty database, check the text encoding. For the ** main database, set sqlite3.enc to the encoding of the main database. ** For an attached db, it is an error if the encoding is not the same ** as sqlite3.enc. */ if( meta[4] ){ /* text encoding */ if( iDb==0 ){ - /* If opening the main database, set db->enc. */ - db->enc = (u8)meta[4]; - db->pDfltColl = sqlite3FindCollSeq(db, db->enc, "BINARY", 6, 0); + /* If opening the main database, set ENC(db). */ + ENC(db) = (u8)meta[4]; + db->pDfltColl = sqlite3FindCollSeq(db, ENC(db), "BINARY", 6, 0); }else{ - /* If opening an attached database, the encoding much match db->enc */ - if( meta[4]!=db->enc ){ + /* If opening an attached database, the encoding much match ENC(db) */ + if( meta[4]!=ENC(db) ){ sqlite3BtreeCloseCursor(curMain); sqlite3SetString(pzErrMsg, "attached databases must use the same" " text encoding as main database", (char*)0); return SQLITE_ERROR; } } } + pDb->pSchema->enc = ENC(db); size = meta[2]; if( size==0 ){ size = MAX_PAGES; } - db->aDb[iDb].cache_size = size; - - if( iDb==0 ){ - db->file_format = meta[1]; - if( db->file_format==0 ){ - /* This happens if the database was initially empty */ - db->file_format = 1; - } - - if( db->file_format==2 || db->file_format==3 ){ - /* File format 2 is treated exactly as file format 1. New - ** databases are created with file format 1. - */ - db->file_format = 1; - } - } + pDb->pSchema->cache_size = size; + sqlite3BtreeSetCacheSize(pDb->pBt, pDb->pSchema->cache_size); /* ** file_format==1 Version 3.0.0. - ** file_format==2 Version 3.1.3. - ** file_format==3 Version 3.1.4. - ** - ** Version 3.0 can only use files with file_format==1. Version 3.1.3 - ** can read and write files with file_format==1 or file_format==2. - ** Version 3.1.4 can read and write file formats 1, 2 and 3. + ** file_format==2 Version 3.1.3. // ALTER TABLE ADD COLUMN + ** file_format==3 Version 3.1.4. // ditto but with non-NULL defaults + ** file_format==4 Version 3.3.0. // DESC indices. Boolean constants */ - if( meta[1]>3 ){ + pDb->pSchema->file_format = meta[1]; + if( pDb->pSchema->file_format==0 ){ + pDb->pSchema->file_format = 1; + } + if( pDb->pSchema->file_format>SQLITE_MAX_FILE_FORMAT ){ sqlite3BtreeCloseCursor(curMain); sqlite3SetString(pzErrMsg, "unsupported file format", (char*)0); return SQLITE_ERROR; } - sqlite3BtreeSetCacheSize(db->aDb[iDb].pBt, db->aDb[iDb].cache_size); /* Read the schema information out of the schema tables */ assert( db->init.busy ); if( rc==SQLITE_EMPTY ){ @@ -299,11 +317,11 @@ sqlite3AnalysisLoad(db, iDb); } #endif sqlite3BtreeCloseCursor(curMain); } - if( sqlite3_malloc_failed ){ + if( sqlite3ThreadData()->mallocFailed ){ sqlite3SetString(pzErrMsg, "out of memory", (char*)0); rc = SQLITE_NOMEM; sqlite3ResetInternalSchema(db, 0); } if( rc==SQLITE_OK ){ @@ -400,18 +418,89 @@ pBt = db->aDb[iDb].pBt; if( pBt==0 ) continue; rc = sqlite3BtreeCursor(pBt, MASTER_ROOT, 0, 0, 0, &curTemp); if( rc==SQLITE_OK ){ rc = sqlite3BtreeGetMeta(pBt, 1, (u32 *)&cookie); - if( rc==SQLITE_OK && cookie!=db->aDb[iDb].schema_cookie ){ + if( rc==SQLITE_OK && cookie!=db->aDb[iDb].pSchema->schema_cookie ){ allOk = 0; } sqlite3BtreeCloseCursor(curTemp); } } return allOk; } + +/* +** Free all resources held by the schema structure. The void* argument points +** at a Schema struct. This function does not call sqliteFree() on the +** pointer itself, it just cleans up subsiduary resources (i.e. the contents +** of the schema hash tables). +*/ +void sqlite3SchemaFree(void *p){ + Hash temp1; + Hash temp2; + HashElem *pElem; + Schema *pSchema = (Schema *)p; + + temp1 = pSchema->tblHash; + temp2 = pSchema->trigHash; + sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0); + sqlite3HashClear(&pSchema->aFKey); + sqlite3HashClear(&pSchema->idxHash); + for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){ + sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem)); + } + sqlite3HashClear(&temp2); + sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0); + for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){ + Table *pTab = sqliteHashData(pElem); + sqlite3DeleteTable(0, pTab); + } + sqlite3HashClear(&temp1); + pSchema->pSeqTab = 0; + pSchema->flags &= ~DB_SchemaLoaded; +} + +Schema *sqlite3SchemaGet(Btree *pBt){ + Schema * p; + if( pBt ){ + p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree); + }else{ + p = (Schema *)sqliteMalloc(sizeof(Schema)); + } + if( p && 0==p->file_format ){ + sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0); + sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0); + sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0); + sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1); + } + return p; +} + +int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ + int i = -1000000; + + /* If pSchema is NULL, then return -1000000. This happens when code in + ** expr.c is trying to resolve a reference to a transient table (i.e. one + ** created by a sub-select). In this case the return value of this + ** function should never be used. + ** + ** We return -1000000 instead of the more usual -1 simply because using + ** -1000000 as incorrectly using -1000000 index into db->aDb[] is much + ** more likely to cause a segfault than -1 (of course there are assert() + ** statements too, but it never hurts to play the odds). + */ + if( pSchema ){ + for(i=0; inDb; i++){ + if( db->aDb[i].pSchema==pSchema ){ + break; + } + } + assert( i>=0 &&i>=0 && inDb ); + } + return i; +} /* ** Compile the UTF-8 encoded SQL statement zSql into a statement handle. */ int sqlite3_prepare( @@ -422,34 +511,42 @@ const char** pzTail /* OUT: End of parsed string */ ){ Parse sParse; char *zErrMsg = 0; int rc = SQLITE_OK; + int i; - if( sqlite3_malloc_failed ){ - return SQLITE_NOMEM; - } + assert( !sqlite3ThreadData()->mallocFailed ); assert( ppStmt ); *ppStmt = 0; if( sqlite3SafetyOn(db) ){ return SQLITE_MISUSE; } + /* If any attached database schemas are locked, do not proceed with + ** compilation. Instead return SQLITE_LOCKED immediately. + */ + for(i=0; inDb; i++) { + Btree *pBt = db->aDb[i].pBt; + if( pBt && sqlite3BtreeSchemaLocked(pBt) ){ + const char *zDb = db->aDb[i].zName; + sqlite3Error(db, SQLITE_LOCKED, "database schema is locked: %s", zDb); + sqlite3SafetyOff(db); + return SQLITE_LOCKED; + } + } + memset(&sParse, 0, sizeof(sParse)); sParse.db = db; sqlite3RunParser(&sParse, zSql, &zErrMsg); - if( sqlite3_malloc_failed ){ - rc = SQLITE_NOMEM; - sqlite3RollbackAll(db); - sqlite3ResetInternalSchema(db, 0); - db->flags &= ~SQLITE_InTrans; - goto prepare_out; + if( sqlite3ThreadData()->mallocFailed ){ + sParse.rc = SQLITE_NOMEM; } if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; - if( sParse.rc!=SQLITE_OK && sParse.checkSchema && !schemaIsValid(db) ){ + if( sParse.checkSchema && !schemaIsValid(db) ){ sParse.rc = SQLITE_SCHEMA; } if( sParse.rc==SQLITE_SCHEMA ){ sqlite3ResetInternalSchema(db, 0); } @@ -472,11 +569,10 @@ sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC); } } #endif -prepare_out: if( sqlite3SafetyOff(db) ){ rc = SQLITE_MISUSE; } if( rc==SQLITE_OK ){ *ppStmt = (sqlite3_stmt*)sParse.pVdbe; @@ -488,10 +584,20 @@ sqlite3Error(db, rc, "%s", zErrMsg); sqliteFree(zErrMsg); }else{ sqlite3Error(db, rc, 0); } + + /* We must check for malloc failure last of all, in case malloc() failed + ** inside of the sqlite3Error() call above or something. + */ + if( sqlite3ThreadData()->mallocFailed ){ + rc = SQLITE_NOMEM; + sqlite3Error(db, rc, 0); + } + + sqlite3MallocClearFailed(); return rc; } #ifndef SQLITE_OMIT_UTF16 /* @@ -506,21 +612,18 @@ ){ /* This function currently works by first transforming the UTF-16 ** encoded string to UTF-8, then invoking sqlite3_prepare(). The ** tricky bit is figuring out the pointer to return in *pzTail. */ - char const *zSql8 = 0; - char const *zTail8 = 0; + char *zSql8 = 0; + const char *zTail8 = 0; int rc; - sqlite3_value *pTmp; if( sqlite3SafetyCheck(db) ){ return SQLITE_MISUSE; } - pTmp = sqlite3GetTransientValue(db); - sqlite3ValueSetStr(pTmp, -1, zSql, SQLITE_UTF16NATIVE, SQLITE_STATIC); - zSql8 = sqlite3ValueText(pTmp, SQLITE_UTF8); + zSql8 = sqlite3utf16to8(zSql, nBytes); if( !zSql8 ){ sqlite3Error(db, SQLITE_NOMEM, 0); return SQLITE_NOMEM; } rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8); @@ -532,9 +635,9 @@ ** the same number of characters into the UTF-16 string. */ int chars_parsed = sqlite3utf8CharLen(zSql8, zTail8-zSql8); *pzTail = (u8 *)zSql + sqlite3utf16ByteLen(zSql, chars_parsed); } - + sqliteFree(zSql8); return rc; } #endif /* SQLITE_OMIT_UTF16 */ Index: SQLite.Interop/src/printf.c ================================================================== --- SQLite.Interop/src/printf.c +++ SQLite.Interop/src/printf.c @@ -118,14 +118,16 @@ { 'c', 0, 0, etCHARX, 0, 0 }, { 'o', 8, 0, etRADIX, 0, 2 }, { 'u', 10, 0, etRADIX, 0, 0 }, { 'x', 16, 0, etRADIX, 16, 1 }, { 'X', 16, 0, etRADIX, 0, 4 }, +#ifndef SQLITE_OMIT_FLOATING_POINT { 'f', 0, 1, etFLOAT, 0, 0 }, { 'e', 0, 1, etEXP, 30, 0 }, { 'E', 0, 1, etEXP, 14, 0 }, { 'G', 0, 1, etGENERIC, 14, 0 }, +#endif { 'i', 10, 1, etRADIX, 0, 0 }, { 'n', 0, 0, etSIZE, 0, 0 }, { '%', 0, 0, etPERCENT, 0, 0 }, { 'p', 16, 0, etPOINTER, 0, 1 }, { 'T', 0, 2, etTOKEN, 0, 0 }, @@ -132,14 +134,14 @@ { 'S', 0, 2, etSRCLIST, 0, 0 }, }; #define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0])) /* -** If NOFLOATINGPOINT is defined, then none of the floating point +** If SQLITE_OMIT_FLOATING_POINT is defined, then none of the floating point ** conversions will work. */ -#ifndef etNOFLOATINGPOINT +#ifndef SQLITE_OMIT_FLOATING_POINT /* ** "*val" is a double such that 0.1 <= *val < 10.0 ** Return the ascii code for the leading digit of *val, then ** multiply "*val" by 10.0 to renormalize. ** @@ -159,11 +161,11 @@ d = digit; digit += '0'; *val = (*val - d)*10.0; return digit; } -#endif +#endif /* SQLITE_OMIT_FLOATING_POINT */ /* ** On machines with a small stack size, you can redefine the ** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for ** smaller values some %f conversions may go into an infinite loop. @@ -232,11 +234,11 @@ etByte xtype; /* Conversion paradigm */ char *zExtra; /* Extra memory used for etTCLESCAPE conversions */ static const char spaces[] = " "; #define etSPACESIZE (sizeof(spaces)-1) -#ifndef etNOFLOATINGPOINT +#ifndef SQLITE_OMIT_FLOATING_POINT int exp, e2; /* exponent of real numbers */ double rounder; /* Used for rounding floating point values */ etByte flag_dp; /* True if decimal point should be shown */ etByte flag_rtz; /* True if trailing zeros should be removed */ etByte flag_exp; /* True to force display of the exponent */ @@ -423,11 +425,11 @@ break; case etFLOAT: case etEXP: case etGENERIC: realvalue = va_arg(ap,double); -#ifndef etNOFLOATINGPOINT +#ifndef SQLITE_OMIT_FLOATING_POINT if( precision<0 ) precision = 6; /* Set default precision */ if( precision>etBUFSIZE/2-10 ) precision = etBUFSIZE/2-10; if( realvalue<0.0 ){ realvalue = -realvalue; prefix = '-'; @@ -623,11 +625,11 @@ break; } case etTOKEN: { Token *pToken = va_arg(ap, Token*); if( pToken && pToken->z ){ - (*func)(arg, pToken->z, pToken->n); + (*func)(arg, (char*)pToken->z, pToken->n); } length = width = 0; break; } case etSRCLIST: { Index: SQLite.Interop/src/random.c ================================================================== --- SQLite.Interop/src/random.c +++ SQLite.Interop/src/random.c @@ -13,11 +13,11 @@ ** generator (PRNG) for SQLite. ** ** Random numbers are used by some of the database backends in order ** to generate random integer keys for tables or random filenames. ** -** $Id: random.c,v 1.10 2005/12/19 17:57:47 rmsimpson Exp $ +** $Id: random.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" #include "os.h" Index: SQLite.Interop/src/select.c ================================================================== --- SQLite.Interop/src/select.c +++ SQLite.Interop/src/select.c @@ -10,14 +10,14 @@ ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.10 2005/12/19 17:57:47 rmsimpson Exp $ +** $Id: select.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include "sqliteInt.h" -#include "../interop.h" + /* ** Allocate a new Select structure and return a pointer to that ** structure. */ @@ -107,11 +107,11 @@ apAll[2] = pC; for(i=0; i<3 && apAll[i]; i++){ p = apAll[i]; for(j=0; jn==keywords[j].nChar - && sqlite3StrNICmp(p->z, keywords[j].zKeyword, p->n)==0 ){ + && sqlite3StrNICmp((char*)p->z, keywords[j].zKeyword, p->n)==0 ){ jointype |= keywords[j].code; break; } } if( j>=sizeof(keywords)/sizeof(keywords[0]) ){ @@ -152,12 +152,12 @@ /* ** Set the value of a token to a '\000'-terminated string. */ static void setToken(Token *p, const char *z){ - p->z = z; - p->n = strlen(z); + p->z = (u8*)z; + p->n = z ? strlen(z) : 0; p->dyn = 0; } /* ** Create an expression node for an identifier with the name of zName @@ -349,42 +349,53 @@ /* ** Insert code into "v" that will push the record on the top of the ** stack into the sorter. */ -static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){ +static void pushOntoSorter( + Parse *pParse, /* Parser context */ + ExprList *pOrderBy, /* The ORDER BY clause */ + Select *pSelect /* The whole SELECT statement */ +){ + Vdbe *v = pParse->pVdbe; sqlite3ExprCodeExprList(pParse, pOrderBy); sqlite3VdbeAddOp(v, OP_Sequence, pOrderBy->iECursor, 0); sqlite3VdbeAddOp(v, OP_Pull, pOrderBy->nExpr + 1, 0); sqlite3VdbeAddOp(v, OP_MakeRecord, pOrderBy->nExpr + 2, 0); sqlite3VdbeAddOp(v, OP_IdxInsert, pOrderBy->iECursor, 0); + if( pSelect->iLimit>=0 ){ + int addr1, addr2; + addr1 = sqlite3VdbeAddOp(v, OP_IfMemZero, pSelect->iLimit+1, 0); + sqlite3VdbeAddOp(v, OP_MemIncr, -1, pSelect->iLimit+1); + addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); + sqlite3VdbeJumpHere(v, addr1); + sqlite3VdbeAddOp(v, OP_Last, pOrderBy->iECursor, 0); + sqlite3VdbeAddOp(v, OP_Delete, pOrderBy->iECursor, 0); + sqlite3VdbeJumpHere(v, addr2); + pSelect->iLimit = -1; + } } /* -** Add code to implement the OFFSET and LIMIT +** Add code to implement the OFFSET */ -static void codeLimiter( +static void codeOffset( Vdbe *v, /* Generate code into this VM */ Select *p, /* The SELECT statement being coded */ int iContinue, /* Jump here to skip the current record */ - int iBreak, /* Jump here to end the loop */ int nPop /* Number of times to pop stack when jumping */ ){ if( p->iOffset>=0 && iContinue!=0 ){ - int addr = sqlite3VdbeCurrentAddr(v) + 3; - if( nPop>0 ) addr++; - sqlite3VdbeAddOp(v, OP_MemIncr, p->iOffset, 0); - sqlite3VdbeAddOp(v, OP_IfMemPos, p->iOffset, addr); + int addr; + sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iOffset); + addr = sqlite3VdbeAddOp(v, OP_IfMemNeg, p->iOffset, 0); if( nPop>0 ){ sqlite3VdbeAddOp(v, OP_Pop, nPop, 0); } sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue); VdbeComment((v, "# skip OFFSET records")); - } - if( p->iLimit>=0 && iBreak!=0 ){ - sqlite3VdbeAddOp(v, OP_MemIncr, p->iLimit, iBreak); - VdbeComment((v, "# exit when LIMIT reached")); + sqlite3VdbeJumpHere(v, addr); } } /* ** Add code that will check to make sure the top N elements of the @@ -447,11 +458,11 @@ /* If there was a LIMIT clause on the SELECT statement, then do the check ** to see if this row should be output. */ hasDistinct = distinct>=0 && pEList && pEList->nExpr>0; if( pOrderBy==0 && !hasDistinct ){ - codeLimiter(v, p, iContinue, iBreak, 0); + codeOffset(v, p, iContinue, 0); } /* Pull the requested columns. */ if( nColumn>0 ){ @@ -469,11 +480,11 @@ */ if( hasDistinct ){ int n = pEList->nExpr; codeDistinct(v, distinct, iContinue, n, n+1); if( pOrderBy==0 ){ - codeLimiter(v, p, iContinue, iBreak, nColumn); + codeOffset(v, p, iContinue, nColumn); } } switch( eDest ){ /* In this mode, write each query result to the key of the temporary @@ -507,11 +518,11 @@ */ case SRT_Table: case SRT_VirtualTab: { sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); if( pOrderBy ){ - pushOntoSorter(pParse, v, pOrderBy); + pushOntoSorter(pParse, pOrderBy, p); }else{ sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Insert, iParm, 0); } @@ -534,33 +545,41 @@ if( pOrderBy ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ - pushOntoSorter(pParse, v, pOrderBy); + pushOntoSorter(pParse, pOrderBy, p); }else{ char aff = (iParm>>16)&0xFF; aff = sqlite3CompareAffinity(pEList->a[0].pExpr, aff); sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &aff, 1); sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); } sqlite3VdbeJumpHere(v, addr2); break; } + + /* If any row exists in the result set, record that fact and abort. + */ + case SRT_Exists: { + sqlite3VdbeAddOp(v, OP_MemInt, 1, iParm); + sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); + /* The LIMIT clause will terminate the loop for us */ + break; + } /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. */ - case SRT_Exists: case SRT_Mem: { assert( nColumn==1 ); if( pOrderBy ){ - pushOntoSorter(pParse, v, pOrderBy); + pushOntoSorter(pParse, pOrderBy, p); }else{ sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); - sqlite3VdbeAddOp(v, OP_Goto, 0, iBreak); + /* The LIMIT clause will jump out of the loop for us */ } break; } #endif /* #ifndef SQLITE_OMIT_SUBQUERY */ @@ -570,11 +589,11 @@ */ case SRT_Subroutine: case SRT_Callback: { if( pOrderBy ){ sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); - pushOntoSorter(pParse, v, pOrderBy); + pushOntoSorter(pParse, pOrderBy, p); }else if( eDest==SRT_Subroutine ){ sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm); }else{ sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0); } @@ -592,10 +611,17 @@ sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); break; } #endif } + + /* Jump to the end of the loop if the LIMIT is reached. + */ + if( p->iLimit>=0 && pOrderBy==0 ){ + sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit); + sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, iBreak); + } return 0; } /* ** Given an expression list, generate a KeyInfo structure that records @@ -620,13 +646,13 @@ int i; nExpr = pList->nExpr; pInfo = sqliteMalloc( sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) ); if( pInfo ){ - pInfo->aSortOrder = (char*)&pInfo->aColl[nExpr]; + pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr]; pInfo->nField = nExpr; - pInfo->enc = db->enc; + pInfo->enc = ENC(db); for(i=0, pItem=pList->a; ipExpr); if( !pColl ){ pColl = db->pDfltColl; @@ -659,11 +685,11 @@ int iTab; ExprList *pOrderBy = p->pOrderBy; iTab = pOrderBy->iECursor; addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk); - codeLimiter(v, p, cont, brk, 0); + codeOffset(v, p, cont, 0); sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1); switch( eDest ){ case SRT_Table: case SRT_VirtualTab: { sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); @@ -675,19 +701,18 @@ case SRT_Set: { assert( nColumn==1 ); sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3); - sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "n", P3_STATIC); + sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, "c", P3_STATIC); sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); break; } - case SRT_Exists: case SRT_Mem: { assert( nColumn==1 ); sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); - sqlite3VdbeAddOp(v, OP_Goto, 0, brk); + /* The LIMIT clause will terminate the loop for us */ break; } #endif case SRT_Callback: case SRT_Subroutine: { @@ -708,10 +733,20 @@ default: { /* Do nothing */ break; } } + + /* Jump to the end of the loop when the LIMIT is reached + */ + if( p->iLimit>=0 ){ + sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit); + sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, brk); + } + + /* The bottom of the loop + */ sqlite3VdbeResolveLabel(v, cont); sqlite3VdbeAddOp(v, OP_Next, iTab, addr); sqlite3VdbeResolveLabel(v, brk); } @@ -835,11 +870,11 @@ return; } #endif assert( v!=0 ); - if( pParse->colNamesSet || v==0 || sqlite3_malloc_failed ) return; + if( pParse->colNamesSet || v==0 || sqlite3ThreadData()->mallocFailed ) return; pParse->colNamesSet = 1; fullNames = (db->flags & SQLITE_FullColNames)!=0; shortNames = (db->flags & SQLITE_ShortColNames)!=0; sqlite3VdbeSetNumCols(v, pEList->nExpr); for(i=0; inExpr; i++){ @@ -864,24 +899,24 @@ zCol = "rowid"; }else{ zCol = pTab->aCol[iCol].zName; } if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){ - sqlite3VdbeSetColName(v, i, p->span.z, p->span.n); + sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n); }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){ char *zName = 0; char *zTab; zTab = pTabList->a[j].zAlias; if( fullNames || zTab==0 ) zTab = pTab->zName; - sqlite3SetString(&zName, zTab, ".", zCol, 0); + sqlite3SetString(&zName, zTab, ".", zCol, (char*)0); sqlite3VdbeSetColName(v, i, zName, P3_DYNAMIC); }else{ sqlite3VdbeSetColName(v, i, zCol, strlen(zCol)); } }else if( p->span.z && p->span.z[0] ){ - sqlite3VdbeSetColName(v, i, p->span.z, p->span.n); + sqlite3VdbeSetColName(v, i, (char*)p->span.z, p->span.n); /* sqlite3VdbeCompressSpace(v, addr); */ }else{ char zName[30]; assert( p->op!=TK_COLUMN || pTabList==0 ); sprintf(zName, "column%d", i+1); @@ -963,11 +998,11 @@ }else{ /* If all else fails, make up a name */ zName = sqlite3MPrintf("column%d", i+1); } sqlite3Dequote(zName); - if( sqlite3_malloc_failed ){ + if( sqlite3ThreadData()->mallocFailed ){ sqliteFree(zName); sqlite3DeleteTable(0, pTab); return 0; } @@ -1035,11 +1070,11 @@ SrcList *pTabList; ExprList *pEList; Table *pTab; struct SrcList_item *pFrom; - if( p==0 || p->pSrc==0 || sqlite3_malloc_failed ) return 1; + if( p==0 || p->pSrc==0 || sqlite3ThreadData()->mallocFailed ) return 1; pTabList = p->pSrc; pEList = p->pEList; /* Make sure cursor numbers have been assigned to all entries in ** the FROM clause of the SELECT statement. @@ -1143,11 +1178,15 @@ if( pE->op!=TK_ALL && (pE->op!=TK_DOT || pE->pRight==0 || pE->pRight->op!=TK_ALL) ){ /* This particular expression does not need to be expanded. */ pNew = sqlite3ExprListAppend(pNew, a[k].pExpr, 0); - pNew->a[pNew->nExpr-1].zName = a[k].zName; + if( pNew ){ + pNew->a[pNew->nExpr-1].zName = a[k].zName; + }else{ + rc = 1; + } a[k].pExpr = 0; a[k].zName = 0; }else{ /* This expression is a "*" or a "TABLE.*" and needs to be ** expanded. */ @@ -1323,57 +1362,78 @@ if( v==0 ){ v = pParse->pVdbe = sqlite3VdbeCreate(pParse->db); } return v; } + /* ** Compute the iLimit and iOffset fields of the SELECT based on the -** pLimit and pOffset expressions. nLimit and nOffset hold the expressions +** pLimit and pOffset expressions. pLimit and pOffset hold the expressions ** that appear in the original SQL statement after the LIMIT and OFFSET ** keywords. Or NULL if those keywords are omitted. iLimit and iOffset ** are the integer memory register numbers for counters used to compute ** the limit and offset. If there is no limit and/or offset, then ** iLimit and iOffset are negative. ** -** This routine changes the values if iLimit and iOffset only if -** a limit or offset is defined by nLimit and nOffset. iLimit and +** This routine changes the values of iLimit and iOffset only if +** a limit or offset is defined by pLimit and pOffset. iLimit and ** iOffset should have been preset to appropriate default values ** (usually but not always -1) prior to calling this routine. -** Only if nLimit>=0 or nOffset>0 do the limit registers get +** Only if pLimit!=0 or pOffset!=0 do the limit registers get ** redefined. The UNION ALL operator uses this property to force ** the reuse of the same limit and offset registers across multiple ** SELECT statements. */ -static void computeLimitRegisters(Parse *pParse, Select *p){ +static void computeLimitRegisters(Parse *pParse, Select *p, int iBreak){ + Vdbe *v; + int iLimit; + int iOffset; + int addr1, addr2; + /* ** "LIMIT -1" always shows all rows. There is some ** contraversy about what the correct behavior should be. ** The current implementation interprets "LIMIT 0" to mean ** no rows. */ if( p->pLimit ){ - int iMem = pParse->nMem++; - Vdbe *v = sqlite3GetVdbe(pParse); + p->iLimit = iLimit = pParse->nMem; + pParse->nMem += 2; + v = sqlite3GetVdbe(pParse); if( v==0 ) return; sqlite3ExprCode(pParse, p->pLimit); sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); - sqlite3VdbeAddOp(v, OP_Negative, 0, 0); - sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1); + sqlite3VdbeAddOp(v, OP_MemStore, iLimit, 0); VdbeComment((v, "# LIMIT counter")); - p->iLimit = iMem; + sqlite3VdbeAddOp(v, OP_IfMemZero, iLimit, iBreak); } if( p->pOffset ){ - int iMem = pParse->nMem++; - Vdbe *v = sqlite3GetVdbe(pParse); + p->iOffset = iOffset = pParse->nMem++; + v = sqlite3GetVdbe(pParse); if( v==0 ) return; sqlite3ExprCode(pParse, p->pOffset); sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); - sqlite3VdbeAddOp(v, OP_Negative, 0, 0); - sqlite3VdbeAddOp(v, OP_MemStore, iMem, 1); + sqlite3VdbeAddOp(v, OP_MemStore, iOffset, p->pLimit==0); VdbeComment((v, "# OFFSET counter")); - p->iOffset = iMem; + addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iOffset, 0); + sqlite3VdbeAddOp(v, OP_Pop, 1, 0); + sqlite3VdbeAddOp(v, OP_Integer, 0, 0); + sqlite3VdbeJumpHere(v, addr1); + if( p->pLimit ){ + sqlite3VdbeAddOp(v, OP_Add, 0, 0); + } + } + if( p->pLimit ){ + addr1 = sqlite3VdbeAddOp(v, OP_IfMemPos, iLimit, 0); + sqlite3VdbeAddOp(v, OP_Pop, 1, 0); + sqlite3VdbeAddOp(v, OP_MemInt, -1, iLimit+1); + addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); + sqlite3VdbeJumpHere(v, addr1); + sqlite3VdbeAddOp(v, OP_MemStore, iLimit+1, 1); + VdbeComment((v, "# LIMIT+OFFSET")); + sqlite3VdbeJumpHere(v, addr2); } } /* ** Allocate a virtual index to use for sorting. @@ -1517,27 +1577,35 @@ */ pOrderBy = p->pOrderBy; switch( p->op ){ case TK_ALL: { if( pOrderBy==0 ){ + int addr = 0; assert( !pPrior->pLimit ); pPrior->pLimit = p->pLimit; pPrior->pOffset = p->pOffset; rc = sqlite3Select(pParse, pPrior, eDest, iParm, 0, 0, 0, aff); + p->pLimit = 0; + p->pOffset = 0; if( rc ){ goto multi_select_end; } p->pPrior = 0; p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; - p->pLimit = 0; - p->pOffset = 0; + if( p->iLimit>=0 ){ + addr = sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, 0); + VdbeComment((v, "# Jump ahead if LIMIT reached")); + } rc = sqlite3Select(pParse, p, eDest, iParm, 0, 0, 0, aff); p->pPrior = pPrior; if( rc ){ goto multi_select_end; } + if( addr ){ + sqlite3VdbeJumpHere(v, addr); + } break; } /* For UNION ALL ... ORDER BY fall through to the next case */ } case TK_EXCEPT: @@ -1620,12 +1688,12 @@ if( eDest==SRT_Callback ){ generateColumnNames(pParse, 0, p->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); + computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak); - computeLimitRegisters(pParse, p); iStart = sqlite3VdbeCurrentAddr(v); rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr, pOrderBy, -1, eDest, iParm, iCont, iBreak, 0); if( rc ){ @@ -1696,12 +1764,12 @@ if( eDest==SRT_Callback ){ generateColumnNames(pParse, 0, p->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); + computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak); - computeLimitRegisters(pParse, p); iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0); sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont); rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr, pOrderBy, -1, eDest, iParm, iCont, iBreak, 0); @@ -1758,11 +1826,11 @@ if( !pKeyInfo ){ rc = SQLITE_NOMEM; goto multi_select_end; } - pKeyInfo->enc = pParse->db->enc; + pKeyInfo->enc = ENC(pParse->db); pKeyInfo->nField = nCol; for(i=0, apColl=pKeyInfo->aColl; ia; - int nExpr = pOrderBy->nExpr; + int nOrderByExpr = pOrderBy->nExpr; int addr; u8 *pSortOrder; aCopy = (CollSeq**)&pKeyInfo[1]; - pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nExpr]; + pSortOrder = pKeyInfo->aSortOrder = (u8*)&aCopy[nCol]; memcpy(aCopy, pKeyInfo->aColl, nCol*sizeof(CollSeq*)); apColl = pKeyInfo->aColl; - for(i=0; inExpr; i++, pOTerm++, apColl++, pSortOrder++){ + for(i=0; ipExpr; char *zName = pOTerm->zName; assert( pExpr->op==TK_COLUMN && pExpr->iColumnpRightmost==p ); assert( p->addrOpenVirt[2]>=0 ); addr = p->addrOpenVirt[2]; sqlite3VdbeChangeP2(v, addr, p->pEList->nExpr+2); - pKeyInfo->nField = pOrderBy->nExpr; + pKeyInfo->nField = nOrderByExpr; sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO_HANDOFF); pKeyInfo = 0; generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm); } @@ -2083,11 +2151,11 @@ substExprList(p->pEList, iParent, pSub->pEList); pList = p->pEList; for(i=0; inExpr; i++){ Expr *pExpr; if( pList->a[i].zName==0 && (pExpr = pList->a[i].pExpr)->span.z!=0 ){ - pList->a[i].zName = sqliteStrNDup(pExpr->span.z, pExpr->span.n); + pList->a[i].zName = sqliteStrNDup((char*)pExpr->span.z, pExpr->span.n); } } if( isAgg ){ substExprList(p->pGroupBy, iParent, pSub->pEList); substExpr(p->pHaving, iParent, pSub->pEList); @@ -2164,14 +2232,15 @@ Table *pTab; Index *pIdx; int base; Vdbe *v; int seekOp; - int cont; ExprList *pEList, *pList, eList; struct ExprList_item eListItem; SrcList *pSrc; + int brk; + int iDb; /* Check to see if this query is a simple min() or max() query. Return ** zero if it is not. */ if( p->pGroupBy || p->pHaving || p->pWhere ) return 0; @@ -2182,21 +2251,22 @@ pExpr = pEList->a[0].pExpr; if( pExpr->op!=TK_AGG_FUNCTION ) return 0; pList = pExpr->pList; if( pList==0 || pList->nExpr!=1 ) return 0; if( pExpr->token.n!=3 ) return 0; - if( sqlite3StrNICmp(pExpr->token.z,"min",3)==0 ){ + if( sqlite3StrNICmp((char*)pExpr->token.z,"min",3)==0 ){ seekOp = OP_Rewind; - }else if( sqlite3StrNICmp(pExpr->token.z,"max",3)==0 ){ + }else if( sqlite3StrNICmp((char*)pExpr->token.z,"max",3)==0 ){ seekOp = OP_Last; }else{ return 0; } pExpr = pList->a[0].pExpr; if( pExpr->op!=TK_COLUMN ) return 0; iCol = pExpr->iColumn; pTab = pSrc->a[0].pTab; + /* If we get to here, it means the query is of the correct form. ** Check to make sure we have an index and make pIdx point to the ** appropriate index. If the min() or max() is on an INTEGER PRIMARY ** key column, no index is necessary so set pIdx to NULL. If no @@ -2229,17 +2299,20 @@ /* Generating code to find the min or the max. Basically all we have ** to do is find the first or the last entry in the chosen index. If ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first ** or last entry in the main table. */ - sqlite3CodeVerifySchema(pParse, pTab->iDb); + iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema); + assert( iDb>=0 || pTab->isTransient ); + sqlite3CodeVerifySchema(pParse, iDb); + sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); base = pSrc->a[0].iCursor; - computeLimitRegisters(pParse, p); + brk = sqlite3VdbeMakeLabel(v); + computeLimitRegisters(pParse, p, brk); if( pSrc->a[0].pSelect==0 ){ - sqlite3OpenTableForReading(v, base, pTab); + sqlite3OpenTable(pParse, base, iDb, pTab, OP_OpenRead); } - cont = sqlite3VdbeMakeLabel(v); if( pIdx==0 ){ sqlite3VdbeAddOp(v, seekOp, base, 0); }else{ /* Even though the cursor used to open the index here is closed ** as soon as a single value has been read from it, allocate it @@ -2247,11 +2320,12 @@ ** reused. This is important for statements of the form ** "INSERT INTO x SELECT max() FROM x". */ int iIdx; iIdx = pParse->nTab++; - sqlite3VdbeAddOp(v, OP_Integer, pIdx->iDb, 0); + assert( pIdx->pSchema==pTab->pSchema ); + sqlite3VdbeAddOp(v, OP_Integer, iDb, 0); sqlite3VdbeOp3(v, OP_OpenRead, iIdx, pIdx->tnum, (char*)&pIdx->keyInfo, P3_KEYINFO); if( seekOp==OP_Rewind ){ sqlite3VdbeAddOp(v, OP_Null, 0, 0); sqlite3VdbeAddOp(v, OP_MakeRecord, 1, 0); @@ -2264,12 +2338,12 @@ } eList.nExpr = 1; memset(&eListItem, 0, sizeof(eListItem)); eList.a = &eListItem; eList.a[0].pExpr = pExpr; - selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont, 0); - sqlite3VdbeResolveLabel(v, cont); + selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, brk, brk, 0); + sqlite3VdbeResolveLabel(v, brk); sqlite3VdbeAddOp(v, OP_Close, base, 0); return 1; } @@ -2354,18 +2428,12 @@ } /* Resolve the expressions in the LIMIT and OFFSET clauses. These ** are not allowed to refer to any names, so pass an empty NameContext. */ + memset(&sNC, 0, sizeof(sNC)); sNC.pParse = pParse; - sNC.hasAgg = 0; - sNC.nErr = 0; - sNC.nRef = 0; - sNC.pEList = 0; - sNC.allowAgg = 0; - sNC.pSrcList = 0; - sNC.pNext = 0; if( sqlite3ExprResolveNames(&sNC, p->pLimit) || sqlite3ExprResolveNames(&sNC, p->pOffset) ){ return SQLITE_ERROR; } @@ -2613,12 +2681,13 @@ int isDistinct; /* True if the DISTINCT keyword is present */ int distinct; /* Table to use for the distinct set */ int rc = 1; /* Value to return from this function */ int addrSortIndex; /* Address of an OP_OpenVirtual instruction */ AggInfo sAggInfo; /* Information used by aggregate queries */ + int iEnd; /* Address of the end of the query */ - if( sqlite3_malloc_failed || pParse->nErr || p==0 ) return 1; + if( sqlite3ThreadData()->mallocFailed || pParse->nErr || p==0 ) return 1; if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; memset(&sAggInfo, 0, sizeof(sAggInfo)); #ifndef SQLITE_OMIT_COMPOUND_SELECT /* If there is are a sequence of queries, do the earlier ones first. @@ -2661,11 +2730,10 @@ if( pParse->nErr>0 ) goto select_end; /* If writing to memory or generating a set ** only a single column may be output. */ - assert( eDest!=SRT_Exists || pEList->nExpr==1 ); #ifndef SQLITE_OMIT_SUBQUERY if( (eDest==SRT_Mem || eDest==SRT_Set) && pEList->nExpr>1 ){ sqlite3ErrorMsg(pParse, "only a single result allowed for " "a SELECT that is part of an expression"); goto select_end; @@ -2770,27 +2838,19 @@ addrSortIndex = -1; } /* Set the limiter. */ - computeLimitRegisters(pParse, p); + iEnd = sqlite3VdbeMakeLabel(v); + computeLimitRegisters(pParse, p, iEnd); /* If the output is destined for a temporary table, open that table. */ if( eDest==SRT_VirtualTab ){ sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr); } - - /* Initialize the memory cell to NULL for SRT_Mem or 0 for SRT_Exists - */ - if( eDest==SRT_Mem ){ - sqlite3VdbeAddOp(v, OP_MemNull, iParm, 0); - }else if( eDest==SRT_Exists ){ - sqlite3VdbeAddOp(v, OP_MemInt, 0, iParm); - } - /* Open a virtual index to use for the distinct set. */ if( isDistinct ){ KeyInfo *pKeyInfo; distinct = pParse->nTab++; @@ -2877,11 +2937,11 @@ for(i=0; ipList) ){ goto select_end; } } - if( sqlite3_malloc_failed ) goto select_end; + if( sqlite3ThreadData()->mallocFailed ) goto select_end; /* Processing for aggregates with GROUP BY is very different and ** much more complex tha aggregates without a GROUP BY. */ if( pGroupBy ){ @@ -3110,10 +3170,14 @@ sqlite3SelectDelete(p); pParent->pSrc->a[parentTab].pSelect = 0; } #endif + /* Jump here to skip this query + */ + sqlite3VdbeResolveLabel(v, iEnd); + /* The SELECT was successfully coded. Set the return code to 0 ** to indicate no errors. */ rc = 0; ADDED SQLite.Interop/src/server.c Index: SQLite.Interop/src/server.c ================================================================== --- /dev/null +++ SQLite.Interop/src/server.c @@ -0,0 +1,428 @@ +/* +** 2006 January 07 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +****************************************************************************** +** +** This file contains demonstration code. Nothing in this file gets compiled +** or linked into the SQLite library unless you use a non-standard option: +** +** -DSQLITE_SERVER=1 +** +** The configure script will never generate a Makefile with the option +** above. You will need to manually modify the Makefile if you want to +** include any of the code from this file in your project. Or, at your +** option, you may want to copy and paste the code from this file and +** thereby avoiding a recompile of SQLite. +** +** +** This source file demonstrates how to use SQLite to create an SQL database +** server thread in a multiple-threaded program. One or more client threads +** send messages to the server thread and the server thread processes those +** messages in the order received and returns the results to the client. +** +** One might ask: "Why bother? Why not just let each thread connect +** to the database directly?" There are a several of reasons to +** prefer the client/server approach. +** +** (1) Some systems (ex: Redhat9) have broken threading implementations +** that prevent SQLite database connections from being used in +** a thread different from the one where they were created. With +** the client/server approach, all database connections are created +** and used within the server thread. Client calls to the database +** can be made from multiple threads (though not at the same time!) +** +** (2) Beginning with SQLite version 3.3.0, when two or more +** connections to the same database occur within the same thread, +** they will share their database cache. This reduces I/O +** and memory requirements. +** +** (3) Database connections on a shared cache use table-level locking +** instead of file-level locking for improved concurrency. +** +** (4) Database connections on a shared cache can by optionally +** set to READ UNCOMMITTED isolation. (The default isolation for +** SQLite is SERIALIZABLE.) When this occurs, readers will +** never be blocked by a writer and writers will not be +** blocked by readers. There can still only be a single writer +** at a time, but multiple readers can simultaneously exist with +** that writer. This is a huge increase in concurrency. +** +** To summarize the rational for using a client/server approach: prior +** to SQLite version 3.3.0 it probably was not worth the trouble. But +** with SQLite version 3.3.0 and beyond you can get significant performance +** and concurrency improvements and memory usage reductions by going +** client/server. +** +** Note: The extra features of version 3.3.0 described by points (2) +** through (4) above are only available if you compile without the +** option -DSQLITE_OMIT_SHARED_CACHE. For reasons of backwards +** compatibility, SQLite is compile with this option by default. +** +** Here is how the client/server approach works: The database server +** thread is started on this procedure: +** +** void *sqlite3_server(void *NotUsed); +** +** The sqlite_server procedure runs as long as the g.serverHalt variable +** is false. A mutex is used to make sure no more than one server runs +** at a time. The server waits for messages to arrive on a message +** queue and processes the messages in order. +** +** Two convenience routines are provided for starting and stopping the +** server thread: +** +** void sqlite3_server_start(void); +** void sqlite3_server_stop(void); +** +** Both of the convenience routines return immediately. Neither will +** ever give an error. If a server is already started or already halted, +** then the routines are effectively no-ops. +** +** Clients use the following interfaces: +** +** sqlite3_client_open +** sqlite3_client_prepare +** sqlite3_client_step +** sqlite3_client_reset +** sqlite3_client_finalize +** sqlite3_client_close +** +** These interfaces work exactly like the standard core SQLite interfaces +** having the same names without the "_client_" infix. Many other SQLite +** interfaces can be used directly without having to send messages to the +** server. The following interfaces fall into this second category: +** +** sqlite3_bind_* +** sqlite3_changes +** sqlite3_clear_bindings +** sqlite3_column_* +** sqlite3_complete +** sqlite3_create_collation +** sqlite3_create_function +** sqlite3_data_count +** sqlite3_db_handle +** sqlite3_errcode +** sqlite3_errmsg +** sqlite3_last_insert_rowid +** sqlite3_libversion +** sqlite3_mprintf +** sqlite3_total_changes +** sqlite3_transfer_bindings +** sqlite3_vmprintf +** +** A single SQLite connection (an sqlite3* object) or an SQLite statement +** (an sqlite3_stmt* object) should only be passed to a single interface +** function at a time. The connections and statements can be freely used +** by any thread as long as only one thread is using them at a time. +** +** The busy handler for all database connections should remain turned +** off. That means that any lock contention will cause the associated +** sqlite3_client_step() call to return immediately with an SQLITE_BUSY +** error code. If a busy handler is enabled and lock contention occurs, +** then the entire server thread will block. This will cause not only +** the requesting client to block but every other database client as +** well. It is possible to enhance the code below so that lock +** contention will cause the message to be placed back on the top of +** the queue to be tried again later. But such enhanced processing is +** not included here, in order to keep the example simple. +** +** This code assumes the use of pthreads. Pthreads implementations +** are available for windows. (See, for example +** http://sourceware.org/pthreads-win32/announcement.html.) Or, you +** can translate the locking and thread synchronization code to use +** windows primitives easily enough. The details are left as an +** exercise to the reader. +*/ + +/* +** Only compile the code in this file on UNIX with a THREADSAFE build +** and only if the SQLITE_SERVER macro is defined. +*/ +#ifdef SQLITE_SERVER +#if defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE + +/* +** We require only pthreads and the public interface of SQLite. +*/ +#include +#include "sqlite3.h" + +/* +** Messages are passed from client to server and back again as +** instances of the following structure. +*/ +typedef struct SqlMessage SqlMessage; +struct SqlMessage { + int op; /* Opcode for the message */ + sqlite3 *pDb; /* The SQLite connection */ + sqlite3_stmt *pStmt; /* A specific statement */ + int errCode; /* Error code returned */ + const char *zIn; /* Input filename or SQL statement */ + int nByte; /* Size of the zIn parameter for prepare() */ + const char *zOut; /* Tail of the SQL statement */ + SqlMessage *pNext; /* Next message in the queue */ + SqlMessage *pPrev; /* Previous message in the queue */ + pthread_mutex_t clientMutex; /* Hold this mutex to access the message */ + pthread_cond_t clientWakeup; /* Signal to wake up the client */ +}; + +/* +** Legal values for SqlMessage.op +*/ +#define MSG_Open 1 /* sqlite3_open(zIn, &pDb) */ +#define MSG_Prepare 2 /* sqlite3_prepare(pDb, zIn, nByte, &pStmt, &zOut) */ +#define MSG_Step 3 /* sqlite3_step(pStmt) */ +#define MSG_Reset 4 /* sqlite3_reset(pStmt) */ +#define MSG_Finalize 5 /* sqlite3_finalize(pStmt) */ +#define MSG_Close 6 /* sqlite3_close(pDb) */ +#define MSG_Done 7 /* Server has finished with this message */ + + +/* +** State information about the server is stored in a static variable +** named "g" as follows: +*/ +static struct ServerState { + pthread_mutex_t queueMutex; /* Hold this mutex to access the msg queue */ + pthread_mutex_t serverMutex; /* Held by the server while it is running */ + pthread_cond_t serverWakeup; /* Signal this condvar to wake up the server */ + volatile int serverHalt; /* Server halts itself when true */ + SqlMessage *pQueueHead; /* Head of the message queue */ + SqlMessage *pQueueTail; /* Tail of the message queue */ +} g = { + PTHREAD_MUTEX_INITIALIZER, + PTHREAD_MUTEX_INITIALIZER, + PTHREAD_COND_INITIALIZER, +}; + +/* +** Send a message to the server. Block until we get a reply. +** +** The mutex and condition variable in the message are uninitialized +** when this routine is called. This routine takes care of +** initializing them and destroying them when it has finished. +*/ +static void sendToServer(SqlMessage *pMsg){ + /* Initialize the mutex and condition variable on the message + */ + pthread_mutex_init(&pMsg->clientMutex, 0); + pthread_cond_init(&pMsg->clientWakeup, 0); + + /* Add the message to the head of the server's message queue. + */ + pthread_mutex_lock(&g.queueMutex); + pMsg->pNext = g.pQueueHead; + if( g.pQueueHead==0 ){ + g.pQueueTail = pMsg; + }else{ + g.pQueueHead->pPrev = pMsg; + } + pMsg->pPrev = 0; + g.pQueueHead = pMsg; + pthread_mutex_unlock(&g.queueMutex); + + /* Signal the server that the new message has be queued, then + ** block waiting for the server to process the message. + */ + pthread_mutex_lock(&pMsg->clientMutex); + pthread_cond_signal(&g.serverWakeup); + while( pMsg->op!=MSG_Done ){ + pthread_cond_wait(&pMsg->clientWakeup, &pMsg->clientMutex); + } + pthread_mutex_unlock(&pMsg->clientMutex); + + /* Destroy the mutex and condition variable of the message. + */ + pthread_mutex_destroy(&pMsg->clientMutex); + pthread_cond_destroy(&pMsg->clientWakeup); +} + +/* +** The following 6 routines are client-side implementations of the +** core SQLite interfaces: +** +** sqlite3_open +** sqlite3_prepare +** sqlite3_step +** sqlite3_reset +** sqlite3_finalize +** sqlite3_close +** +** Clients should use the following client-side routines instead of +** the core routines. +** +** sqlite3_client_open +** sqlite3_client_prepare +** sqlite3_client_step +** sqlite3_client_reset +** sqlite3_client_finalize +** sqlite3_client_close +** +** Each of these routines creates a message for the desired operation, +** sends that message to the server, waits for the server to process +** then message and return a response. +*/ +int sqlite3_client_open(const char *zDatabaseName, sqlite3 **ppDb){ + SqlMessage msg; + msg.op = MSG_Open; + msg.zIn = zDatabaseName; + sendToServer(&msg); + *ppDb = msg.pDb; + return msg.errCode; +} +int sqlite3_client_prepare( + sqlite3 *pDb, + const char *zSql, + int nByte, + sqlite3_stmt **ppStmt, + const char **pzTail +){ + SqlMessage msg; + msg.op = MSG_Prepare; + msg.pDb = pDb; + msg.zIn = zSql; + msg.nByte = nByte; + sendToServer(&msg); + *ppStmt = msg.pStmt; + if( pzTail ) *pzTail = msg.zOut; + return msg.errCode; +} +int sqlite3_client_step(sqlite3_stmt *pStmt){ + SqlMessage msg; + msg.op = MSG_Step; + msg.pStmt = pStmt; + sendToServer(&msg); + return msg.errCode; +} +int sqlite3_client_reset(sqlite3_stmt *pStmt){ + SqlMessage msg; + msg.op = MSG_Reset; + msg.pStmt = pStmt; + sendToServer(&msg); + return msg.errCode; +} +int sqlite3_client_finalize(sqlite3_stmt *pStmt){ + SqlMessage msg; + msg.op = MSG_Finalize; + msg.pStmt = pStmt; + sendToServer(&msg); + return msg.errCode; +} +int sqlite3_client_close(sqlite3 *pDb){ + SqlMessage msg; + msg.op = MSG_Close; + msg.pDb = pDb; + sendToServer(&msg); + return msg.errCode; +} + +/* +** This routine implements the server. To start the server, first +** make sure g.serverHalt is false, then create a new detached thread +** on this procedure. See the sqlite3_server_start() routine below +** for an example. This procedure loops until g.serverHalt becomes +** true. +*/ +void *sqlite3_server(void *NotUsed){ + sqlite3_enable_shared_cache(1); + if( pthread_mutex_trylock(&g.serverMutex) ){ + return 0; /* Another server is already running */ + } + while( !g.serverHalt ){ + SqlMessage *pMsg; + + /* Remove the last message from the message queue. + */ + pthread_mutex_lock(&g.queueMutex); + while( g.pQueueTail==0 && g.serverHalt==0 ){ + pthread_cond_wait(&g.serverWakeup, &g.queueMutex); + } + pMsg = g.pQueueTail; + if( pMsg ){ + if( pMsg->pPrev ){ + pMsg->pPrev->pNext = 0; + }else{ + g.pQueueHead = 0; + } + g.pQueueTail = pMsg->pPrev; + } + pthread_mutex_unlock(&g.queueMutex); + if( pMsg==0 ) break; + + /* Process the message just removed + */ + pthread_mutex_lock(&pMsg->clientMutex); + switch( pMsg->op ){ + case MSG_Open: { + pMsg->errCode = sqlite3_open(pMsg->zIn, &pMsg->pDb); + break; + } + case MSG_Prepare: { + pMsg->errCode = sqlite3_prepare(pMsg->pDb, pMsg->zIn, pMsg->nByte, + &pMsg->pStmt, &pMsg->zOut); + break; + } + case MSG_Step: { + pMsg->errCode = sqlite3_step(pMsg->pStmt); + break; + } + case MSG_Reset: { + pMsg->errCode = sqlite3_reset(pMsg->pStmt); + break; + } + case MSG_Finalize: { + pMsg->errCode = sqlite3_finalize(pMsg->pStmt); + break; + } + case MSG_Close: { + pMsg->errCode = sqlite3_close(pMsg->pDb); + break; + } + } + + /* Signal the client that the message has been processed. + */ + pMsg->op = MSG_Done; + pthread_mutex_unlock(&pMsg->clientMutex); + pthread_cond_signal(&pMsg->clientWakeup); + } + pthread_mutex_unlock(&g.serverMutex); + return 0; +} + +/* +** Start a server thread if one is not already running. If there +** is aleady a server thread running, the new thread will quickly +** die and this routine is effectively a no-op. +*/ +void sqlite3_server_start(void){ + pthread_t x; + int rc; + g.serverHalt = 0; + rc = pthread_create(&x, 0, sqlite3_server, 0); + if( rc==0 ){ + pthread_detach(x); + } +} + +/* +** If a server thread is running, then stop it. If no server is +** running, this routine is effectively a no-op. +** +** This routine returns immediately without waiting for the server +** thread to stop. But be assured that the server will eventually stop. +*/ +void sqlite3_server_stop(void){ + g.serverHalt = 1; + pthread_cond_broadcast(&g.serverWakeup); +} + +#endif /* defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE */ +#endif /* defined(SQLITE_SERVER) */ Index: SQLite.Interop/src/shell.c ================================================================== --- SQLite.Interop/src/shell.c +++ SQLite.Interop/src/shell.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** This file contains code to implement the "sqlite" command line ** utility for accessing SQLite databases. ** -** $Id: shell.c,v 1.10 2005/12/19 17:57:48 rmsimpson Exp $ +** $Id: shell.c,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #include #include #include #include @@ -79,11 +79,11 @@ /* ** Determines if a string is a number of not. */ -static int isNumber(const unsigned char *z, int *realnum){ +static int isNumber(const char *z, int *realnum){ if( *z=='-' || *z=='+' ) z++; if( !isdigit(*z) ){ return 0; } z++; @@ -688,12 +688,13 @@ zSelect = appendText(zSelect, zTmp, '\''); } zSelect = appendText(zSelect, " || ' VALUES(' || ", 0); rc = sqlite3_step(pTableInfo); while( rc==SQLITE_ROW ){ + const char *zText = (const char *)sqlite3_column_text(pTableInfo, 1); zSelect = appendText(zSelect, "quote(", 0); - zSelect = appendText(zSelect, sqlite3_column_text(pTableInfo, 1), '"'); + zSelect = appendText(zSelect, zText, '"'); rc = sqlite3_step(pTableInfo); if( rc==SQLITE_ROW ){ zSelect = appendText(zSelect, ") || ', ' || ", 0); }else{ zSelect = appendText(zSelect, ") ", 0); @@ -827,11 +828,11 @@ }else if( c=='t' ){ c = '\t'; }else if( c=='r' ){ c = '\r'; }else if( c>='0' && c<='7' ){ - c =- '0'; + c -= '0'; if( z[i+1]>='0' && z[i+1]<='7' ){ i++; c = (c<<3) + z[i] - '0'; if( z[i+1]>='0' && z[i+1]<='7' ){ i++; Index: SQLite.Interop/src/sqlite3.h ================================================================== --- SQLite.Interop/src/sqlite3.h +++ SQLite.Interop/src/sqlite3.h @@ -10,11 +10,11 @@ ** ************************************************************************* ** This header file defines the interface that the SQLite library ** presents to client programs. ** -** @(#) $Id: sqlite3.h,v 1.11 2005/12/19 17:57:48 rmsimpson Exp $ +** @(#) $Id: sqlite3.h,v 1.12 2006/01/10 18:40:37 rmsimpson Exp $ */ #ifndef _SQLITE3_H_ #define _SQLITE3_H_ #include /* Needed for the definition of va_list */ @@ -84,10 +84,17 @@ #else typedef long long int sqlite_int64; typedef unsigned long long int sqlite_uint64; #endif +/* +** If compiling for a processor that lacks floating point support, +** substitute integer for floating-point +*/ +#ifdef SQLITE_OMIT_FLOATING_POINT +# define double sqlite_int64 +#endif /* ** A function to close the database. ** ** Call this function with a pointer to a structure that was previously @@ -1249,11 +1256,11 @@ ** dangerous and will almost certainly result in malfunctions. ** ** This functionality can be omitted from a build by defining the ** SQLITE_OMIT_GLOBALRECOVER at compile time. */ -int sqlite3_global_recover(); +int sqlite3_global_recover(void); /* ** Test to see whether or not the database connection is in autocommit ** mode. Return TRUE if it is and FALSE if not. Autocommit mode is on ** by default. Autocommit is disabled by a BEGIN statement and reenabled @@ -1267,9 +1274,104 @@ ** the first argument to the sqlite3_prepare() that was used to create ** the statement in the first place. */ sqlite3 *sqlite3_db_handle(sqlite3_stmt*); +/* +** Register a callback function with the database connection identified by the +** first argument to be invoked whenever a row is updated, inserted or deleted. +** Any callback set by a previous call to this function for the same +** database connection is overridden. +** +** The second argument is a pointer to the function to invoke when a +** row is updated, inserted or deleted. The first argument to the callback is +** a copy of the third argument to sqlite3_update_hook. The second callback +** argument is one of SQLITE_INSERT, SQLITE_DELETE or SQLITE_UPDATE, depending +** on the operation that caused the callback to be invoked. The third and +** fourth arguments to the callback contain pointers to the database and +** table name containing the affected row. The final callback parameter is +** the rowid of the row. In the case of an update, this is the rowid after +** the update takes place. +** +** The update hook is not invoked when internal system tables are +** modified (i.e. sqlite_master and sqlite_sequence). +** +** If another function was previously registered, its pArg value is returned. +** Otherwise NULL is returned. +*/ +void *sqlite3_update_hook( + sqlite3*, + void(*)(void *,int ,char const *,char const *,sqlite_int64), + void* +); + +/* +** Register a callback to be invoked whenever a transaction is rolled +** back. +** +** The new callback function overrides any existing rollback-hook +** callback. If there was an existing callback, then it's pArg value +** (the third argument to sqlite3_rollback_hook() when it was registered) +** is returned. Otherwise, NULL is returned. +** +** For the purposes of this API, a transaction is said to have been +** rolled back if an explicit "ROLLBACK" statement is executed, or +** an error or constraint causes an implicit rollback to occur. The +** callback is not invoked if a transaction is automatically rolled +** back because the database connection is closed. +*/ +void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); + +/* +** This function is only available if the library is compiled without +** the SQLITE_OMIT_SHARED_CACHE macro defined. It is used to enable or +** disable (if the argument is true or false, respectively) the +** "shared pager" feature. +*/ +int sqlite3_enable_shared_cache(int); + +/* +** This function is only available if the library is compiled without +** the SQLITE_OMIT_MEMORY_MANAGEMENT macro defined. It is used to enable or +** disable (if the argument is true or false, respectively) the +** "memory management" features (accessed via the sqlite3_soft_heap_limit() +** and sqlite3_release_memory() APIs). +*/ +int sqlite3_enable_memory_management(int); + +/* +** Attempt to free N bytes of heap memory by deallocating non-essential +** memory allocations held by the database library (example: memory +** used to cache database pages to improve performance). +** +** This function is a no-op unless memory-management has been enabled. +*/ +int sqlite3_release_memory(int); + +/* +** Place a "soft" limit on the amount of heap memory that may be allocated by +** SQLite within the current thread. If an internal allocation is requested +** that would exceed the specified limit, sqlite3_release_memory() is invoked +** one or more times to free up some space before the allocation is made. +** +** The limit is called "soft", because if sqlite3_release_memory() cannot free +** sufficient memory to prevent the limit from being exceeded, the memory is +** allocated anyway and the current operation proceeds. +** +** This function is only available if the library was compiled without the +** SQLITE_OMIT_MEMORY_MANAGEMENT option set. It is a no-op unless +** memory-management has been enabled. +*/ +void sqlite3_soft_heap_limit(sqlite_int64); + +/* +** Undo the hack that converts floating point types to integer for +** builds on processors without floating point support. +*/ +#ifdef SQLITE_OMIT_FLOATING_POINT +# undef double +#endif + #ifdef __cplusplus } /* End of the 'extern "C"' block */ #endif #endif Index: SQLite.Interop/src/sqliteInt.h ================================================================== --- SQLite.Interop/src/sqliteInt.h +++ SQLite.Interop/src/sqliteInt.h @@ -9,15 +9,22 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.10 2005/12/19 17:57:48 rmsimpson Exp $ +** @(#) $Id: sqliteInt.h,v 1.11 2006/01/10 18:40:37 rmsimpson Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ +/* +** Extra interface definitions for those who need them +*/ +#ifdef SQLITE_EXTRA +# include "sqliteExtra.h" +#endif + /* ** Many people are failing to set -DNDEBUG=1 when compiling SQLite. ** Setting NDEBUG makes the code smaller and run faster. So the following ** lines are added to automatically set NDEBUG unless the -DSQLITE_DEBUG=1 ** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out @@ -57,10 +64,22 @@ #include #include #include #include +/* +** If compiling for a processor that lacks floating point support, +** substitute integer for floating-point +*/ +#ifdef SQLITE_OMIT_FLOATING_POINT +# define double sqlite_int64 +# define LONGDOUBLE_TYPE sqlite_int64 +# define SQLITE_BIG_DBL (0x7fffffffffffffff) +# define SQLITE_OMIT_DATETIME_FUNCS 1 +# define SQLITE_OMIT_TRACE 1 +#endif + /* ** The maximum number of in-memory pages to use for the main database ** table and for temporary tables. Internally, the MAX_PAGES and ** TEMP_PAGES macros are used. To override the default values at ** compilation time, the SQLITE_DEFAULT_CACHE_SIZE and @@ -127,22 +146,19 @@ ** The maximum value of a ?nnn wildcard that the parser will accept. */ #define SQLITE_MAX_VARIABLE_NUMBER 999 /* -** When building SQLite for embedded systems where memory is scarce, -** you can define one or more of the following macros to omit extra -** features of the library and thus keep the size of the library to -** a minimum. +** The "file format" number is an integer that is incremented whenever +** the VDBE-level file format changes. The following macros define the +** the default file format for new databases and the maximum file format +** that the library can read. */ -/* #define SQLITE_OMIT_AUTHORIZATION 1 */ -/* #define SQLITE_OMIT_MEMORYDB 1 */ -/* #define SQLITE_OMIT_VACUUM 1 */ -/* #define SQLITE_OMIT_DATETIME_FUNCS 1 */ -/* #define SQLITE_OMIT_PROGRESS_CALLBACK 1 */ -/* #define SQLITE_OMIT_AUTOVACUUM */ -/* #define SQLITE_OMIT_ALTERTABLE */ +#define SQLITE_MAX_FILE_FORMAT 4 +#ifndef SQLITE_DEFAULT_FILE_FORMAT +# define SQLITE_DEFAULT_FILE_FORMAT 4 +#endif /* ** Provide a default value for TEMP_STORE in case it is not specified ** on the command-line */ @@ -226,63 +242,79 @@ ** Defer sourcing vdbe.h and btree.h until after the "u8" and ** "BusyHandler typedefs. */ #include "vdbe.h" #include "btree.h" +#include "pager.h" /* ** This macro casts a pointer to an integer. Useful for doing ** pointer arithmetic. */ #define Addr(X) ((uptr)X) -/* -** If memory allocation problems are found, recompile with -** -** -DSQLITE_DEBUG=1 -** -** to enable some sanity checking on malloc() and free(). To -** check for memory leaks, recompile with -** -** -DSQLITE_DEBUG=2 -** -** and a line of text will be written to standard error for -** each malloc() and free(). This output can be analyzed -** by an AWK script to determine if there are any leaks. -*/ #ifdef SQLITE_MEMDEBUG -# define sqliteMalloc(X) sqlite3Malloc_(X,1,__FILE__,__LINE__) -# define sqliteMallocRaw(X) sqlite3Malloc_(X,0,__FILE__,__LINE__) -# define sqliteFree(X) sqlite3Free_(X,__FILE__,__LINE__) -# define sqliteRealloc(X,Y) sqlite3Realloc_(X,Y,__FILE__,__LINE__) -# define sqliteStrDup(X) sqlite3StrDup_(X,__FILE__,__LINE__) -# define sqliteStrNDup(X,Y) sqlite3StrNDup_(X,Y,__FILE__,__LINE__) -#else -# define sqliteFree sqlite3FreeX -# define sqliteMalloc sqlite3Malloc -# define sqliteMallocRaw sqlite3MallocRaw -# define sqliteRealloc sqlite3Realloc -# define sqliteStrDup sqlite3StrDup -# define sqliteStrNDup sqlite3StrNDup -#endif - -/* -** This variable gets set if malloc() ever fails. After it gets set, -** the SQLite library shuts down permanently. -*/ -extern int sqlite3_malloc_failed; - /* ** The following global variables are used for testing and debugging -** only. They only work if SQLITE_DEBUG is defined. +** only. They only work if SQLITE_MEMDEBUG is defined. */ -#ifdef SQLITE_MEMDEBUG extern int sqlite3_nMalloc; /* Number of sqliteMalloc() calls */ extern int sqlite3_nFree; /* Number of sqliteFree() calls */ extern int sqlite3_iMallocFail; /* Fail sqliteMalloc() after this many calls */ extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */ +#define ENTER_MALLOC (\ + sqlite3ThreadData()->zFile = __FILE__, sqlite3ThreadData()->iLine = __LINE__ \ +) +#define sqliteMalloc(x) (ENTER_MALLOC, sqlite3Malloc(x)) +#define sqliteMallocRaw(x) (ENTER_MALLOC, sqlite3MallocRaw(x)) +#define sqliteRealloc(x,y) (ENTER_MALLOC, sqlite3Realloc(x,y)) +#define sqliteStrDup(x) (ENTER_MALLOC, sqlite3StrDup(x)) +#define sqliteStrNDup(x,y) (ENTER_MALLOC, sqlite3StrNDup(x,y)) +#define sqliteReallocOrFree(x,y) (ENTER_MALLOC, sqlite3ReallocOrFree(x,y)) + +#else + +#define sqliteMalloc(x) sqlite3Malloc(x) +#define sqliteMallocRaw(x) sqlite3MallocRaw(x) +#define sqliteRealloc(x,y) sqlite3Realloc(x,y) +#define sqliteStrDup(x) sqlite3StrDup(x) +#define sqliteStrNDup(x,y) sqlite3StrNDup(x,y) +#define sqliteReallocOrFree(x,y) sqlite3ReallocOrFree(x,y) + +#endif + +#define sqliteFree(x) sqlite3FreeX(x) +#define sqliteAllocSize(x) sqlite3AllocSize(x) + +/* +** An instance of this structure is allocated for each thread that uses SQLite. +*/ +struct ThreadData { + u8 isInit; /* True if structure has been initialised */ + u8 mallocFailed; /* True after a malloc() has failed */ + +#ifndef SQLITE_OMIT_MEMORY_MANAGEMENT + u8 useMemoryManagement; /* True if memory-management is enabled */ + i64 nSoftHeapLimit; /* Suggested max mem allocation. No limit if <0 */ + i64 nAlloc; /* Number of bytes currently allocated */ + Pager *pPager; /* Linked list of all pagers in this thread */ +#endif + +#ifndef SQLITE_OMIT_SHARED_CACHE + u8 useSharedData; /* True if shared pagers and schemas are enabled */ + BtShared *pBtree; /* Linked list of all currently open BTrees */ +#endif + +#ifdef SQLITE_MEMDEBUG + i64 nMaxAlloc; /* High water mark of ThreadData.nAlloc */ + int mallocAllowed; /* assert() in sqlite3Malloc() if not set */ + int isFail; /* True if all malloc() calls should fail */ + const char *zFile; /* Filename to associate debugging info with */ + int iLine; /* Line number to associate debugging info with */ + void *pFirst; /* Pointer to linked list of allocations */ #endif +}; /* ** Name of the master database table. The master database table ** is a special table that holds the names and attributes of all ** user tables and indices. @@ -312,10 +344,11 @@ typedef struct AggInfo AggInfo; typedef struct AuthContext AuthContext; typedef struct CollSeq CollSeq; typedef struct Column Column; typedef struct Db Db; +typedef struct Schema Schema; typedef struct Expr Expr; typedef struct ExprList ExprList; typedef struct FKey FKey; typedef struct FuncDef FuncDef; typedef struct IdList IdList; @@ -324,11 +357,13 @@ typedef struct KeyInfo KeyInfo; typedef struct NameContext NameContext; typedef struct Parse Parse; typedef struct Select Select; typedef struct SrcList SrcList; +typedef struct ThreadData ThreadData; typedef struct Table Table; +typedef struct TableLock TableLock; typedef struct Token Token; typedef struct TriggerStack TriggerStack; typedef struct TriggerStep TriggerStep; typedef struct Trigger Trigger; typedef struct WhereInfo WhereInfo; @@ -342,32 +377,41 @@ ** databases may be attached. */ struct Db { char *zName; /* Name of this database */ Btree *pBt; /* The B*Tree structure for this database file */ + u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */ + u8 safety_level; /* How aggressive at synching data to disk */ + void *pAux; /* Auxiliary data. Usually NULL */ + void (*xFreeAux)(void*); /* Routine to free pAux */ + Schema *pSchema; /* Pointer to database schema (possibly shared) */ +}; + +/* +** An instance of the following structure stores a database schema. +*/ +struct Schema { int schema_cookie; /* Database schema version number for this file */ Hash tblHash; /* All tables indexed by name */ Hash idxHash; /* All (named) indices indexed by name */ Hash trigHash; /* All triggers indexed by name */ Hash aFKey; /* Foreign keys indexed by to-table */ - u16 flags; /* Flags associated with this database */ - u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */ - u8 safety_level; /* How aggressive at synching data to disk */ + Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ + u8 file_format; /* Schema format version for this file */ + u16 flags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ - Table *pSeqTab; /* The sqlite_sequence table used by AUTOINCREMENT */ - void *pAux; /* Auxiliary data. Usually NULL */ - void (*xFreeAux)(void*); /* Routine to free pAux */ + u8 enc; /* Text encoding used by this database */ }; /* ** These macros can be used to test, set, or clear bits in the ** Db.flags field. */ -#define DbHasProperty(D,I,P) (((D)->aDb[I].flags&(P))==(P)) -#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].flags&(P))!=0) -#define DbSetProperty(D,I,P) (D)->aDb[I].flags|=(P) -#define DbClearProperty(D,I,P) (D)->aDb[I].flags&=~(P) +#define DbHasProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))==(P)) +#define DbHasAnyProperty(D,I,P) (((D)->aDb[I].pSchema->flags&(P))!=0) +#define DbSetProperty(D,I,P) (D)->aDb[I].pSchema->flags|=(P) +#define DbClearProperty(D,I,P) (D)->aDb[I].pSchema->flags&=~(P) /* ** Allowed values for the DB.flags field. ** ** The DB_SchemaLoaded flag is set after the database schema has been @@ -411,13 +455,11 @@ struct sqlite3 { int nDb; /* Number of backends currently in use */ Db *aDb; /* All backends */ int flags; /* Miscellanous flags. See below */ int errCode; /* Most recent error code (SQLITE_*) */ - u8 enc; /* Text encoding for this database. */ u8 autoCommit; /* The auto-commit flag. */ - u8 file_format; /* What file format version is this database? */ u8 temp_store; /* 1: file 2: memory 0: default */ int nTable; /* Number of tables in the database */ CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 priorNewRowid; /* Last randomly generated ROWID */ @@ -433,16 +475,19 @@ int activeVdbeCnt; /* Number of vdbes currently executing */ void (*xTrace)(void*,const char*); /* Trace function */ void *pTraceArg; /* Argument to the trace function */ void (*xProfile)(void*,const char*,u64); /* Profiling function */ void *pProfileArg; /* Argument to profile function */ - void *pCommitArg; /* Argument to xCommitCallback() */ - int (*xCommitCallback)(void*);/* Invoked at every commit. */ + void *pCommitArg; /* Argument to xCommitCallback() */ + int (*xCommitCallback)(void*); /* Invoked at every commit. */ + void *pRollbackArg; /* Argument to xRollbackCallback() */ + void (*xRollbackCallback)(void*); /* Invoked at every commit. */ + void *pUpdateArg; + void (*xUpdateCallback)(void*,int, const char*,const char*,sqlite_int64); void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*); void(*xCollNeeded16)(void*,sqlite3*,int eTextRep,const void*); void *pCollNeededArg; - sqlite3_value *pValue; /* Value used for transient conversions */ sqlite3_value *pErr; /* Most recent error message */ char *zErrMsg; /* Most recent error message (UTF-8 encoded) */ char *zErrMsg16; /* Most recent error message (UTF-16 encoded) */ #ifndef SQLITE_OMIT_AUTHORIZATION int (*xAuth)(void*,int,const char*,const char*,const char*,const char*); @@ -465,10 +510,12 @@ #ifdef SQLITE_SSE sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */ #endif }; +#define ENC(db) ((db)->aDb[0].pSchema->enc) + /* ** Possible values for the sqlite.flags and or Db.flags fields. ** ** On sqlite.flags, the SQLITE_InTrans value means that we have ** executed a BEGIN. On Db.flags, SQLITE_InTrans means a statement @@ -489,10 +536,12 @@ #define SQLITE_SqlTrace 0x00000200 /* Debug print SQL as it executes */ #define SQLITE_VdbeListing 0x00000400 /* Debug listings of VDBE programs */ #define SQLITE_WriteSchema 0x00000800 /* OK to update SQLITE_MASTER */ #define SQLITE_NoReadlock 0x00001000 /* Readlocks are omitted when ** accessing read-only databases */ +#define SQLITE_IgnoreChecks 0x00002000 /* Do not enforce check constraints */ +#define SQLITE_ReadUncommitted 0x00004000 /* For shared-cache mode */ /* ** Possible values for the sqlite.magic field. ** The numbers are obtained at random and have no special meaning, other ** than being distinct from one another. @@ -584,16 +633,29 @@ #define SQLITE_SO_ASC 0 /* Sort in ascending order */ #define SQLITE_SO_DESC 1 /* Sort in ascending order */ /* ** Column affinity types. +** +** These used to have mnemonic name like 'i' for SQLITE_AFF_INTEGER and +** 't' for SQLITE_AFF_TEXT. But we can save a little space and improve +** the speed a little by number the values consecutively. +** +** But rather than start with 0 or 1, we begin with 'a'. That way, +** when multiple affinity types are concatenated into a string and +** used as the P3 operand, they will be more readable. +** +** Note also that the numeric types are grouped together so that testing +** for a numeric type is a single comparison. */ -#define SQLITE_AFF_INTEGER 'i' -#define SQLITE_AFF_NUMERIC 'n' -#define SQLITE_AFF_TEXT 't' -#define SQLITE_AFF_NONE 'o' +#define SQLITE_AFF_TEXT 'a' +#define SQLITE_AFF_NONE 'b' +#define SQLITE_AFF_NUMERIC 'c' +#define SQLITE_AFF_INTEGER 'd' +#define SQLITE_AFF_REAL 'e' +#define sqlite3IsNumericAffinity(X) ((X)>=SQLITE_AFF_NUMERIC) /* ** Each SQL table is represented in memory by an instance of the ** following structure. ** @@ -609,10 +671,12 @@ ** that the datatype of the PRIMARY KEY must be INTEGER for this field to ** be set. An INTEGER PRIMARY KEY is used as the rowid for each row of ** the table. If a table has no INTEGER PRIMARY KEY, then a random rowid ** is generated for each row of the table. Table.hasPrimKey is true if ** the table has any PRIMARY KEY, INTEGER or otherwise. +** +** TODO: This comment is out of date. Table.iDb no longer exists. ** ** Table.tnum is the page number for the root BTree page of the table in the ** database file. If Table.iDb is the index of the database table backend ** in sqlite.aDb[]. 0 is for the main database and 1 is for the file that ** holds temporary tables and indices. If Table.isTransient @@ -630,22 +694,25 @@ int iPKey; /* If not less then 0, use aCol[iPKey] as the primary key */ Index *pIndex; /* List of SQL indexes on this table. */ int tnum; /* Root BTree node for this table (see note above) */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ u8 readOnly; /* True if this table should not be written by the user */ - u8 iDb; /* Index into sqlite.aDb[] of the backend for this table */ u8 isTransient; /* True if automatically deleted when VDBE finishes */ u8 hasPrimKey; /* True if there exists a primary key */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ u8 autoInc; /* True if the integer primary key is autoincrement */ int nRef; /* Number of pointers to this Table */ Trigger *pTrigger; /* List of SQL triggers on this table */ FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ +#ifndef SQLITE_OMIT_CHECK + Expr *pCheck; /* The AND of all CHECK constraints */ +#endif #ifndef SQLITE_OMIT_ALTERTABLE int addColOffset; /* Offset in CREATE TABLE statement to add a new column */ #endif + Schema *pSchema; }; /* ** Each foreign key constraint is an instance of the following structure. ** @@ -738,11 +805,11 @@ */ struct KeyInfo { u8 enc; /* Text encoding - one of the TEXT_Utf* values */ u8 incrKey; /* Increase 2nd key by epsilon before comparison */ int nField; /* Number of entries in aColl[] */ - u8 *aSortOrder; /* If defined an aSortOrder[i] is true, sort DESC */ + u8 *aSortOrder; /* If defined and aSortOrder[i] is true, sort DESC */ CollSeq *aColl[1]; /* Collating sequence for each term of the key */ }; /* ** Each SQL index is represented in memory by an @@ -777,13 +844,13 @@ unsigned *aiRowEst; /* Result of ANALYZE: Est. rows selected by each column */ Table *pTable; /* The SQL table being indexed */ int tnum; /* Page containing root of this index in database file */ u8 onError; /* OE_Abort, OE_Ignore, OE_Replace, or OE_None */ u8 autoIndex; /* True if is automatically created (ex: by UNIQUE) */ - u8 iDb; /* Index in sqlite.aDb[] of where this index is stored */ char *zColAff; /* String defining the affinity of each column */ Index *pNext; /* The next index associated with the same table */ + Schema *pSchema; /* Schema containing this index */ KeyInfo keyInfo; /* Info on how to order keys. MUST BE LAST */ }; /* ** Each token coming out of the lexer is an instance of @@ -889,11 +956,10 @@ ** corresponding table definition. */ struct Expr { u8 op; /* Operation performed by this node */ char affinity; /* The affinity of the column or 0 if not a column */ - u8 iDb; /* Database referenced by this expression */ u8 flags; /* Various flags. See below */ CollSeq *pColl; /* The collation type of the column or 0 */ Expr *pLeft, *pRight; /* Left and right subnodes */ ExprList *pList; /* A list of expressions used as function arguments ** or in " IN (aCol[] or ->aFunc[] */ int iRightJoinTable; /* If EP_FromJoin, the right table of the join */ Select *pSelect; /* When the expression is a sub-select. Also the ** right side of " IN (