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 (