summaryrefslogtreecommitdiff
path: root/ext/pdo_sqlite/sqlite/src
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pdo_sqlite/sqlite/src')
-rw-r--r--ext/pdo_sqlite/sqlite/src/alter.c8
-rw-r--r--ext/pdo_sqlite/sqlite/src/analyze.c4
-rw-r--r--ext/pdo_sqlite/sqlite/src/attach.c9
-rw-r--r--ext/pdo_sqlite/sqlite/src/btree.c1124
-rw-r--r--ext/pdo_sqlite/sqlite/src/btree.h9
-rw-r--r--ext/pdo_sqlite/sqlite/src/build.c219
-rw-r--r--ext/pdo_sqlite/sqlite/src/callback.c9
-rw-r--r--ext/pdo_sqlite/sqlite/src/date.c42
-rw-r--r--ext/pdo_sqlite/sqlite/src/delete.c13
-rw-r--r--ext/pdo_sqlite/sqlite/src/expr.c204
-rw-r--r--ext/pdo_sqlite/sqlite/src/func.c251
-rw-r--r--ext/pdo_sqlite/sqlite/src/hash.c5
-rw-r--r--ext/pdo_sqlite/sqlite/src/insert.c570
-rw-r--r--ext/pdo_sqlite/sqlite/src/keywordhash.h137
-rw-r--r--ext/pdo_sqlite/sqlite/src/legacy.c1
-rw-r--r--ext/pdo_sqlite/sqlite/src/loadext.c158
-rw-r--r--ext/pdo_sqlite/sqlite/src/main.c122
-rw-r--r--ext/pdo_sqlite/sqlite/src/opcodes.c273
-rw-r--r--ext/pdo_sqlite/sqlite/src/opcodes.h291
-rw-r--r--ext/pdo_sqlite/sqlite/src/os.c5
-rw-r--r--ext/pdo_sqlite/sqlite/src/os.h69
-rw-r--r--ext/pdo_sqlite/sqlite/src/os_common.h58
-rw-r--r--ext/pdo_sqlite/sqlite/src/os_unix.c1219
-rw-r--r--ext/pdo_sqlite/sqlite/src/os_win.c408
-rw-r--r--ext/pdo_sqlite/sqlite/src/pager.c1788
-rw-r--r--ext/pdo_sqlite/sqlite/src/pager.h110
-rw-r--r--ext/pdo_sqlite/sqlite/src/parse.c2671
-rw-r--r--ext/pdo_sqlite/sqlite/src/parse.h179
-rw-r--r--ext/pdo_sqlite/sqlite/src/parse.y160
-rw-r--r--ext/pdo_sqlite/sqlite/src/pragma.c134
-rw-r--r--ext/pdo_sqlite/sqlite/src/prepare.c146
-rw-r--r--ext/pdo_sqlite/sqlite/src/printf.c5
-rw-r--r--ext/pdo_sqlite/sqlite/src/random.c2
-rw-r--r--ext/pdo_sqlite/sqlite/src/select.c238
-rw-r--r--ext/pdo_sqlite/sqlite/src/shell.c346
-rw-r--r--ext/pdo_sqlite/sqlite/src/sqlite.h.in243
-rw-r--r--ext/pdo_sqlite/sqlite/src/sqlite3ext.h20
-rw-r--r--ext/pdo_sqlite/sqlite/src/sqliteInt.h104
-rw-r--r--ext/pdo_sqlite/sqlite/src/table.c8
-rw-r--r--ext/pdo_sqlite/sqlite/src/tclsqlite.c57
-rw-r--r--ext/pdo_sqlite/sqlite/src/test1.c627
-rw-r--r--ext/pdo_sqlite/sqlite/src/test2.c71
-rw-r--r--ext/pdo_sqlite/sqlite/src/test3.c102
-rw-r--r--ext/pdo_sqlite/sqlite/src/tokenize.c8
-rw-r--r--ext/pdo_sqlite/sqlite/src/trigger.c38
-rw-r--r--ext/pdo_sqlite/sqlite/src/update.c10
-rw-r--r--ext/pdo_sqlite/sqlite/src/utf.c61
-rw-r--r--ext/pdo_sqlite/sqlite/src/util.c40
-rw-r--r--ext/pdo_sqlite/sqlite/src/vacuum.c123
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbe.c324
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbe.h4
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbeInt.h13
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbeapi.c71
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbeaux.c252
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbefifo.c6
-rw-r--r--ext/pdo_sqlite/sqlite/src/vdbemem.c67
-rw-r--r--ext/pdo_sqlite/sqlite/src/vtab.c112
-rw-r--r--ext/pdo_sqlite/sqlite/src/where.c524
58 files changed, 9172 insertions, 4700 deletions
diff --git a/ext/pdo_sqlite/sqlite/src/alter.c b/ext/pdo_sqlite/sqlite/src/alter.c
index 0c00c2c49..7aebf2076 100644
--- a/ext/pdo_sqlite/sqlite/src/alter.c
+++ b/ext/pdo_sqlite/sqlite/src/alter.c
@@ -12,7 +12,7 @@
** This file contains C code routines that used to generate VDBE code
** that implements the ALTER TABLE command.
**
-** $Id: alter.c,v 1.2.2.2.2.1 2006/08/14 16:15:28 iliaa Exp $
+** $Id: alter.c,v 1.2.2.2.2.2 2007/02/09 03:17:46 iliaa Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -28,7 +28,7 @@
** This function is used by SQL generated to implement the
** ALTER TABLE command. The first argument is the text of a CREATE TABLE or
** CREATE INDEX command. The second is a table name. The table name in
-** the CREATE TABLE or CREATE INDEX statement is replaced with the second
+** the CREATE TABLE or CREATE INDEX statement is replaced with the third
** argument and the result returned. Examples:
**
** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def')
@@ -78,10 +78,10 @@ static void renameTableFunc(
}
#ifndef SQLITE_OMIT_TRIGGER
-/* This function is used by SQL generated to implement the ALTER TABLE
+/* This function is used by SQL generated to implement the
** ALTER TABLE command. The first argument is the text of a CREATE TRIGGER
** statement. The second is a table name. The table name in the CREATE
-** TRIGGER statement is replaced with the second argument and the result
+** TRIGGER statement is replaced with the third argument and the result
** returned. This is analagous to renameTableFunc() above, except for CREATE
** TRIGGER, not CREATE INDEX and CREATE TABLE.
*/
diff --git a/ext/pdo_sqlite/sqlite/src/analyze.c b/ext/pdo_sqlite/sqlite/src/analyze.c
index 458d66435..91e8dda25 100644
--- a/ext/pdo_sqlite/sqlite/src/analyze.c
+++ b/ext/pdo_sqlite/sqlite/src/analyze.c
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code associated with the ANALYZE command.
**
-** @(#) $Id: analyze.c,v 1.1.2.2.2.1 2006/08/14 16:15:28 iliaa Exp $
+** @(#) $Id: analyze.c,v 1.1.2.2.2.2 2007/04/09 16:35:11 iliaa Exp $
*/
#ifndef SQLITE_OMIT_ANALYZE
#include "sqliteInt.h"
@@ -211,7 +211,7 @@ static void analyzeOneTable(
}
}
sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "aaa", 0);
- sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0);
+ sqlite3VdbeAddOp(v, OP_Insert, iStatCur, OPFLAG_APPEND);
sqlite3VdbeJumpHere(v, addr);
}
}
diff --git a/ext/pdo_sqlite/sqlite/src/attach.c b/ext/pdo_sqlite/sqlite/src/attach.c
index 10abc4901..41eb949d5 100644
--- a/ext/pdo_sqlite/sqlite/src/attach.c
+++ b/ext/pdo_sqlite/sqlite/src/attach.c
@@ -15,6 +15,7 @@
*/
#include "sqliteInt.h"
+#ifndef SQLITE_OMIT_ATTACH
/*
** Resolve an expression that was part of an ATTACH or DETACH statement. This
** is slightly different from resolving a normal SQL expression, because simple
@@ -133,13 +134,14 @@ static void attachFunc(
"attached databases must use the same text encoding as main database");
goto attach_error;
}
+ sqlite3PagerLockingMode(sqlite3BtreePager(aNew->pBt), db->dfltLockMode);
}
aNew->zName = sqliteStrDup(zName);
aNew->safety_level = 3;
#if SQLITE_HAS_CODEC
{
- extern int sqlite3CodecAttach(sqlite3*, int, void*, int);
+ extern int sqlite3CodecAttach(sqlite3*, int, const void*, int);
extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*);
int nKey;
char *zKey;
@@ -188,7 +190,7 @@ static void attachFunc(
sqlite3ResetInternalSchema(db, 0);
db->nDb = iDb;
if( rc==SQLITE_NOMEM ){
- if( !sqlite3MallocFailed() ) sqlite3FailedMalloc();
+ sqlite3FailedMalloc();
sqlite3_snprintf(sizeof(zErr),zErr, "out of memory");
}else{
sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile);
@@ -350,14 +352,17 @@ void sqlite3Detach(Parse *pParse, Expr *pDbname){
void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){
codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey);
}
+#endif /* SQLITE_OMIT_ATTACH */
/*
** Register the functions sqlite_attach and sqlite_detach.
*/
void sqlite3AttachFunctions(sqlite3 *db){
+#ifndef SQLITE_OMIT_ATTACH
static const int enc = SQLITE_UTF8;
sqlite3CreateFunc(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0);
sqlite3CreateFunc(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0);
+#endif
}
/*
diff --git a/ext/pdo_sqlite/sqlite/src/btree.c b/ext/pdo_sqlite/sqlite/src/btree.c
index 52bc749a3..3df2a3b01 100644
--- a/ext/pdo_sqlite/sqlite/src/btree.c
+++ b/ext/pdo_sqlite/sqlite/src/btree.c
@@ -22,13 +22,13 @@
** entries and N+1 pointers to subpages.
**
** ----------------------------------------------------------------
-** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N) | Ptr(N+1) |
+** | Ptr(0) | Key(0) | Ptr(1) | Key(1) | ... | Key(N-1) | Ptr(N) |
** ----------------------------------------------------------------
**
** All of the keys on the page that Ptr(0) points to have values less
** than Key(0). All of the keys on page Ptr(1) and its subpages have
** values greater than Key(0) and less than Key(1). All of the keys
-** on Ptr(N+1) and its subpages have values greater than Key(N). And
+** on Ptr(N) and its subpages have values greater than Key(N-1). And
** so forth.
**
** Finding a particular key requires reading O(log(M)) pages from the
@@ -41,7 +41,7 @@
** page. If the payload is larger than the preset amount then surplus
** bytes are stored on overflow pages. The payload for an entry
** and the preceding pointer are combined to form a "Cell". Each
-** page has a small header which contains the Ptr(N+1) pointer and other
+** page has a small header which contains the Ptr(N) pointer and other
** information such as the size of key and data.
**
** FORMAT DETAILS
@@ -123,7 +123,7 @@
** 3 2 number of cells on this page
** 5 2 first byte of the cell content area
** 7 1 number of fragmented free bytes
-** 8 4 Right child (the Ptr(N+1) value). Omitted on leaves.
+** 8 4 Right child (the Ptr(N) value). Omitted on leaves.
**
** The flags define the format of this btree page. The leaf flag means that
** this page has no children. The zerodata flag means that this page carries
@@ -291,6 +291,7 @@ struct MemPage {
} aOvfl[5];
BtShared *pBt; /* Pointer back to BTree structure */
u8 *aData; /* Pointer back to the start of the page */
+ DbPage *pDbPage; /* Pager page handle */
Pgno pgno; /* Page number for this page */
MemPage *pParent; /* The parent of this page. NULL for root */
};
@@ -365,6 +366,7 @@ struct CellInfo {
u8 *pCell; /* Pointer to the start of cell content */
i64 nKey; /* The key for INTKEY tables, or number of bytes in key */
u32 nData; /* Number of bytes of data */
+ u32 nPayload; /* Total amount of payload */
u16 nHeader; /* Size of the cell content header in bytes */
u16 nLocal; /* Amount of payload held locally */
u16 iOverflow; /* Offset to overflow page number. Zero if no overflow */
@@ -387,17 +389,13 @@ struct BtCursor {
CellInfo info; /* A parse of the cell we are pointing at */
u8 wrFlag; /* True if writable */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
-#ifndef SQLITE_OMIT_SHARED_CACHE
void *pKey; /* Saved key that was cursor's last known position */
i64 nKey; /* Size of pKey, or last integer key */
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.
+** Potential values for BtCursor.eState.
**
** CURSOR_VALID:
** Cursor points to a valid entry. getPayload() etc. may be called.
@@ -425,7 +423,8 @@ struct BtCursor {
*/
#if SQLITE_TEST
# define TRACE(X) if( sqlite3_btree_trace )\
- { sqlite3DebugPrintf X; fflush(stdout); }
+/* { sqlite3DebugPrintf X; fflush(stdout); } */ \
+{ printf X; fflush(stdout); }
int sqlite3_btree_trace=0; /* True to enable tracing */
#else
# define TRACE(X)
@@ -434,7 +433,7 @@ int sqlite3_btree_trace=0; /* True to enable tracing */
/*
** Forward declaration
*/
-static int checkReadLocks(BtShared*,Pgno,BtCursor*);
+static int checkReadLocks(Btree*,Pgno,BtCursor*);
/*
** Read or write a two- and four-byte big-endian integer values.
@@ -509,105 +508,8 @@ struct BtLock {
#define queryTableLock(a,b,c) SQLITE_OK
#define lockTable(a,b,c) SQLITE_OK
#define unlockAllTables(a)
- #define restoreOrClearCursorPosition(a,b) SQLITE_OK
- #define saveAllCursors(a,b,c) SQLITE_OK
-
#else
-static void releasePage(MemPage *pPage);
-
-/*
-** 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;
-
- assert( CURSOR_VALID==pCur->eState );
- assert( 0==pCur->pKey );
-
- 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 );
-
- if( rc==SQLITE_OK ){
- releasePage(pCur->pPage);
- pCur->pPage = 0;
- 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( sqlite3ThreadDataReadOnly()->useSharedData ){
- for(p=pBt->pCursor; p; p=p->pNext){
- if( p!=pExcept && (0==iRoot || 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 restoreOrClearCursorPosition() 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 restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){
- int rc = SQLITE_OK;
- assert( sqlite3ThreadDataReadOnly()->useSharedData );
- assert( pCur->eState==CURSOR_REQUIRESEEK );
- pCur->eState = CURSOR_INVALID;
- if( doSeek ){
- rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip);
- }
- if( rc==SQLITE_OK ){
- sqliteFree(pCur->pKey);
- pCur->pKey = 0;
- assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState );
- }
- return rc;
-}
-
-#define restoreOrClearCursorPosition(p,x) \
- (p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK)
/*
** Query to see if btree handle p may obtain a lock of type eLock
@@ -747,6 +649,105 @@ static void unlockAllTables(Btree *p){
}
#endif /* SQLITE_OMIT_SHARED_CACHE */
+static void releasePage(MemPage *pPage); /* Forward reference */
+
+/*
+** 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;
+
+ assert( CURSOR_VALID==pCur->eState );
+ assert( 0==pCur->pKey );
+
+ 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 );
+
+ if( rc==SQLITE_OK ){
+ releasePage(pCur->pPage);
+ pCur->pPage = 0;
+ 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;
+ for(p=pBt->pCursor; p; p=p->pNext){
+ if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&
+ p->eState==CURSOR_VALID ){
+ int rc = saveCursorPosition(p);
+ if( SQLITE_OK!=rc ){
+ return rc;
+ }
+ }
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Clear the current cursor position.
+*/
+static void clearCursorPosition(BtCursor *pCur){
+ sqliteFree(pCur->pKey);
+ pCur->pKey = 0;
+ pCur->eState = CURSOR_INVALID;
+}
+
+/*
+** 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 restoreOrClearCursorPosition() 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 restoreOrClearCursorPositionX(BtCursor *pCur){
+ int rc;
+ assert( pCur->eState==CURSOR_REQUIRESEEK );
+ pCur->eState = CURSOR_INVALID;
+ rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skip);
+ if( rc==SQLITE_OK ){
+ sqliteFree(pCur->pKey);
+ pCur->pKey = 0;
+ assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );
+ }
+ return rc;
+}
+
+#define restoreOrClearCursorPosition(p) \
+ (p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p):SQLITE_OK)
+
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** These macros define the location of the pointer-map entry for a
@@ -822,9 +823,10 @@ static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){
** An error code is returned if something goes wrong, otherwise SQLITE_OK.
*/
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 */
+ DbPage *pDbPage; /* The pointer map page */
+ u8 *pPtrmap; /* The pointer map data */
+ Pgno iPtrmap; /* The pointer map page number */
+ int offset; /* Offset in pointer map page */
int rc;
/* The master-journal page number must never be used as a pointer map page */
@@ -835,22 +837,23 @@ static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){
return SQLITE_CORRUPT_BKPT;
}
iPtrmap = PTRMAP_PAGENO(pBt, key);
- rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
+ rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);
if( rc!=SQLITE_OK ){
return rc;
}
offset = PTRMAP_PTROFFSET(pBt, key);
+ pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
- rc = sqlite3pager_write(pPtrmap);
+ rc = sqlite3PagerWrite(pDbPage);
if( rc==SQLITE_OK ){
pPtrmap[offset] = eType;
put4byte(&pPtrmap[offset+1], parent);
}
}
- sqlite3pager_unref(pPtrmap);
+ sqlite3PagerUnref(pDbPage);
return rc;
}
@@ -862,23 +865,25 @@ static int ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent){
** An error code is returned if something goes wrong, otherwise SQLITE_OK.
*/
static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
+ DbPage *pDbPage; /* The pointer map page */
int iPtrmap; /* Pointer map page index */
u8 *pPtrmap; /* Pointer map page data */
int offset; /* Offset of entry in pointer map */
int rc;
iPtrmap = PTRMAP_PAGENO(pBt, key);
- rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
+ rc = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);
if( rc!=0 ){
return rc;
}
+ pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
offset = PTRMAP_PTROFFSET(pBt, key);
assert( pEType!=0 );
*pEType = pPtrmap[offset];
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
- sqlite3pager_unref(pPtrmap);
+ sqlite3PagerUnref(pDbPage);
if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;
return SQLITE_OK;
}
@@ -952,6 +957,7 @@ static void parseCellPtr(
pInfo->nKey = x;
nPayload += x;
}
+ pInfo->nPayload = nPayload;
pInfo->nHeader = n;
if( nPayload<=pPage->maxLocal ){
/* This is the (easy) common case where the entire payload fits
@@ -1028,6 +1034,7 @@ static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){
if( pCell ){
CellInfo info;
parseCellPtr(pPage, pCell, &info);
+ assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload );
if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){
Pgno ovfl = get4byte(&pCell[info.iOverflow]);
return ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno);
@@ -1048,91 +1055,6 @@ static int ptrmapPutOvfl(MemPage *pPage, int iCell){
#endif
-/*
-** Do sanity checking on a page. Throw an exception if anything is
-** not right.
-**
-** This routine is used for internal error checking only. It is omitted
-** from most builds.
-*/
-#if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0
-static void _pageIntegrity(MemPage *pPage){
- int usableSize;
- u8 *data;
- int i, j, idx, c, pc, hdr, nFree;
- int cellOffset;
- int nCell, cellLimit;
- u8 *used;
-
- used = sqliteMallocRaw( pPage->pBt->pageSize );
- if( used==0 ) return;
- usableSize = pPage->pBt->usableSize;
- assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] );
- hdr = pPage->hdrOffset;
- assert( hdr==(pPage->pgno==1 ? 100 : 0) );
- assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
- c = pPage->aData[hdr];
- if( pPage->isInit ){
- assert( pPage->leaf == ((c & PTF_LEAF)!=0) );
- assert( pPage->zeroData == ((c & PTF_ZERODATA)!=0) );
- assert( pPage->leafData == ((c & PTF_LEAFDATA)!=0) );
- assert( pPage->intKey == ((c & (PTF_INTKEY|PTF_LEAFDATA))!=0) );
- assert( pPage->hasData ==
- !(pPage->zeroData || (!pPage->leaf && pPage->leafData)) );
- assert( pPage->cellOffset==pPage->hdrOffset+12-4*pPage->leaf );
- assert( pPage->nCell = get2byte(&pPage->aData[hdr+3]) );
- }
- data = pPage->aData;
- memset(used, 0, usableSize);
- for(i=0; i<hdr+10-pPage->leaf*4; i++) used[i] = 1;
- nFree = 0;
- pc = get2byte(&data[hdr+1]);
- while( pc ){
- int size;
- assert( pc>0 && pc<usableSize-4 );
- size = get2byte(&data[pc+2]);
- assert( pc+size<=usableSize );
- nFree += size;
- for(i=pc; i<pc+size; i++){
- assert( used[i]==0 );
- used[i] = 1;
- }
- pc = get2byte(&data[pc]);
- }
- idx = 0;
- nCell = get2byte(&data[hdr+3]);
- cellLimit = get2byte(&data[hdr+5]);
- assert( pPage->isInit==0
- || pPage->nFree==nFree+data[hdr+7]+cellLimit-(cellOffset+2*nCell) );
- cellOffset = pPage->cellOffset;
- for(i=0; i<nCell; i++){
- int size;
- pc = get2byte(&data[cellOffset+2*i]);
- assert( pc>0 && pc<usableSize-4 );
- size = cellSize(pPage, &data[pc]);
- assert( pc+size<=usableSize );
- for(j=pc; j<pc+size; j++){
- assert( used[j]==0 );
- used[j] = 1;
- }
- }
- for(i=cellOffset+2*nCell; i<cellimit; i++){
- assert( used[i]==0 );
- used[i] = 1;
- }
- nFree = 0;
- for(i=0; i<usableSize; i++){
- assert( used[i]<=1 );
- if( used[i]==0 ) nFree++;
- }
- assert( nFree==data[hdr+7] );
- sqliteFree(used);
-}
-#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.
*/
@@ -1161,7 +1083,7 @@ static int defragmentPage(MemPage *pPage){
unsigned char *data; /* The page data */
unsigned char *temp; /* Temp area for cell content */
- assert( sqlite3pager_iswriteable(pPage->aData) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( pPage->pBt!=0 );
assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );
assert( pPage->nOverflow==0 );
@@ -1219,7 +1141,7 @@ static int allocateSpace(MemPage *pPage, int nByte){
unsigned char *data;
data = pPage->aData;
- assert( sqlite3pager_iswriteable(data) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( pPage->pBt );
if( nByte<4 ) nByte = 4;
if( pPage->nFree<nByte || pPage->nOverflow>0 ) return 0;
@@ -1276,7 +1198,7 @@ static void freeSpace(MemPage *pPage, int start, int size){
unsigned char *data = pPage->aData;
assert( pPage->pBt!=0 );
- assert( sqlite3pager_iswriteable(data) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
assert( start>=pPage->hdrOffset+6+(pPage->leaf?0:4) );
assert( (start + size)<=pPage->pBt->usableSize );
if( size<4 ) size = 4;
@@ -1385,7 +1307,7 @@ static int initPage(
pBt = pPage->pBt;
assert( pBt!=0 );
assert( pParent==0 || pParent->pBt==pBt );
- assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );
+ assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );
if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
/* The parent page should never change unless the file is corrupt */
@@ -1394,7 +1316,7 @@ static int initPage(
if( pPage->isInit ) return SQLITE_OK;
if( pPage->pParent==0 && pParent!=0 ){
pPage->pParent = pParent;
- sqlite3pager_ref(pParent->aData);
+ sqlite3PagerRef(pParent->pDbPage);
}
hdr = pPage->hdrOffset;
data = pPage->aData;
@@ -1439,7 +1361,6 @@ static int initPage(
}
pPage->isInit = 1;
- pageIntegrity(pPage);
return SQLITE_OK;
}
@@ -1453,9 +1374,9 @@ static void zeroPage(MemPage *pPage, int flags){
int hdr = pPage->hdrOffset;
int first;
- assert( sqlite3pager_pagenumber(data)==pPage->pgno );
+ assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno );
assert( &data[pBt->pageSize] == (unsigned char*)pPage );
- assert( sqlite3pager_iswriteable(data) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
memset(&data[hdr], 0, pBt->usableSize - hdr);
data[hdr] = flags;
first = hdr + 8 + 4*((flags&PTF_LEAF)==0);
@@ -1470,21 +1391,29 @@ static void zeroPage(MemPage *pPage, int flags){
pPage->idxShift = 0;
pPage->nCell = 0;
pPage->isInit = 1;
- pageIntegrity(pPage);
}
/*
** Get a page from the pager. Initialize the MemPage.pBt and
** MemPage.aData elements if needed.
+**
+** If the noContent flag is set, it means that we do not care about
+** the content of the page at this time. So do not go to the disk
+** to fetch the content. Just fill in the content with zeros for now.
+** If in the future we call sqlite3PagerWrite() on this page, that
+** means we have started to be concerned about content and the disk
+** read should occur at that point.
*/
-static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage){
+static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage, int noContent){
int rc;
- unsigned char *aData;
MemPage *pPage;
- rc = sqlite3pager_get(pBt->pPager, pgno, (void**)&aData);
+ DbPage *pDbPage;
+
+ rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent);
if( rc ) return rc;
- pPage = (MemPage*)&aData[pBt->pageSize];
- pPage->aData = aData;
+ pPage = (MemPage *)sqlite3PagerGetExtra(pDbPage);
+ pPage->aData = sqlite3PagerGetData(pDbPage);
+ pPage->pDbPage = pDbPage;
pPage->pBt = pBt;
pPage->pgno = pgno;
pPage->hdrOffset = pPage->pgno==1 ? 100 : 0;
@@ -1507,7 +1436,7 @@ static int getAndInitPage(
if( pgno==0 ){
return SQLITE_CORRUPT_BKPT;
}
- rc = getPage(pBt, pgno, ppPage);
+ rc = getPage(pBt, pgno, ppPage, 0);
if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
rc = initPage(*ppPage, pParent);
}
@@ -1523,7 +1452,7 @@ static void releasePage(MemPage *pPage){
assert( pPage->aData );
assert( pPage->pBt );
assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage );
- sqlite3pager_unref(pPage->aData);
+ sqlite3PagerUnref(pPage->pDbPage);
}
}
@@ -1532,10 +1461,10 @@ static void releasePage(MemPage *pPage){
** reaches zero. We need to unref the pParent pointer when that
** happens.
*/
-static void pageDestructor(void *pData, int pageSize){
+static void pageDestructor(DbPage *pData, int pageSize){
MemPage *pPage;
assert( (pageSize & 7)==0 );
- pPage = (MemPage*)&((char*)pData)[pageSize];
+ pPage = (MemPage *)sqlite3PagerGetExtra(pData);
if( pPage->pParent ){
MemPage *pParent = pPage->pParent;
pPage->pParent = 0;
@@ -1552,10 +1481,10 @@ static void pageDestructor(void *pData, int pageSize){
** This routine needs to reset the extra data section at the end of the
** page to agree with the restored data.
*/
-static void pageReinit(void *pData, int pageSize){
+static void pageReinit(DbPage *pData, int pageSize){
MemPage *pPage;
assert( (pageSize & 7)==0 );
- pPage = (MemPage*)&((char*)pData)[pageSize];
+ pPage = (MemPage *)sqlite3PagerGetExtra(pData);
if( pPage->isInit ){
pPage->isInit = 0;
initPage(pPage, pPage->pParent);
@@ -1591,9 +1520,9 @@ int sqlite3BtreeOpen(
*/
#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)
#ifdef SQLITE_OMIT_MEMORYDB
- const int isMemdb = !zFilename;
+ const int isMemdb = 0;
#else
- const int isMemdb = !zFilename || (strcmp(zFilename, ":memory:")?0:1);
+ const int isMemdb = zFilename && !strcmp(zFilename, ":memory:");
#endif
#endif
@@ -1615,7 +1544,7 @@ int sqlite3BtreeOpen(
}
for(pBt=pTsdro->pBtree; pBt; pBt=pBt->pNext){
assert( pBt->nRef>0 );
- if( 0==strcmp(zFullPathname, sqlite3pager_filename(pBt->pPager)) ){
+ if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager)) ){
p->pBt = pBt;
*ppBtree = p;
pBt->nRef++;
@@ -1644,9 +1573,14 @@ int sqlite3BtreeOpen(
sqliteFree(p);
return SQLITE_NOMEM;
}
- rc = sqlite3pager_open(&pBt->pPager, zFilename, EXTRA_SIZE, flags);
+ rc = sqlite3PagerOpen(&pBt->pPager, zFilename, EXTRA_SIZE, flags);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
+ }
if( rc!=SQLITE_OK ){
- if( pBt->pPager ) sqlite3pager_close(pBt->pPager);
+ if( pBt->pPager ){
+ sqlite3PagerClose(pBt->pPager);
+ }
sqliteFree(pBt);
sqliteFree(p);
*ppBtree = 0;
@@ -1654,12 +1588,11 @@ int sqlite3BtreeOpen(
}
p->pBt = pBt;
- sqlite3pager_set_destructor(pBt->pPager, pageDestructor);
- sqlite3pager_set_reiniter(pBt->pPager, pageReinit);
+ sqlite3PagerSetDestructor(pBt->pPager, pageDestructor);
+ sqlite3PagerSetReiniter(pBt->pPager, pageReinit);
pBt->pCursor = 0;
pBt->pPage1 = 0;
- pBt->readOnly = sqlite3pager_isreadonly(pBt->pPager);
- sqlite3pager_read_fileheader(pBt->pPager, sizeof(zDbHeader), zDbHeader);
+ pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);
pBt->pageSize = get2byte(&zDbHeader[16]);
if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE
|| ((pBt->pageSize-1)&pBt->pageSize)!=0 ){
@@ -1691,7 +1624,7 @@ int sqlite3BtreeOpen(
}
pBt->usableSize = pBt->pageSize - nReserve;
assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */
- sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize);
+ sqlite3PagerSetPagesize(pBt->pPager, pBt->pageSize);
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
/* Add the new btree to the linked list starting at ThreadData.pBtree.
@@ -1768,7 +1701,7 @@ int sqlite3BtreeClose(Btree *p){
/* Close the pager and free the shared-btree structure */
assert( !pBt->pCursor );
- sqlite3pager_close(pBt->pPager);
+ sqlite3PagerClose(pBt->pPager);
if( pBt->xFreeSchema && pBt->pSchema ){
pBt->xFreeSchema(pBt->pSchema);
}
@@ -1783,7 +1716,7 @@ int sqlite3BtreeClose(Btree *p){
int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){
BtShared *pBt = p->pBt;
pBt->pBusyHandler = pHandler;
- sqlite3pager_set_busyhandler(pBt->pPager, pHandler);
+ sqlite3PagerSetBusyhandler(pBt->pPager, pHandler);
return SQLITE_OK;
}
@@ -1804,7 +1737,7 @@ int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){
*/
int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
BtShared *pBt = p->pBt;
- sqlite3pager_set_cachesize(pBt->pPager, mxPage);
+ sqlite3PagerSetCachesize(pBt->pPager, mxPage);
return SQLITE_OK;
}
@@ -1819,7 +1752,7 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
BtShared *pBt = p->pBt;
- sqlite3pager_set_safety_level(pBt->pPager, level, fullSync);
+ sqlite3PagerSetSafetyLevel(pBt->pPager, level, fullSync);
return SQLITE_OK;
}
#endif
@@ -1831,7 +1764,7 @@ int sqlite3BtreeSetSafetyLevel(Btree *p, int level, int fullSync){
int sqlite3BtreeSyncDisabled(Btree *p){
BtShared *pBt = p->pBt;
assert( pBt && pBt->pPager );
- return sqlite3pager_nosync(pBt->pPager);
+ return sqlite3PagerNosync(pBt->pPager);
}
#if !defined(SQLITE_OMIT_PAGER_PRAGMAS) || !defined(SQLITE_OMIT_VACUUM)
@@ -1862,7 +1795,7 @@ int sqlite3BtreeSetPageSize(Btree *p, int pageSize, int nReserve){
((pageSize-1)&pageSize)==0 ){
assert( (pageSize & 7)==0 );
assert( !pBt->pPage1 && !pBt->pCursor );
- pBt->pageSize = sqlite3pager_set_pagesize(pBt->pPager, pageSize);
+ pBt->pageSize = sqlite3PagerSetPagesize(pBt->pPager, pageSize);
}
pBt->usableSize = pBt->pageSize - nReserve;
return SQLITE_OK;
@@ -1918,14 +1851,13 @@ int sqlite3BtreeGetAutoVacuum(Btree *p){
** SQLITE_OK is returned on success. If the file is not a
** 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.
+** is returned if we run out of memory.
*/
static int lockBtree(BtShared *pBt){
int rc, pageSize;
MemPage *pPage1;
if( pBt->pPage1 ) return SQLITE_OK;
- rc = getPage(pBt, 1, &pPage1);
+ rc = getPage(pBt, 1, &pPage1, 0);
if( rc!=SQLITE_OK ) return rc;
@@ -1933,7 +1865,7 @@ static int lockBtree(BtShared *pBt){
** a valid database file.
*/
rc = SQLITE_NOTADB;
- if( sqlite3pager_pagecount(pBt->pPager)>0 ){
+ if( sqlite3PagerPagecount(pBt->pPager)>0 ){
u8 *page1 = pPage1->aData;
if( memcmp(page1, zMagicHeader, 16)!=0 ){
goto page1_init_failed;
@@ -1942,7 +1874,7 @@ static int lockBtree(BtShared *pBt){
goto page1_init_failed;
}
pageSize = get2byte(&page1[16]);
- if( ((pageSize-1)&pageSize)!=0 ){
+ if( ((pageSize-1)&pageSize)!=0 || pageSize<512 ){
goto page1_init_failed;
}
assert( (pageSize & 7)==0 );
@@ -2022,13 +1954,15 @@ static int lockBtreeWithRetry(Btree *pRef){
*/
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 = &((u8*)pPage)[-pBt->pageSize];
- pPage->pBt = pBt;
- pPage->pgno = 1;
+ if( sqlite3PagerRefcount(pBt->pPager)>=1 ){
+ if( pBt->pPage1->aData==0 ){
+ MemPage *pPage = pBt->pPage1;
+ pPage->aData = &((u8*)pPage)[-pBt->pageSize];
+ pPage->pBt = pBt;
+ pPage->pgno = 1;
+ }
+ releasePage(pBt->pPage1);
}
- releasePage(pBt->pPage1);
pBt->pPage1 = 0;
pBt->inStmt = 0;
}
@@ -2042,11 +1976,11 @@ static int newDatabase(BtShared *pBt){
MemPage *pP1;
unsigned char *data;
int rc;
- if( sqlite3pager_pagecount(pBt->pPager)>0 ) return SQLITE_OK;
+ if( sqlite3PagerPagecount(pBt->pPager)>0 ) return SQLITE_OK;
pP1 = pBt->pPage1;
assert( pP1!=0 );
data = pP1->aData;
- rc = sqlite3pager_write(data);
+ rc = sqlite3PagerWrite(pP1->pDbPage);
if( rc ) return rc;
memcpy(data, zMagicHeader, sizeof(zMagicHeader));
assert( sizeof(zMagicHeader)==16 );
@@ -2136,7 +2070,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
}
if( rc==SQLITE_OK && wrflag ){
- rc = sqlite3pager_begin(pBt->pPage1->aData, wrflag>1);
+ rc = sqlite3PagerBegin(pBt->pPage1->pDbPage, wrflag>1);
if( rc==SQLITE_OK ){
rc = newDatabase(pBt);
}
@@ -2292,7 +2226,7 @@ static int relocatePage(
/* Move page iDbPage from it's current location to page number iFreePage */
TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
iDbPage, iFreePage, iPtrPage, eType));
- rc = sqlite3pager_movepage(pPager, pDbPage->aData, iFreePage);
+ rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -2326,11 +2260,11 @@ static int relocatePage(
** iPtrPage.
*/
if( eType!=PTRMAP_ROOTPAGE ){
- rc = getPage(pBt, iPtrPage, &pPtrPage);
+ rc = getPage(pBt, iPtrPage, &pPtrPage, 0);
if( rc!=SQLITE_OK ){
return rc;
}
- rc = sqlite3pager_write(pPtrPage->aData);
+ rc = sqlite3PagerWrite(pPtrPage->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(pPtrPage);
return rc;
@@ -2345,13 +2279,18 @@ static int relocatePage(
}
/* Forward declaration required by autoVacuumCommit(). */
-static int allocatePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
+static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
/*
-** This routine is called prior to sqlite3pager_commit when a transaction
+** This routine is called prior to sqlite3PagerCommit when a transaction
** is commited for an auto-vacuum database.
+**
+** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages
+** the database file should be truncated to during the commit process.
+** i.e. the database has been reorganized so that only the first *pnTrunc
+** pages are in use.
*/
-static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
+static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){
Pager *pPager = pBt->pPager;
Pgno nFreeList; /* Number of pages remaining on the free-list. */
int nPtrMap; /* Number of pointer-map pages deallocated */
@@ -2367,11 +2306,11 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
MemPage *pFreeMemPage = 0; /* "" */
#ifndef NDEBUG
- int nRef = sqlite3pager_refcount(pPager);
+ int nRef = sqlite3PagerRefcount(pPager);
#endif
assert( pBt->autoVacuum );
- if( PTRMAP_ISPAGE(pBt, sqlite3pager_pagecount(pPager)) ){
+ if( PTRMAP_ISPAGE(pBt, sqlite3PagerPagecount(pPager)) ){
return SQLITE_CORRUPT_BKPT;
}
@@ -2380,7 +2319,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
*/
nFreeList = get4byte(&pBt->pPage1->aData[36]);
if( nFreeList==0 ){
- *nTrunc = 0;
+ *pnTrunc = 0;
return SQLITE_OK;
}
@@ -2393,7 +2332,7 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
** be required, less 1 if the pending-byte page was part of the database
** but is not after the truncation.
**/
- origSize = sqlite3pager_pagecount(pPager);
+ origSize = sqlite3PagerPagecount(pPager);
if( origSize==PENDING_BYTE_PAGE(pBt) ){
origSize--;
}
@@ -2430,19 +2369,19 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
if( eType==PTRMAP_FREEPAGE ){
continue;
}
- rc = getPage(pBt, iDbPage, &pDbMemPage);
+ rc = getPage(pBt, iDbPage, &pDbMemPage, 0);
if( rc!=SQLITE_OK ) goto autovacuum_out;
/* Find the next page in the free-list that is not already at the end
** of the file. A page can be pulled off the free list using the
- ** allocatePage() routine.
+ ** allocateBtreePage() routine.
*/
do{
if( pFreeMemPage ){
releasePage(pFreeMemPage);
pFreeMemPage = 0;
}
- rc = allocatePage(pBt, &pFreeMemPage, &iFreePage, 0, 0);
+ rc = allocateBtreePage(pBt, &pFreeMemPage, &iFreePage, 0, 0);
if( rc!=SQLITE_OK ){
releasePage(pDbMemPage);
goto autovacuum_out;
@@ -2467,29 +2406,81 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
** truncate the database file to finSize pages and consider the
** free-list empty.
*/
- rc = sqlite3pager_write(pBt->pPage1->aData);
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
if( rc!=SQLITE_OK ) goto autovacuum_out;
put4byte(&pBt->pPage1->aData[32], 0);
put4byte(&pBt->pPage1->aData[36], 0);
- *nTrunc = finSize;
+ *pnTrunc = finSize;
assert( finSize!=PENDING_BYTE_PAGE(pBt) );
autovacuum_out:
- assert( nRef==sqlite3pager_refcount(pPager) );
+ assert( nRef==sqlite3PagerRefcount(pPager) );
if( rc!=SQLITE_OK ){
- sqlite3pager_rollback(pPager);
+ sqlite3PagerRollback(pPager);
}
return rc;
}
#endif
/*
+** This routine does the first phase of a two-phase commit. This routine
+** causes a rollback journal to be created (if it does not already exist)
+** and populated with enough information so that if a power loss occurs
+** the database can be restored to its original state by playing back
+** the journal. Then the contents of the journal are flushed out to
+** the disk. After the journal is safely on oxide, the changes to the
+** database are written into the database file and flushed to oxide.
+** At the end of this call, the rollback journal still exists on the
+** disk and we are still holding all locks, so the transaction has not
+** committed. See sqlite3BtreeCommit() for the second phase of the
+** commit process.
+**
+** This call is a no-op if no write-transaction is currently active on pBt.
+**
+** Otherwise, sync the database file for the btree pBt. zMaster points to
+** the name of a master journal file that should be written into the
+** individual journal file, or is NULL, indicating no master journal file
+** (single database transaction).
+**
+** When this is called, the master journal should already have been
+** 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 sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){
+ int rc = SQLITE_OK;
+ if( p->inTrans==TRANS_WRITE ){
+ BtShared *pBt = p->pBt;
+ Pgno nTrunc = 0;
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pBt->autoVacuum ){
+ rc = autoVacuumCommit(pBt, &nTrunc);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ }
+#endif
+ rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zMaster, nTrunc);
+ }
+ return rc;
+}
+
+/*
** Commit the transaction currently in progress.
**
+** This routine implements the second phase of a 2-phase commit. The
+** sqlite3BtreeSync() routine does the first phase and should be invoked
+** prior to calling this routine. The sqlite3BtreeSync() routine did
+** all the work of writing information out to disk and flushing the
+** contents so that they are written onto the disk platter. All this
+** routine has to do is delete or truncate the rollback journal
+** (which causes the transaction to commit) and drop locks.
+**
** 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 *p){
+int sqlite3BtreeCommitPhaseTwo(Btree *p){
BtShared *pBt = p->pBt;
btreeIntegrity(p);
@@ -2501,7 +2492,7 @@ int sqlite3BtreeCommit(Btree *p){
int rc;
assert( pBt->inTransaction==TRANS_WRITE );
assert( pBt->nTransaction>0 );
- rc = sqlite3pager_commit(pBt->pPager);
+ rc = sqlite3PagerCommitPhaseTwo(pBt->pPager);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -2532,6 +2523,18 @@ int sqlite3BtreeCommit(Btree *p){
return SQLITE_OK;
}
+/*
+** Do both phases of a commit.
+*/
+int sqlite3BtreeCommit(Btree *p){
+ int rc;
+ rc = sqlite3BtreeCommitPhaseOne(p, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3BtreeCommitPhaseTwo(p);
+ }
+ return rc;
+}
+
#ifndef NDEBUG
/*
** Return the number of write-cursors open on this handle. This is for use
@@ -2548,7 +2551,7 @@ static int countWriteCursors(BtShared *pBt){
}
#endif
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/*
** Print debugging information about all cursors to standard output.
*/
@@ -2606,7 +2609,7 @@ int sqlite3BtreeRollback(Btree *p){
int rc2;
assert( TRANS_WRITE==pBt->inTransaction );
- rc2 = sqlite3pager_rollback(pBt->pPager);
+ rc2 = sqlite3PagerRollback(pBt->pPager);
if( rc2!=SQLITE_OK ){
rc = rc2;
}
@@ -2614,7 +2617,7 @@ int sqlite3BtreeRollback(Btree *p){
/* 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 ){
+ if( getPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){
releasePage(pPage1);
}
assert( countWriteCursors(pBt)==0 );
@@ -2659,7 +2662,7 @@ int sqlite3BtreeBeginStmt(Btree *p){
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
assert( pBt->inTransaction==TRANS_WRITE );
- rc = pBt->readOnly ? SQLITE_OK : sqlite3pager_stmt_begin(pBt->pPager);
+ rc = pBt->readOnly ? SQLITE_OK : sqlite3PagerStmtBegin(pBt->pPager);
pBt->inStmt = 1;
return rc;
}
@@ -2673,7 +2676,7 @@ int sqlite3BtreeCommitStmt(Btree *p){
int rc;
BtShared *pBt = p->pBt;
if( pBt->inStmt && !pBt->readOnly ){
- rc = sqlite3pager_stmt_commit(pBt->pPager);
+ rc = sqlite3PagerStmtCommit(pBt->pPager);
}else{
rc = SQLITE_OK;
}
@@ -2694,7 +2697,7 @@ int sqlite3BtreeRollbackStmt(Btree *p){
BtShared *pBt = p->pBt;
sqlite3MallocDisallow();
if( pBt->inStmt && !pBt->readOnly ){
- rc = sqlite3pager_stmt_rollback(pBt->pPager);
+ rc = sqlite3PagerStmtRollback(pBt->pPager);
assert( countWriteCursors(pBt)==0 );
pBt->inStmt = 0;
}
@@ -2732,25 +2735,16 @@ static int dfltCompare(
**
** 1: The cursor must have been opened with wrFlag==1
**
-** 2: No other cursors may be open with wrFlag==0 on the same table
+** 2: Other database connections that share the same pager cache
+** but which are not in the READ_UNCOMMITTED state may not have
+** cursors open with wrFlag==0 on the same table. Otherwise
+** the changes made by this write cursor would be visible to
+** the read cursors in the other database connection.
**
** 3: The database must be writable (not on read-only media)
**
** 4: There must be an active transaction.
**
-** Condition 2 warrants further discussion. If any cursor is opened
-** on a table with wrFlag==0, that prevents all other cursors from
-** writing to that table. This is a kind of "read-lock". When a cursor
-** is opened with wrFlag==0 it is guaranteed that the table will not
-** change as long as the cursor is open. This allows the cursor to
-** do a sequential scan of the table without having to worry about
-** entries being inserted or deleted during the scan. Cursors should
-** be opened with wrFlag==0 only if this read-lock property is needed.
-** That is to say, cursors should be opened with wrFlag==0 only if they
-** intend to use the sqlite3BtreeNext() system call. All other cursors
-** should be opened with wrFlag==1 even if they never really intend
-** to write.
-**
** No checking is done to make sure that page iTable really is the
** root page of a b-tree. If it is not, then the cursor acquired
** will not work correctly.
@@ -2778,7 +2772,7 @@ int sqlite3BtreeCursor(
if( pBt->readOnly ){
return SQLITE_READONLY;
}
- if( checkReadLocks(pBt, iTable, 0) ){
+ if( checkReadLocks(p, iTable, 0) ){
return SQLITE_LOCKED;
}
}
@@ -2795,7 +2789,7 @@ int sqlite3BtreeCursor(
goto create_cursor_exception;
}
pCur->pgnoRoot = (Pgno)iTable;
- if( iTable==1 && sqlite3pager_pagecount(pBt->pPager)==0 ){
+ if( iTable==1 && sqlite3PagerPagecount(pBt->pPager)==0 ){
rc = SQLITE_EMPTY;
goto create_cursor_exception;
}
@@ -2850,7 +2844,7 @@ void sqlite3BtreeSetCompare(
*/
int sqlite3BtreeCloseCursor(BtCursor *pCur){
BtShared *pBt = pCur->pBtree->pBt;
- restoreOrClearCursorPosition(pCur, 0);
+ clearCursorPosition(pCur);
if( pCur->pPrev ){
pCur->pPrev->pNext = pCur->pNext;
}else{
@@ -2874,7 +2868,7 @@ static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){
pTempCur->pNext = 0;
pTempCur->pPrev = 0;
if( pTempCur->pPage ){
- sqlite3pager_ref(pTempCur->pPage->aData);
+ sqlite3PagerRef(pTempCur->pPage->pDbPage);
}
}
@@ -2884,7 +2878,7 @@ static void getTempCursor(BtCursor *pCur, BtCursor *pTempCur){
*/
static void releaseTempCursor(BtCursor *pCur){
if( pCur->pPage ){
- sqlite3pager_unref(pCur->pPage->aData);
+ sqlite3PagerUnref(pCur->pPage->pDbPage);
}
}
@@ -2917,7 +2911,7 @@ static void getCellInfo(BtCursor *pCur){
** itself, not the number of bytes in the key.
*/
int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
- int rc = restoreOrClearCursorPosition(pCur, 1);
+ int rc = restoreOrClearCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
if( pCur->eState==CURSOR_INVALID ){
@@ -2938,7 +2932,7 @@ int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
** the database is empty) then *pSize is set to 0.
*/
int sqlite3BtreeDataSize(BtCursor *pCur, u32 *pSize){
- int rc = restoreOrClearCursorPosition(pCur, 1);
+ int rc = restoreOrClearCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
if( pCur->eState==CURSOR_INVALID ){
@@ -2980,7 +2974,6 @@ static int getPayload(
assert( pCur->eState==CURSOR_VALID );
pBt = pCur->pBtree->pBt;
pPage = pCur->pPage;
- pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
getCellInfo(pCur);
aPayload = pCur->info.pCell + pCur->info.nHeader;
@@ -3015,10 +3008,12 @@ static int getPayload(
if( amt>0 ){
nextPage = get4byte(&aPayload[pCur->info.nLocal]);
while( amt>0 && nextPage ){
- rc = sqlite3pager_get(pBt->pPager, nextPage, (void**)&aPayload);
+ DbPage *pDbPage;
+ rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage);
if( rc!=0 ){
return rc;
}
+ aPayload = sqlite3PagerGetData(pDbPage);
nextPage = get4byte(aPayload);
if( offset<ovflSize ){
int a = amt;
@@ -3032,7 +3027,7 @@ static int getPayload(
}else{
offset -= ovflSize;
}
- sqlite3pager_unref(aPayload);
+ sqlite3PagerUnref(pDbPage);
}
}
@@ -3052,7 +3047,7 @@ static int getPayload(
** the available payload.
*/
int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- int rc = restoreOrClearCursorPosition(pCur, 1);
+ int rc = restoreOrClearCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_VALID );
assert( pCur->pPage!=0 );
@@ -3076,7 +3071,7 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
** the available payload.
*/
int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
- int rc = restoreOrClearCursorPosition(pCur, 1);
+ int rc = restoreOrClearCursorPosition(pCur);
if( rc==SQLITE_OK ){
assert( pCur->eState==CURSOR_VALID );
assert( pCur->pPage!=0 );
@@ -3118,7 +3113,6 @@ static const unsigned char *fetchPayload(
assert( pCur!=0 && pCur->pPage!=0 );
assert( pCur->eState==CURSOR_VALID );
pPage = pCur->pPage;
- pageIntegrity(pPage);
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
getCellInfo(pCur);
aPayload = pCur->info.pCell;
@@ -3180,7 +3174,6 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
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;
pOldPage->idxShift = 0;
@@ -3228,12 +3221,10 @@ static void moveToParent(BtCursor *pCur){
pPage = pCur->pPage;
assert( pPage!=0 );
assert( !isRootPage(pPage) );
- pageIntegrity(pPage);
pParent = pPage->pParent;
assert( pParent!=0 );
- pageIntegrity(pParent);
idxParent = pPage->idxParent;
- sqlite3pager_ref(pParent->aData);
+ sqlite3PagerRef(pParent->pDbPage);
releasePage(pPage);
pCur->pPage = pParent;
pCur->info.nSize = 0;
@@ -3249,7 +3240,9 @@ static int moveToRoot(BtCursor *pCur){
int rc = SQLITE_OK;
BtShared *pBt = pCur->pBtree->pBt;
- restoreOrClearCursorPosition(pCur, 0);
+ if( pCur->eState==CURSOR_REQUIRESEEK ){
+ clearCursorPosition(pCur);
+ }
pRoot = pCur->pPage;
if( pRoot && pRoot->pgno==pCur->pgnoRoot ){
assert( pRoot->isInit );
@@ -3261,7 +3254,6 @@ static int moveToRoot(BtCursor *pCur){
return rc;
}
releasePage(pCur->pPage);
- pageIntegrity(pRoot);
pCur->pPage = pRoot;
}
pCur->idx = 0;
@@ -3392,20 +3384,24 @@ int sqlite3BtreeLast(BtCursor *pCur, int *pRes){
** *pRes>0 The cursor is left pointing at an entry that
** is larger than pKey.
*/
-int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
+int sqlite3BtreeMoveto(
+ BtCursor *pCur, /* The cursor to be moved */
+ const void *pKey, /* The key content for indices. Not used by tables */
+ i64 nKey, /* Size of pKey. Or the key for tables */
+ int biasRight, /* If true, bias the search to the high end */
+ int *pRes /* Search result flag */
+){
int rc;
- int tryRightmost;
rc = moveToRoot(pCur);
if( rc ) return rc;
assert( pCur->pPage );
assert( pCur->pPage->isInit );
- tryRightmost = pCur->pPage->intKey;
if( pCur->eState==CURSOR_INVALID ){
*pRes = -1;
assert( pCur->pPage->nCell==0 );
return SQLITE_OK;
}
- for(;;){
+ for(;;){
int lwr, upr;
Pgno chldPg;
MemPage *pPage = pCur->pPage;
@@ -3415,17 +3411,17 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
if( !pPage->intKey && pKey==0 ){
return SQLITE_CORRUPT_BKPT;
}
- pageIntegrity(pPage);
- while( lwr<=upr ){
+ if( biasRight ){
+ pCur->idx = upr;
+ }else{
+ pCur->idx = (upr+lwr)/2;
+ }
+ if( lwr<=upr ) for(;;){
void *pCellKey;
i64 nCellKey;
- pCur->idx = (lwr+upr)/2;
pCur->info.nSize = 0;
if( pPage->intKey ){
u8 *pCell;
- if( tryRightmost ){
- pCur->idx = upr;
- }
pCell = findCell(pPage, pCur->idx) + pPage->childPtrSize;
if( pPage->hasData ){
u32 dummy;
@@ -3436,7 +3432,6 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
c = -1;
}else if( nCellKey>nKey ){
c = +1;
- tryRightmost = 0;
}else{
c = 0;
}
@@ -3470,6 +3465,10 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
}else{
upr = pCur->idx-1;
}
+ if( lwr>upr ){
+ break;
+ }
+ pCur->idx = (lwr+upr)/2;
}
assert( lwr==upr+1 );
assert( pPage->isInit );
@@ -3521,10 +3520,18 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
MemPage *pPage;
#ifndef SQLITE_OMIT_SHARED_CACHE
- rc = restoreOrClearCursorPosition(pCur, 1);
+ rc = restoreOrClearCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
+#endif
+ assert( pRes!=0 );
+ pPage = pCur->pPage;
+ if( CURSOR_INVALID==pCur->eState ){
+ *pRes = 1;
+ return SQLITE_OK;
+ }
+#ifndef SQLITE_OMIT_SHARED_CACHE
if( pCur->skip>0 ){
pCur->skip = 0;
*pRes = 0;
@@ -3533,12 +3540,6 @@ int sqlite3BtreeNext(BtCursor *pCur, int *pRes){
pCur->skip = 0;
#endif
- assert( pRes!=0 );
- pPage = pCur->pPage;
- if( CURSOR_INVALID==pCur->eState ){
- *pRes = 1;
- return SQLITE_OK;
- }
assert( pPage->isInit );
assert( pCur->idx<pPage->nCell );
@@ -3589,10 +3590,16 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
MemPage *pPage;
#ifndef SQLITE_OMIT_SHARED_CACHE
- rc = restoreOrClearCursorPosition(pCur, 1);
+ rc = restoreOrClearCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
+#endif
+ if( CURSOR_INVALID==pCur->eState ){
+ *pRes = 1;
+ return SQLITE_OK;
+ }
+#ifndef SQLITE_OMIT_SHARED_CACHE
if( pCur->skip<0 ){
pCur->skip = 0;
*pRes = 0;
@@ -3601,11 +3608,6 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
pCur->skip = 0;
#endif
- if( CURSOR_INVALID==pCur->eState ){
- *pRes = 1;
- return SQLITE_OK;
- }
-
pPage = pCur->pPage;
assert( pPage->isInit );
assert( pCur->idx>=0 );
@@ -3639,14 +3641,14 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
/*
** Allocate a new page from the database file.
**
-** The new page is marked as dirty. (In other words, sqlite3pager_write()
+** The new page is marked as dirty. (In other words, sqlite3PagerWrite()
** has already been called on the new page.) The new page has also
** been referenced and the calling routine is responsible for calling
-** sqlite3pager_unref() on the new page when it is done.
+** sqlite3PagerUnref() on the new page when it is done.
**
** SQLITE_OK is returned on success. Any other return value indicates
** an error. *ppPage and *pPgno are undefined in the event of an error.
-** Do not invoke sqlite3pager_unref() on *ppPage if an error is returned.
+** Do not invoke sqlite3PagerUnref() on *ppPage if an error is returned.
**
** If the "nearby" parameter is not 0, then a (feeble) effort is made to
** locate a page close to the page number "nearby". This can be used in an
@@ -3657,7 +3659,7 @@ int sqlite3BtreePrevious(BtCursor *pCur, int *pRes){
** 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(
+static int allocateBtreePage(
BtShared *pBt,
MemPage **ppPage,
Pgno *pPgno,
@@ -3668,14 +3670,14 @@ static int allocatePage(
int rc;
int n; /* Number of pages on the freelist */
int k; /* Number of leaves on the trunk of the freelist */
+ MemPage *pTrunk = 0;
+ MemPage *pPrevTrunk = 0;
pPage1 = pBt->pPage1;
n = get4byte(&pPage1->aData[36]);
if( n>0 ){
/* There are pages on the freelist. Reuse one of those pages. */
- MemPage *pTrunk = 0;
Pgno iTrunk;
- MemPage *pPrevTrunk = 0;
u8 searchList = 0; /* If the free-list must be searched for 'nearby' */
/* If the 'exact' parameter was true and a query of the pointer-map
@@ -3699,7 +3701,7 @@ static int allocatePage(
/* Decrement the free-list count by 1. Set iTrunk to the index of the
** first free-list trunk page. iPrevTrunk is initially 1.
*/
- rc = sqlite3pager_write(pPage1->aData);
+ rc = sqlite3PagerWrite(pPage1->pDbPage);
if( rc ) return rc;
put4byte(&pPage1->aData[36], n-1);
@@ -3714,18 +3716,10 @@ static int allocatePage(
}else{
iTrunk = get4byte(&pPage1->aData[32]);
}
- rc = getPage(pBt, iTrunk, &pTrunk);
- if( rc ){
- releasePage(pPrevTrunk);
- return rc;
- }
-
- /* TODO: This should move to after the loop? */
- rc = sqlite3pager_write(pTrunk->aData);
+ rc = getPage(pBt, iTrunk, &pTrunk, 0);
if( rc ){
- releasePage(pTrunk);
- releasePage(pPrevTrunk);
- return rc;
+ pTrunk = 0;
+ goto end_allocate_page;
}
k = get4byte(&pTrunk->aData[4]);
@@ -3734,6 +3728,10 @@ static int allocatePage(
** So extract the trunk page itself and use it as the newly
** allocated page */
assert( pPrevTrunk==0 );
+ rc = sqlite3PagerWrite(pTrunk->pDbPage);
+ if( rc ){
+ goto end_allocate_page;
+ }
*pPgno = iTrunk;
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
*ppPage = pTrunk;
@@ -3741,7 +3739,8 @@ static int allocatePage(
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
}else if( k>pBt->usableSize/4 - 8 ){
/* Value of k is out of range. Database corruption */
- return SQLITE_CORRUPT_BKPT;
+ rc = SQLITE_CORRUPT_BKPT;
+ goto end_allocate_page;
#ifndef SQLITE_OMIT_AUTOVACUUM
}else if( searchList && nearby==iTrunk ){
/* The list is being searched and this trunk page is the page
@@ -3750,6 +3749,10 @@ static int allocatePage(
assert( *pPgno==iTrunk );
*ppPage = pTrunk;
searchList = 0;
+ rc = sqlite3PagerWrite(pTrunk->pDbPage);
+ if( rc ){
+ goto end_allocate_page;
+ }
if( k==0 ){
if( !pPrevTrunk ){
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
@@ -3763,28 +3766,28 @@ static int allocatePage(
*/
MemPage *pNewTrunk;
Pgno iNewTrunk = get4byte(&pTrunk->aData[8]);
- rc = getPage(pBt, iNewTrunk, &pNewTrunk);
+ rc = getPage(pBt, iNewTrunk, &pNewTrunk, 0);
if( rc!=SQLITE_OK ){
- releasePage(pTrunk);
- releasePage(pPrevTrunk);
- return rc;
+ goto end_allocate_page;
}
- rc = sqlite3pager_write(pNewTrunk->aData);
+ rc = sqlite3PagerWrite(pNewTrunk->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(pNewTrunk);
- releasePage(pTrunk);
- releasePage(pPrevTrunk);
- return rc;
+ goto end_allocate_page;
}
memcpy(&pNewTrunk->aData[0], &pTrunk->aData[0], 4);
put4byte(&pNewTrunk->aData[4], k-1);
memcpy(&pNewTrunk->aData[8], &pTrunk->aData[12], (k-1)*4);
+ releasePage(pNewTrunk);
if( !pPrevTrunk ){
put4byte(&pPage1->aData[32], iNewTrunk);
}else{
+ rc = sqlite3PagerWrite(pPrevTrunk->pDbPage);
+ if( rc ){
+ goto end_allocate_page;
+ }
put4byte(&pPrevTrunk->aData[0], iNewTrunk);
}
- releasePage(pNewTrunk);
}
pTrunk = 0;
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
@@ -3794,6 +3797,10 @@ static int allocatePage(
int closest;
Pgno iPage;
unsigned char *aData = pTrunk->aData;
+ rc = sqlite3PagerWrite(pTrunk->pDbPage);
+ if( rc ){
+ goto end_allocate_page;
+ }
if( nearby>0 ){
int i, dist;
closest = 0;
@@ -3814,7 +3821,7 @@ static int allocatePage(
iPage = get4byte(&aData[8+closest*4]);
if( !searchList || iPage==nearby ){
*pPgno = iPage;
- if( *pPgno>sqlite3pager_pagecount(pBt->pPager) ){
+ if( *pPgno>sqlite3PagerPagecount(pBt->pPager) ){
/* Free page off the end of the file */
return SQLITE_CORRUPT_BKPT;
}
@@ -3825,10 +3832,10 @@ static int allocatePage(
memcpy(&aData[8+closest*4], &aData[4+k*4], 4);
}
put4byte(&aData[4], k-1);
- rc = getPage(pBt, *pPgno, ppPage);
+ rc = getPage(pBt, *pPgno, ppPage, 1);
if( rc==SQLITE_OK ){
- sqlite3pager_dont_rollback((*ppPage)->aData);
- rc = sqlite3pager_write((*ppPage)->aData);
+ sqlite3PagerDontRollback((*ppPage)->pDbPage);
+ rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(*ppPage);
}
@@ -3837,12 +3844,12 @@ static int allocatePage(
}
}
releasePage(pPrevTrunk);
+ pPrevTrunk = 0;
}while( searchList );
- releasePage(pTrunk);
}else{
/* There are no pages on the freelist, so create a new page at the
** end of the file */
- *pPgno = sqlite3pager_pagecount(pBt->pPager) + 1;
+ *pPgno = sqlite3PagerPagecount(pBt->pPager) + 1;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
@@ -3857,9 +3864,9 @@ static int allocatePage(
#endif
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
- rc = getPage(pBt, *pPgno, ppPage);
+ rc = getPage(pBt, *pPgno, ppPage, 0);
if( rc ) return rc;
- rc = sqlite3pager_write((*ppPage)->aData);
+ rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(*ppPage);
}
@@ -3867,13 +3874,17 @@ static int allocatePage(
}
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
+
+end_allocate_page:
+ releasePage(pTrunk);
+ releasePage(pPrevTrunk);
return rc;
}
/*
** Add a page of the database file to the freelist.
**
-** sqlite3pager_unref() is NOT called for pPage.
+** sqlite3PagerUnref() is NOT called for pPage.
*/
static int freePage(MemPage *pPage){
BtShared *pBt = pPage->pBt;
@@ -3887,7 +3898,7 @@ static int freePage(MemPage *pPage){
pPage->pParent = 0;
/* Increment the free page count on pPage1 */
- rc = sqlite3pager_write(pPage1->aData);
+ rc = sqlite3PagerWrite(pPage1->pDbPage);
if( rc ) return rc;
n = get4byte(&pPage1->aData[36]);
put4byte(&pPage1->aData[36], n+1);
@@ -3896,7 +3907,7 @@ static int freePage(MemPage *pPage){
/* If the SQLITE_SECURE_DELETE compile-time option is enabled, then
** always fully overwrite deleted information with zeros.
*/
- rc = sqlite3pager_write(pPage->aData);
+ rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
memset(pPage->aData, 0, pPage->pBt->pageSize);
#endif
@@ -3913,7 +3924,7 @@ static int freePage(MemPage *pPage){
if( n==0 ){
/* This is the first free page */
- rc = sqlite3pager_write(pPage->aData);
+ rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
memset(pPage->aData, 0, 8);
put4byte(&pPage1->aData[32], pPage->pgno);
@@ -3922,13 +3933,13 @@ static int freePage(MemPage *pPage){
/* Other free pages already exist. Retrive the first trunk page
** of the freelist and find out how many leaves it has. */
MemPage *pTrunk;
- rc = getPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk);
+ rc = getPage(pBt, get4byte(&pPage1->aData[32]), &pTrunk, 0);
if( rc ) return rc;
k = get4byte(&pTrunk->aData[4]);
if( k>=pBt->usableSize/4 - 8 ){
/* The trunk is full. Turn the page being freed into a new
** trunk page with no leaves. */
- rc = sqlite3pager_write(pPage->aData);
+ rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
put4byte(pPage->aData, pTrunk->pgno);
put4byte(&pPage->aData[4], 0);
@@ -3937,13 +3948,14 @@ static int freePage(MemPage *pPage){
pPage->pgno, pTrunk->pgno));
}else{
/* Add the newly freed page as a leaf on the current trunk */
- rc = sqlite3pager_write(pTrunk->aData);
- if( rc ) return rc;
- put4byte(&pTrunk->aData[4], k+1);
- put4byte(&pTrunk->aData[8+k*4], pPage->pgno);
+ rc = sqlite3PagerWrite(pTrunk->pDbPage);
+ if( rc==SQLITE_OK ){
+ put4byte(&pTrunk->aData[4], k+1);
+ put4byte(&pTrunk->aData[8+k*4], pPage->pgno);
#ifndef SQLITE_SECURE_DELETE
- sqlite3pager_dont_write(pBt->pPager, pPage->pgno);
+ sqlite3PagerDontWrite(pPage->pDbPage);
#endif
+ }
TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
}
releasePage(pTrunk);
@@ -3959,22 +3971,29 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
CellInfo info;
Pgno ovflPgno;
int rc;
+ int nOvfl;
+ int ovflPageSize;
parseCellPtr(pPage, pCell, &info);
if( info.iOverflow==0 ){
return SQLITE_OK; /* No overflow pages. Return without doing anything */
}
ovflPgno = get4byte(&pCell[info.iOverflow]);
- while( ovflPgno!=0 ){
+ ovflPageSize = pBt->usableSize - 4;
+ nOvfl = (info.nPayload - info.nLocal + ovflPageSize - 1)/ovflPageSize;
+ assert( ovflPgno==0 || nOvfl>0 );
+ while( nOvfl-- ){
MemPage *pOvfl;
- if( ovflPgno>sqlite3pager_pagecount(pBt->pPager) ){
+ if( ovflPgno==0 || ovflPgno>sqlite3PagerPagecount(pBt->pPager) ){
return SQLITE_CORRUPT_BKPT;
}
- rc = getPage(pBt, ovflPgno, &pOvfl);
+ rc = getPage(pBt, ovflPgno, &pOvfl, nOvfl==0);
if( rc ) return rc;
- ovflPgno = get4byte(pOvfl->aData);
+ if( nOvfl ){
+ ovflPgno = get4byte(pOvfl->aData);
+ }
rc = freePage(pOvfl);
- sqlite3pager_unref(pOvfl->aData);
+ sqlite3PagerUnref(pOvfl->pDbPage);
if( rc ) return rc;
}
return SQLITE_OK;
@@ -4049,7 +4068,7 @@ static int fillInCell(
#ifndef SQLITE_OMIT_AUTOVACUUM
Pgno pgnoPtrmap = pgnoOvfl; /* Overflow page pointer-map entry page */
#endif
- rc = allocatePage(pBt, &pOvfl, &pgnoOvfl, pgnoOvfl, 0);
+ rc = allocateBtreePage(pBt, &pOvfl, &pgnoOvfl, pgnoOvfl, 0);
#ifndef SQLITE_OMIT_AUTOVACUUM
/* If the database supports auto-vacuum, and the second or subsequent
** overflow page is being allocated, add an entry to the pointer-map
@@ -4062,7 +4081,6 @@ static int fillInCell(
#endif
if( rc ){
releasePage(pToRelease);
- /* clearCell(pPage, pCell); */
return rc;
}
put4byte(pPrior, pgnoOvfl);
@@ -4099,24 +4117,24 @@ static int fillInCell(
*/
static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){
MemPage *pThis;
- unsigned char *aData;
+ DbPage *pDbPage;
assert( pNewParent!=0 );
if( pgno==0 ) return SQLITE_OK;
assert( pBt->pPager!=0 );
- aData = sqlite3pager_lookup(pBt->pPager, pgno);
- if( aData ){
- pThis = (MemPage*)&aData[pBt->pageSize];
- assert( pThis->aData==aData );
+ pDbPage = sqlite3PagerLookup(pBt->pPager, pgno);
+ if( pDbPage ){
+ pThis = (MemPage *)sqlite3PagerGetExtra(pDbPage);
if( pThis->isInit ){
+ assert( pThis->aData==(sqlite3PagerGetData(pDbPage)) );
if( pThis->pParent!=pNewParent ){
- if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
+ if( pThis->pParent ) sqlite3PagerUnref(pThis->pParent->pDbPage);
pThis->pParent = pNewParent;
- sqlite3pager_ref(pNewParent->aData);
+ sqlite3PagerRef(pNewParent->pDbPage);
}
pThis->idxParent = idx;
}
- sqlite3pager_unref(aData);
+ sqlite3PagerUnref(pDbPage);
}
#ifndef SQLITE_OMIT_AUTOVACUUM
@@ -4177,7 +4195,7 @@ static void dropCell(MemPage *pPage, int idx, int sz){
assert( idx>=0 && idx<pPage->nCell );
assert( sz==cellSize(pPage, idx) );
- assert( sqlite3pager_iswriteable(pPage->aData) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
data = pPage->aData;
ptr = &data[pPage->cellOffset + 2*idx];
pc = get2byte(ptr);
@@ -4230,7 +4248,7 @@ static int insertCell(
assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
assert( sz==cellSizePtr(pPage, pCell) );
- assert( sqlite3pager_iswriteable(pPage->aData) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
if( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){
memcpy(pTemp+nSkip, pCell+nSkip, sz-nSkip);
@@ -4267,7 +4285,6 @@ static int insertCell(
put2byte(&data[ins], idx);
put2byte(&data[hdr+3], pPage->nCell);
pPage->idxShift = 1;
- pageIntegrity(pPage);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pPage->pBt->autoVacuum ){
/* The cell may contain a pointer to an overflow page. If so, write
@@ -4275,6 +4292,7 @@ static int insertCell(
*/
CellInfo info;
parseCellPtr(pPage, pCell, &info);
+ assert( (info.nData+(pPage->intKey?0:info.nKey))==info.nPayload );
if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){
Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]);
int rc = ptrmapPut(pPage->pBt, pgnoOvfl, PTRMAP_OVERFLOW1, pPage->pgno);
@@ -4382,7 +4400,7 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
/* Allocate a new page. Insert the overflow cell from pPage
** into it. Then remove the overflow cell from pPage.
*/
- rc = allocatePage(pBt, &pNew, &pgnoNew, 0, 0);
+ rc = allocateBtreePage(pBt, &pNew, &pgnoNew, 0, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -4394,7 +4412,7 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){
/* Set the parent of the newly allocated page to pParent. */
pNew->pParent = pParent;
- sqlite3pager_ref(pParent->aData);
+ sqlite3PagerRef(pParent->pDbPage);
/* pPage is currently the right-child of pParent. Change this
** so that the right-child is the new page allocated above and
@@ -4519,11 +4537,11 @@ static int balance_nonroot(MemPage *pPage){
** Find the parent page.
*/
assert( pPage->isInit );
- assert( sqlite3pager_iswriteable(pPage->aData) );
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
pBt = pPage->pBt;
pParent = pPage->pParent;
assert( pParent );
- if( SQLITE_OK!=(rc = sqlite3pager_write(pParent->aData)) ){
+ if( SQLITE_OK!=(rc = sqlite3PagerWrite(pParent->pDbPage)) ){
return rc;
}
TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno));
@@ -4561,7 +4579,7 @@ static int balance_nonroot(MemPage *pPage){
if( pParent->idxShift ){
Pgno pgno;
pgno = pPage->pgno;
- assert( pgno==sqlite3pager_pagenumber(pPage->aData) );
+ assert( pgno==sqlite3PagerPagenumber(pPage->pDbPage) );
for(idx=0; idx<pParent->nCell; idx++){
if( get4byte(findCell(pParent, idx))==pgno ){
break;
@@ -4578,7 +4596,7 @@ static int balance_nonroot(MemPage *pPage){
** directly to balance_cleanup at any moment.
*/
nOld = nNew = 0;
- sqlite3pager_ref(pParent->aData);
+ sqlite3PagerRef(pParent->pDbPage);
/*
** Find sibling pages to pPage and the cells in pParent that divide
@@ -4822,15 +4840,16 @@ static int balance_nonroot(MemPage *pPage){
pNew = apNew[i] = apOld[i];
pgnoNew[i] = pgnoOld[i];
apOld[i] = 0;
- rc = sqlite3pager_write(pNew->aData);
+ rc = sqlite3PagerWrite(pNew->pDbPage);
+ nNew++;
if( rc ) goto balance_cleanup;
}else{
assert( i>0 );
- rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1], 0);
+ rc = allocateBtreePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1], 0);
if( rc ) goto balance_cleanup;
apNew[i] = pNew;
+ nNew++;
}
- nNew++;
zeroPage(pNew, pageFlags);
}
@@ -5007,8 +5026,6 @@ static int balance_nonroot(MemPage *pPage){
** But the parent page will always be initialized.
*/
assert( pParent->isInit );
- /* assert( pPage->isInit ); // No! pPage might have been added to freelist */
- /* pageIntegrity(pPage); // No! pPage might have been added to freelist */
rc = balance(pParent, 0);
/*
@@ -5067,8 +5084,8 @@ static int balance_shallower(MemPage *pPage){
*/
pgnoChild = get4byte(&pPage->aData[pPage->hdrOffset+8]);
assert( pgnoChild>0 );
- assert( pgnoChild<=sqlite3pager_pagecount(pPage->pBt->pPager) );
- rc = getPage(pPage->pBt, pgnoChild, &pChild);
+ assert( pgnoChild<=sqlite3PagerPagecount(pPage->pBt->pPager) );
+ rc = getPage(pPage->pBt, pgnoChild, &pChild, 0);
if( rc ) goto end_shallow_balance;
if( pPage->pgno==1 ){
rc = initPage(pChild, pPage);
@@ -5149,9 +5166,9 @@ static int balance_deeper(MemPage *pPage){
assert( pPage->pParent==0 );
assert( pPage->nOverflow>0 );
pBt = pPage->pBt;
- rc = allocatePage(pBt, &pChild, &pgnoChild, pPage->pgno, 0);
+ rc = allocateBtreePage(pBt, &pChild, &pgnoChild, pPage->pgno, 0);
if( rc ) return rc;
- assert( sqlite3pager_iswriteable(pChild->aData) );
+ assert( sqlite3PagerIswriteable(pChild->pDbPage) );
usableSize = pBt->usableSize;
data = pPage->aData;
hdr = pPage->hdrOffset;
@@ -5215,27 +5232,35 @@ static int balance(MemPage *pPage, int insert){
/*
** This routine checks all cursors that point to table pgnoRoot.
-** If any of those cursors other than pExclude were opened with
-** wrFlag==0 then this routine returns SQLITE_LOCKED. If all
-** cursors that point to pgnoRoot were opened with wrFlag==1
-** then this routine returns SQLITE_OK.
+** If any of those cursors were opened with wrFlag==0 in a different
+** database connection (a database connection that shares the pager
+** cache with the current connection) and that other connection
+** is not in the ReadUncommmitted state, then this routine returns
+** SQLITE_LOCKED.
**
** In addition to checking for read-locks (where a read-lock
** means a cursor opened with wrFlag==0) this routine also moves
-** all cursors other than pExclude so that they are pointing to the
-** first Cell on root page. This is necessary because an insert
+** all cursors write cursors so that they are pointing to the
+** first Cell on the 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(BtShared *pBt, Pgno pgnoRoot, BtCursor *pExclude){
+static int checkReadLocks(Btree *pBtree, Pgno pgnoRoot, BtCursor *pExclude){
BtCursor *p;
+ BtShared *pBt = pBtree->pBt;
+ sqlite3 *db = pBtree->pSqlite;
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 ){
+ if( p==pExclude ) continue;
+ if( p->eState!=CURSOR_VALID ) continue;
+ if( p->pgnoRoot!=pgnoRoot ) continue;
+ if( p->wrFlag==0 ){
+ sqlite3 *dbOther = p->pBtree->pSqlite;
+ if( dbOther==0 ||
+ (dbOther!=db && (dbOther->flags & SQLITE_ReadUncommitted)==0) ){
+ return SQLITE_LOCKED;
+ }
+ }else if( p->pPage->pgno!=p->pgnoRoot ){
moveToRoot(p);
}
}
@@ -5254,7 +5279,8 @@ static int checkReadLocks(BtShared *pBt, Pgno pgnoRoot, BtCursor *pExclude){
int sqlite3BtreeInsert(
BtCursor *pCur, /* Insert data into the table of this cursor */
const void *pKey, i64 nKey, /* The key of the new record */
- const void *pData, int nData /* The data of the new record */
+ const void *pData, int nData, /* The data of the new record */
+ int appendBias /* True if this is likely an append */
){
int rc;
int loc;
@@ -5272,15 +5298,15 @@ int sqlite3BtreeInsert(
if( !pCur->wrFlag ){
return SQLITE_PERM; /* Cursor not open for writing */
}
- if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
+ if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
/* Save the positions of any other cursors open on this table */
- restoreOrClearCursorPosition(pCur, 0);
+ clearCursorPosition(pCur);
if(
SQLITE_OK!=(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur)) ||
- SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, &loc))
+ SQLITE_OK!=(rc = sqlite3BtreeMoveto(pCur, pKey, nKey, appendBias, &loc))
){
return rc;
}
@@ -5292,7 +5318,7 @@ int sqlite3BtreeInsert(
pCur->pgnoRoot, nKey, nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit );
- rc = sqlite3pager_write(pPage->aData);
+ rc = sqlite3PagerWrite(pPage->pDbPage);
if( rc ) return rc;
newCell = sqliteMallocRaw( MX_CELL_SIZE(pBt) );
if( newCell==0 ) return SQLITE_NOMEM;
@@ -5354,19 +5380,19 @@ int sqlite3BtreeDelete(BtCursor *pCur){
if( !pCur->wrFlag ){
return SQLITE_PERM; /* Did not open this cursor for writing */
}
- if( checkReadLocks(pBt, pCur->pgnoRoot, pCur) ){
+ if( checkReadLocks(pCur->pBtree, pCur->pgnoRoot, pCur) ){
return SQLITE_LOCKED; /* The table pCur points to has a read lock */
}
/* 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
+ ** open on the same table. Then call sqlite3PagerWrite() on the page
** that the entry will be deleted from.
*/
if(
- (rc = restoreOrClearCursorPosition(pCur, 1))!=0 ||
+ (rc = restoreOrClearCursorPosition(pCur))!=0 ||
(rc = saveAllCursors(pBt, pCur->pgnoRoot, pCur))!=0 ||
- (rc = sqlite3pager_write(pPage->aData))!=0
+ (rc = sqlite3PagerWrite(pPage->pDbPage))!=0
){
return rc;
}
@@ -5400,13 +5426,8 @@ int sqlite3BtreeDelete(BtCursor *pCur){
assert( !pPage->leafData );
getTempCursor(pCur, &leafCur);
rc = sqlite3BtreeNext(&leafCur, &notUsed);
- if( rc!=SQLITE_OK ){
- if( rc!=SQLITE_NOMEM ){
- rc = SQLITE_CORRUPT_BKPT;
- }
- }
if( rc==SQLITE_OK ){
- rc = sqlite3pager_write(leafCur.pPage->aData);
+ rc = sqlite3PagerWrite(leafCur.pPage->pDbPage);
}
if( rc==SQLITE_OK ){
TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n",
@@ -5477,7 +5498,7 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
}
#ifdef SQLITE_OMIT_AUTOVACUUM
- rc = allocatePage(pBt, &pRoot, &pgnoRoot, 1, 0);
+ rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0);
if( rc ) return rc;
#else
if( pBt->autoVacuum ){
@@ -5505,17 +5526,25 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
** be moved to the allocated page (unless the allocated page happens
** to reside at pgnoRoot).
*/
- rc = allocatePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1);
+ rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1);
if( rc!=SQLITE_OK ){
return rc;
}
if( pgnoMove!=pgnoRoot ){
+ /* pgnoRoot is the page that will be used for the root-page of
+ ** the new table (assuming an error did not occur). But we were
+ ** allocated pgnoMove. If required (i.e. if it was not allocated
+ ** by extending the file), the current page at position pgnoMove
+ ** is already journaled.
+ */
u8 eType;
Pgno iPtrPage;
releasePage(pPageMove);
- rc = getPage(pBt, pgnoRoot, &pRoot);
+
+ /* Move the page currently at pgnoRoot to pgnoMove. */
+ rc = getPage(pBt, pgnoRoot, &pRoot, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -5526,21 +5555,23 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
}
assert( eType!=PTRMAP_ROOTPAGE );
assert( eType!=PTRMAP_FREEPAGE );
- rc = sqlite3pager_write(pRoot->aData);
+ rc = sqlite3PagerWrite(pRoot->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(pRoot);
return rc;
}
rc = relocatePage(pBt, pRoot, eType, iPtrPage, pgnoMove);
releasePage(pRoot);
+
+ /* Obtain the page at pgnoRoot */
if( rc!=SQLITE_OK ){
return rc;
}
- rc = getPage(pBt, pgnoRoot, &pRoot);
+ rc = getPage(pBt, pgnoRoot, &pRoot, 0);
if( rc!=SQLITE_OK ){
return rc;
}
- rc = sqlite3pager_write(pRoot->aData);
+ rc = sqlite3PagerWrite(pRoot->pDbPage);
if( rc!=SQLITE_OK ){
releasePage(pRoot);
return rc;
@@ -5562,13 +5593,13 @@ int sqlite3BtreeCreateTable(Btree *p, int *piTable, int flags){
}
}else{
- rc = allocatePage(pBt, &pRoot, &pgnoRoot, 1, 0);
+ rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0);
if( rc ) return rc;
}
#endif
- assert( sqlite3pager_iswriteable(pRoot->aData) );
+ assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
zeroPage(pRoot, flags | PTF_LEAF);
- sqlite3pager_unref(pRoot->aData);
+ sqlite3PagerUnref(pRoot->pDbPage);
*piTable = (int)pgnoRoot;
return SQLITE_OK;
}
@@ -5588,14 +5619,12 @@ static int clearDatabasePage(
unsigned char *pCell;
int i;
- if( pgno>sqlite3pager_pagecount(pBt->pPager) ){
+ if( pgno>sqlite3PagerPagecount(pBt->pPager) ){
return SQLITE_CORRUPT_BKPT;
}
rc = getAndInitPage(pBt, pgno, &pPage, pParent);
if( rc ) goto cleardatabasepage_out;
- rc = sqlite3pager_write(pPage->aData);
- if( rc ) goto cleardatabasepage_out;
for(i=0; i<pPage->nCell; i++){
pCell = findCell(pPage, i);
if( !pPage->leaf ){
@@ -5611,7 +5640,7 @@ static int clearDatabasePage(
}
if( freePageFlag ){
rc = freePage(pPage);
- }else{
+ }else if( (rc = sqlite3PagerWrite(pPage->pDbPage))==0 ){
zeroPage(pPage, pPage->aData[0] | PTF_LEAF);
}
@@ -5631,25 +5660,13 @@ cleardatabasepage_out:
*/
int sqlite3BtreeClearTable(Btree *p, int iTable){
int rc;
- BtCursor *pCur;
BtShared *pBt = p->pBt;
- sqlite3 *db = p->pSqlite;
if( p->inTrans!=TRANS_WRITE ){
return pBt->readOnly ? SQLITE_READONLY : SQLITE_ERROR;
}
-
- /* If this connection is not in read-uncommitted mode and currently has
- ** a read-cursor open on the table being cleared, return SQLITE_LOCKED.
- */
- if( 0==db || 0==(db->flags&SQLITE_ReadUncommitted) ){
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- if( pCur->pBtree==p && pCur->pgnoRoot==(Pgno)iTable ){
- if( 0==pCur->wrFlag ){
- return SQLITE_LOCKED;
- }
- moveToRoot(pCur);
- }
- }
+ rc = checkReadLocks(p, iTable, 0);
+ if( rc ){
+ return rc;
}
/* Save the position of all cursors open on this table */
@@ -5699,7 +5716,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
return SQLITE_LOCKED;
}
- rc = getPage(pBt, (Pgno)iTable, &pPage);
+ rc = getPage(pBt, (Pgno)iTable, &pPage, 0);
if( rc ) return rc;
rc = sqlite3BtreeClearTable(p, iTable);
if( rc ){
@@ -5738,7 +5755,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
*/
MemPage *pMove;
releasePage(pPage);
- rc = getPage(pBt, maxRootPgno, &pMove);
+ rc = getPage(pBt, maxRootPgno, &pMove, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -5747,7 +5764,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
if( rc!=SQLITE_OK ){
return rc;
}
- rc = getPage(pBt, maxRootPgno, &pMove);
+ rc = getPage(pBt, maxRootPgno, &pMove, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -5799,6 +5816,7 @@ int sqlite3BtreeDropTable(Btree *p, int iTable, int *piMoved){
** free pages is not visible. So Cookie[0] is the same as Meta[1].
*/
int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
+ DbPage *pDbPage;
int rc;
unsigned char *pP1;
BtShared *pBt = p->pBt;
@@ -5814,10 +5832,11 @@ int sqlite3BtreeGetMeta(Btree *p, int idx, u32 *pMeta){
}
assert( idx>=0 && idx<=15 );
- rc = sqlite3pager_get(pBt->pPager, 1, (void**)&pP1);
+ rc = sqlite3PagerGet(pBt->pPager, 1, &pDbPage);
if( rc ) return rc;
+ pP1 = (unsigned char *)sqlite3PagerGetData(pDbPage);
*pMeta = get4byte(&pP1[36 + idx*4]);
- sqlite3pager_unref(pP1);
+ sqlite3PagerUnref(pDbPage);
/* If autovacuumed is disabled in this build but we are trying to
** access an autovacuumed database, then make the database readonly.
@@ -5845,7 +5864,7 @@ int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){
}
assert( pBt->pPage1!=0 );
pP1 = pBt->pPage1->aData;
- rc = sqlite3pager_write(pP1);
+ rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
if( rc ) return rc;
put4byte(&pP1[36 + idx*4], iMeta);
return SQLITE_OK;
@@ -5881,7 +5900,7 @@ static int btreePageDump(BtShared *pBt, int pgno, int recursive, MemPage *pParen
char range[20];
unsigned char payload[20];
- rc = getPage(pBt, (Pgno)pgno, &pPage);
+ rc = getPage(pBt, (Pgno)pgno, &pPage, 0);
isInit = pPage->isInit;
if( pPage->isInit==0 ){
initPage(pPage, pParent);
@@ -5960,7 +5979,7 @@ static int btreePageDump(BtShared *pBt, int pgno, int recursive, MemPage *pParen
btreePageDump(pBt, get4byte(&data[hdr+8]), 1, pPage);
}
pPage->isInit = isInit;
- sqlite3pager_unref(data);
+ sqlite3PagerUnref(pPage->pDbPage);
fflush(stdout);
return SQLITE_OK;
}
@@ -5969,7 +5988,7 @@ int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
}
#endif
-#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
/*
** Fill aResult[] with information about the entry and page that the
** cursor is pointing to.
@@ -5984,6 +6003,7 @@ int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
** aResult[7] = Header size in bytes
** aResult[8] = Local payload size
** aResult[9] = Parent page number
+** aResult[10]= Page number of the first overflow page
**
** This routine is used for testing and debugging only.
*/
@@ -5992,20 +6012,18 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
MemPage *pPage = pCur->pPage;
BtCursor tmpCur;
- int rc = restoreOrClearCursorPosition(pCur, 1);
+ int rc = restoreOrClearCursorPosition(pCur);
if( rc!=SQLITE_OK ){
return rc;
}
- pageIntegrity(pPage);
assert( pPage->isInit );
getTempCursor(pCur, &tmpCur);
while( upCnt-- ){
moveToParent(&tmpCur);
}
pPage = tmpCur.pPage;
- pageIntegrity(pPage);
- aResult[0] = sqlite3pager_pagenumber(pPage->aData);
+ aResult[0] = sqlite3PagerPagenumber(pPage->pDbPage);
assert( aResult[0]==pPage->pgno );
aResult[1] = tmpCur.idx;
aResult[2] = pPage->nCell;
@@ -6034,6 +6052,11 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
}else{
aResult[9] = pPage->pParent->pgno;
}
+ if( tmpCur.info.iOverflow ){
+ aResult[10] = get4byte(&tmpCur.info.pCell[tmpCur.info.iOverflow]);
+ }else{
+ aResult[10] = 0;
+ }
releaseTempCursor(&tmpCur);
return SQLITE_OK;
}
@@ -6054,10 +6077,12 @@ Pager *sqlite3BtreePager(Btree *p){
typedef struct IntegrityCk IntegrityCk;
struct IntegrityCk {
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. */
+ 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 */
+ int mxErr; /* Stop accumulating errors when this reaches zero */
+ char *zErrMsg; /* An error message. NULL if no errors seen. */
+ int nErr; /* Number of messages written to zErrMsg so far */
};
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
@@ -6072,6 +6097,9 @@ static void checkAppendMsg(
){
va_list ap;
char *zMsg2;
+ if( !pCheck->mxErr ) return;
+ pCheck->mxErr--;
+ pCheck->nErr++;
va_start(ap, zFormat);
zMsg2 = sqlite3VMPrintf(zFormat, ap);
va_end(ap);
@@ -6155,8 +6183,9 @@ static void checkList(
int i;
int expected = N;
int iFirst = iPage;
- while( N-- > 0 ){
- unsigned char *pOvfl;
+ while( N-- > 0 && pCheck->mxErr ){
+ DbPage *pOvflPage;
+ unsigned char *pOvflData;
if( iPage<1 ){
checkAppendMsg(pCheck, zContext,
"%d of %d pages missing from overflow list starting at %d",
@@ -6164,12 +6193,13 @@ static void checkList(
break;
}
if( checkRef(pCheck, iPage, zContext) ) break;
- if( sqlite3pager_get(pCheck->pPager, (Pgno)iPage, (void**)&pOvfl) ){
+ if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage) ){
checkAppendMsg(pCheck, zContext, "failed to get page %d", iPage);
break;
}
+ pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
if( isFreeList ){
- int n = get4byte(&pOvfl[4]);
+ int n = get4byte(&pOvflData[4]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pCheck->pBt->autoVacuum ){
checkPtrmap(pCheck, iPage, PTRMAP_FREEPAGE, 0, zContext);
@@ -6181,7 +6211,7 @@ static void checkList(
N--;
}else{
for(i=0; i<n; i++){
- Pgno iFreePage = get4byte(&pOvfl[8+i*4]);
+ Pgno iFreePage = get4byte(&pOvflData[8+i*4]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pCheck->pBt->autoVacuum ){
checkPtrmap(pCheck, iFreePage, PTRMAP_FREEPAGE, 0, zContext);
@@ -6199,13 +6229,13 @@ static void checkList(
** the following page matches iPage.
*/
if( pCheck->pBt->autoVacuum && N>0 ){
- i = get4byte(pOvfl);
+ i = get4byte(pOvflData);
checkPtrmap(pCheck, i, PTRMAP_OVERFLOW2, iPage, zContext);
}
}
#endif
- iPage = get4byte(pOvfl);
- sqlite3pager_unref(pOvfl);
+ iPage = get4byte(pOvflData);
+ sqlite3PagerUnref(pOvflPage);
}
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -6253,7 +6283,7 @@ static int checkTreePage(
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage, zParentContext) ) return 0;
- if( (rc = getPage(pBt, (Pgno)iPage, &pPage))!=0 ){
+ if( (rc = getPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck, zContext,
"unable to get the page. error code=%d", rc);
return 0;
@@ -6267,7 +6297,7 @@ static int checkTreePage(
/* Check out all the cells.
*/
depth = 0;
- for(i=0; i<pPage->nCell; i++){
+ for(i=0; i<pPage->nCell && pCheck->mxErr; i++){
u8 *pCell;
int sz;
CellInfo info;
@@ -6279,6 +6309,7 @@ static int checkTreePage(
parseCellPtr(pPage, pCell, &info);
sz = info.nData;
if( !pPage->intKey ) sz += info.nKey;
+ assert( sz==info.nPayload );
if( sz>info.nLocal ){
int nPage = (sz - info.nLocal + usableSize - 5)/(usableSize - 4);
Pgno pgnoOvfl = get4byte(&pCell[info.iOverflow]);
@@ -6382,19 +6413,28 @@ static int checkTreePage(
** 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 *p, int *aRoot, int nRoot){
+char *sqlite3BtreeIntegrityCheck(
+ Btree *p, /* The btree to be checked */
+ int *aRoot, /* An array of root pages numbers for individual trees */
+ int nRoot, /* Number of entries in aRoot[] */
+ int mxErr, /* Stop reporting errors after this many */
+ int *pnErr /* Write number of errors seen to this variable */
+){
int i;
int nRef;
IntegrityCk sCheck;
BtShared *pBt = p->pBt;
- nRef = sqlite3pager_refcount(pBt->pPager);
+ nRef = sqlite3PagerRefcount(pBt->pPager);
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);
+ sCheck.nPage = sqlite3PagerPagecount(sCheck.pPager);
+ sCheck.mxErr = mxErr;
+ sCheck.nErr = 0;
+ *pnErr = 0;
if( sCheck.nPage==0 ){
unlockBtreeIfUnused(pBt);
return 0;
@@ -6402,6 +6442,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
sCheck.anRef = sqliteMallocRaw( (sCheck.nPage+1)*sizeof(sCheck.anRef[0]) );
if( !sCheck.anRef ){
unlockBtreeIfUnused(pBt);
+ *pnErr = 1;
return sqlite3MPrintf("Unable to malloc %d bytes",
(sCheck.nPage+1)*sizeof(sCheck.anRef[0]));
}
@@ -6419,7 +6460,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Check all the tables.
*/
- for(i=0; i<nRoot; i++){
+ for(i=0; i<nRoot && sCheck.mxErr; i++){
if( aRoot[i]==0 ) continue;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum && aRoot[i]>1 ){
@@ -6431,7 +6472,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Make sure every page in the file is referenced
*/
- for(i=1; i<=sCheck.nPage; i++){
+ for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
if( sCheck.anRef[i]==0 ){
checkAppendMsg(&sCheck, 0, "Page %d is never used", i);
@@ -6454,16 +6495,17 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
/* Make sure this analysis did not leave any unref() pages
*/
unlockBtreeIfUnused(pBt);
- if( nRef != sqlite3pager_refcount(pBt->pPager) ){
+ if( nRef != sqlite3PagerRefcount(pBt->pPager) ){
checkAppendMsg(&sCheck, 0,
"Outstanding page count goes from %d to %d during this analysis",
- nRef, sqlite3pager_refcount(pBt->pPager)
+ nRef, sqlite3PagerRefcount(pBt->pPager)
);
}
/* Clean up and report errors.
*/
sqliteFree(sCheck.anRef);
+ *pnErr = sCheck.nErr;
return sCheck.zErrMsg;
}
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -6473,7 +6515,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
*/
const char *sqlite3BtreeGetFilename(Btree *p){
assert( p->pBt->pPager!=0 );
- return sqlite3pager_filename(p->pBt->pPager);
+ return sqlite3PagerFilename(p->pBt->pPager);
}
/*
@@ -6481,7 +6523,7 @@ const char *sqlite3BtreeGetFilename(Btree *p){
*/
const char *sqlite3BtreeGetDirname(Btree *p){
assert( p->pBt->pPager!=0 );
- return sqlite3pager_dirname(p->pBt->pPager);
+ return sqlite3PagerDirname(p->pBt->pPager);
}
/*
@@ -6491,7 +6533,7 @@ const char *sqlite3BtreeGetDirname(Btree *p){
*/
const char *sqlite3BtreeGetJournalname(Btree *p){
assert( p->pBt->pPager!=0 );
- return sqlite3pager_journalname(p->pBt->pPager);
+ return sqlite3PagerJournalname(p->pBt->pPager);
}
#ifndef SQLITE_OMIT_VACUUM
@@ -6513,30 +6555,42 @@ int sqlite3BtreeCopyFile(Btree *pTo, Btree *pFrom){
return SQLITE_ERROR;
}
if( pBtTo->pCursor ) return SQLITE_BUSY;
- nToPage = sqlite3pager_pagecount(pBtTo->pPager);
- nPage = sqlite3pager_pagecount(pBtFrom->pPager);
+ nToPage = sqlite3PagerPagecount(pBtTo->pPager);
+ nPage = sqlite3PagerPagecount(pBtFrom->pPager);
iSkip = PENDING_BYTE_PAGE(pBtTo);
for(i=1; rc==SQLITE_OK && i<=nPage; i++){
- void *pPage;
+ DbPage *pDbPage;
if( i==iSkip ) continue;
- rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage);
- if( rc ) break;
- rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage);
+ rc = sqlite3PagerGet(pBtFrom->pPager, i, &pDbPage);
if( rc ) break;
- sqlite3pager_unref(pPage);
+ rc = sqlite3PagerOverwrite(pBtTo->pPager, i, sqlite3PagerGetData(pDbPage));
+ sqlite3PagerUnref(pDbPage);
}
+
+ /* If the file is shrinking, journal the pages that are being truncated
+ ** so that they can be rolled back if the commit fails.
+ */
for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
- void *pPage;
+ DbPage *pDbPage;
if( i==iSkip ) continue;
- rc = sqlite3pager_get(pBtTo->pPager, i, &pPage);
+ rc = sqlite3PagerGet(pBtTo->pPager, i, &pDbPage);
if( rc ) break;
- rc = sqlite3pager_write(pPage);
- sqlite3pager_unref(pPage);
- sqlite3pager_dont_write(pBtTo->pPager, i);
+ rc = sqlite3PagerWrite(pDbPage);
+ sqlite3PagerDontWrite(pDbPage);
+ /* Yeah. It seems wierd to call DontWrite() right after Write(). But
+ ** that is because the names of those procedures do not exactly
+ ** represent what they do. Write() really means "put this page in the
+ ** rollback journal and mark it as dirty so that it will be written
+ ** to the database file later." DontWrite() undoes the second part of
+ ** that and prevents the page from being written to the database. The
+ ** page is still on the rollback journal, though. And that is the whole
+ ** point of this loop: to put pages on the rollback journal. */
+ sqlite3PagerUnref(pDbPage);
}
if( !rc && nPage<nToPage ){
- rc = sqlite3pager_truncate(pBtTo->pPager, nPage);
+ rc = sqlite3PagerTruncate(pBtTo->pPager, nPage);
}
+
if( rc ){
sqlite3BtreeRollback(pTo);
}
@@ -6566,38 +6620,6 @@ int sqlite3BtreeIsInReadTrans(Btree *p){
}
/*
-** This call is a no-op if no write-transaction is currently active on pBt.
-**
-** Otherwise, sync the database file for the btree pBt. zMaster points to
-** the name of a master journal file that should be written into the
-** individual journal file, or is NULL, indicating no master journal file
-** (single database transaction).
-**
-** When this is called, the master journal should already have been
-** 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 *p, const char *zMaster){
- int rc = SQLITE_OK;
- if( p->inTrans==TRANS_WRITE ){
- BtShared *pBt = p->pBt;
- Pgno nTrunc = 0;
-#ifndef SQLITE_OMIT_AUTOVACUUM
- if( pBt->autoVacuum ){
- rc = autoVacuumCommit(pBt, &nTrunc);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- }
-#endif
- rc = sqlite3pager_sync(pBt->pPager, zMaster, nTrunc);
- }
- return rc;
-}
-
-/*
** 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
@@ -6667,7 +6689,7 @@ int sqlite3_shared_cache_report(
BtShared *pBt;
Tcl_Obj *pRet = Tcl_NewObj();
for(pBt=pTd->pBtree; pBt; pBt=pBt->pNext){
- const char *zFile = sqlite3pager_filename(pBt->pPager);
+ const char *zFile = sqlite3PagerFilename(pBt->pPager);
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewStringObj(zFile, -1));
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(pBt->nRef));
}
diff --git a/ext/pdo_sqlite/sqlite/src/btree.h b/ext/pdo_sqlite/sqlite/src/btree.h
index 896ebf11b..59c9b855b 100644
--- a/ext/pdo_sqlite/sqlite/src/btree.h
+++ b/ext/pdo_sqlite/sqlite/src/btree.h
@@ -67,6 +67,8 @@ int sqlite3BtreeGetReserve(Btree*);
int sqlite3BtreeSetAutoVacuum(Btree *, int);
int sqlite3BtreeGetAutoVacuum(Btree *);
int sqlite3BtreeBeginTrans(Btree*,int);
+int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
+int sqlite3BtreeCommitPhaseTwo(Btree*);
int sqlite3BtreeCommit(Btree*);
int sqlite3BtreeRollback(Btree*);
int sqlite3BtreeBeginStmt(Btree*);
@@ -76,7 +78,6 @@ int sqlite3BtreeCreateTable(Btree*, int*, int flags);
int sqlite3BtreeIsInTrans(Btree*);
int sqlite3BtreeIsInStmt(Btree*);
int sqlite3BtreeIsInReadTrans(Btree*);
-int sqlite3BtreeSync(Btree*, const char *zMaster);
void *sqlite3BtreeSchema(Btree *, int, void(*)(void *));
int sqlite3BtreeSchemaLocked(Btree *);
int sqlite3BtreeLockTable(Btree *, int, u8);
@@ -114,10 +115,10 @@ void sqlite3BtreeSetCompare(
);
int sqlite3BtreeCloseCursor(BtCursor*);
-int sqlite3BtreeMoveto(BtCursor*, const void *pKey, i64 nKey, int *pRes);
+int sqlite3BtreeMoveto(BtCursor*,const void *pKey,i64 nKey,int bias,int *pRes);
int sqlite3BtreeDelete(BtCursor*);
int sqlite3BtreeInsert(BtCursor*, const void *pKey, i64 nKey,
- const void *pData, int nData);
+ const void *pData, int nData, int bias);
int sqlite3BtreeFirst(BtCursor*, int *pRes);
int sqlite3BtreeLast(BtCursor*, int *pRes);
int sqlite3BtreeNext(BtCursor*, int *pRes);
@@ -131,7 +132,7 @@ const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
-char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot);
+char *sqlite3BtreeIntegrityCheck(Btree*, int *aRoot, int nRoot, int, int*);
struct Pager *sqlite3BtreePager(Btree*);
diff --git a/ext/pdo_sqlite/sqlite/src/build.c b/ext/pdo_sqlite/sqlite/src/build.c
index 5294c1a31..2dc8c52b4 100644
--- a/ext/pdo_sqlite/sqlite/src/build.c
+++ b/ext/pdo_sqlite/sqlite/src/build.c
@@ -82,7 +82,7 @@ void sqlite3TableLock(
}
nBytes = sizeof(TableLock) * (pParse->nTableLock+1);
- sqliteReallocOrFree((void **)&pParse->aTableLock, nBytes);
+ pParse->aTableLock = sqliteReallocOrFree(pParse->aTableLock, nBytes);
if( pParse->aTableLock ){
p = &pParse->aTableLock[pParse->nTableLock++];
p->iDb = iDb;
@@ -443,17 +443,6 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){
}
/*
-** This routine is called whenever a rollback occurs. If there were
-** schema changes during the transaction, then we have to reset the
-** internal hash tables and reload them from disk.
-*/
-void sqlite3RollbackInternalChanges(sqlite3 *db){
- if( db->flags & SQLITE_InternChanges ){
- sqlite3ResetInternalSchema(db, 0);
- }
-}
-
-/*
** This routine is called when a commit occurs.
*/
void sqlite3CommitInternalChanges(sqlite3 *db){
@@ -489,18 +478,11 @@ static void sqliteResetColumnNames(Table *pTable){
** foreign keys from the sqlite.aFKey hash table. But it does destroy
** memory structures of the indices and foreign keys associated with
** the table.
-**
-** Indices associated with the table are unlinked from the "db"
-** data structure if db!=NULL. If db==NULL, indices attached to
-** the table are deleted, but it is assumed they have already been
-** unlinked.
*/
-void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
+void sqlite3DeleteTable(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. */
@@ -520,7 +502,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
#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
+ ** should have already been unlinked from the pSchema->aFKey hash table
*/
for(pFKey=pTable->pFKey; pFKey; pFKey=pNextFKey){
pNextFKey = pFKey->pNextFrom;
@@ -572,7 +554,7 @@ void sqlite3UnlinkAndDeleteTable(sqlite3 *db, int iDb, const char *zTabName){
}
}
#endif
- sqlite3DeleteTable(db, p);
+ sqlite3DeleteTable(p);
}
db->flags |= SQLITE_InternChanges;
}
@@ -821,7 +803,7 @@ void sqlite3StartTable(
pTable->iPKey = -1;
pTable->pSchema = db->aDb[iDb].pSchema;
pTable->nRef = 1;
- if( pParse->pNewTable ) sqlite3DeleteTable(db, pParse->pNewTable);
+ if( pParse->pNewTable ) sqlite3DeleteTable(pParse->pNewTable);
pParse->pNewTable = pTable;
/* If this is the magic sqlite_sequence table used by autoincrement,
@@ -887,7 +869,7 @@ void sqlite3StartTable(
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_Insert, 0, OPFLAG_APPEND);
sqlite3VdbeAddOp(v, OP_Close, 0, 0);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
}
@@ -1077,8 +1059,12 @@ void sqlite3AddDefaultValue(Parse *pParse, Expr *pExpr){
sqlite3ErrorMsg(pParse, "default value of column [%s] is not constant",
pCol->zName);
}else{
+ Expr *pCopy;
sqlite3ExprDelete(pCol->pDflt);
- pCol->pDflt = sqlite3ExprDup(pExpr);
+ pCol->pDflt = pCopy = sqlite3ExprDup(pExpr);
+ if( pCopy ){
+ sqlite3TokenCopy(&pCopy->span, &pExpr->span);
+ }
}
}
sqlite3ExprDelete(pExpr);
@@ -1218,6 +1204,10 @@ void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
** If no versions of the requested collations sequence are available, or
** another error occurs, NULL is returned and an error message written into
** pParse.
+**
+** This routine is a wrapper around sqlite3FindCollSeq(). This routine
+** invokes the collation factory if the named collation cannot be found
+** and generates an error message.
*/
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
sqlite3 *db = pParse->db;
@@ -1487,7 +1477,7 @@ void sqlite3EndTable(
p->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
- sqlite3DeleteTable(0, pSelTab);
+ sqlite3DeleteTable(pSelTab);
}
}
@@ -1586,7 +1576,8 @@ void sqlite3CreateView(
Token *pName1, /* The token that holds the name of the view */
Token *pName2, /* The token that holds the name of the view */
Select *pSelect, /* A SELECT statement that will become the new view */
- int isTemp /* TRUE for a TEMPORARY view */
+ int isTemp, /* TRUE for a TEMPORARY view */
+ int noErr /* Suppress error messages if VIEW already exists */
){
Table *p;
int n;
@@ -1601,7 +1592,7 @@ void sqlite3CreateView(
sqlite3SelectDelete(pSelect);
return;
}
- sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, 0);
+ sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0, noErr);
p = pParse->pNewTable;
if( p==0 || pParse->nErr ){
sqlite3SelectDelete(pSelect);
@@ -1714,7 +1705,7 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){
pTable->aCol = pSelTab->aCol;
pSelTab->nCol = 0;
pSelTab->aCol = 0;
- sqlite3DeleteTable(0, pSelTab);
+ sqlite3DeleteTable(pSelTab);
pTable->pSchema->flags |= DB_UnresetViews;
}else{
pTable->nCol = 0;
@@ -2212,7 +2203,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
sqlite3VdbeAddOp(v, OP_IsUnique, iIdx, addr2);
sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort,
"indexed columns are not unique", P3_STATIC);
- assert( addr2==sqlite3VdbeCurrentAddr(v) );
+ assert( sqlite3MallocFailed() || addr2==sqlite3VdbeCurrentAddr(v) );
}
sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0);
sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1);
@@ -2348,17 +2339,17 @@ void sqlite3CreateIndex(
}
if( !db->init.busy ){
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
- 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;
}
}
+ if( sqlite3FindIndex(db, zName, pDb->zName)!=0 ){
+ if( !ifNotExist ){
+ sqlite3ErrorMsg(pParse, "index %s already exists", zName);
+ }
+ goto exit_create_index;
+ }
}else{
char zBuf[30];
int n;
@@ -2452,7 +2443,7 @@ void sqlite3CreateIndex(
const char *zColName = pListItem->zName;
Column *pTabCol;
int requestedSortOrder;
- char *zColl; /* Collation sequence */
+ char *zColl; /* Collation sequence name */
for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
@@ -2462,6 +2453,12 @@ void sqlite3CreateIndex(
pTab->zName, zColName);
goto exit_create_index;
}
+ /* TODO: Add a test to make sure that the same column is not named
+ ** more than once within the same index. Only the first instance of
+ ** the column will ever be used by the optimizer. Note that using the
+ ** same column more than once cannot be an error because that would
+ ** break backwards compatibility - it needs to be a warning.
+ */
pIndex->aiColumn[i] = j;
if( pListItem->pExpr ){
assert( pListItem->pExpr->pColl );
@@ -2768,44 +2765,46 @@ exit_drop_index:
}
/*
-** ppArray points into a structure where there is an array pointer
-** followed by two integers. The first integer is the
-** number of elements in the structure array. The second integer
-** is the number of allocated slots in the array.
+** pArray is a pointer to an array of objects. Each object in the
+** array is szEntry bytes in size. This routine allocates a new
+** object on the end of the array.
**
-** In other words, the structure looks something like this:
+** *pnEntry is the number of entries already in use. *pnAlloc is
+** the previously allocated size of the array. initSize is the
+** suggested initial array size allocation.
**
-** struct Example1 {
-** struct subElem *aEntry;
-** int nEntry;
-** int nAlloc;
-** }
+** The index of the new entry is returned in *pIdx.
**
-** The pnEntry parameter points to the equivalent of Example1.nEntry.
-**
-** This routine allocates a new slot in the array, zeros it out,
-** and returns its index. If malloc fails a negative number is returned.
-**
-** szEntry is the sizeof of a single array entry. initSize is the
-** number of array entries allocated on the initial allocation.
+** This routine returns a pointer to the array of objects. This
+** might be the same as the pArray parameter or it might be a different
+** pointer if the array was resized.
*/
-int sqlite3ArrayAllocate(void **ppArray, int szEntry, int initSize){
- char *p;
- int *an = (int*)&ppArray[1];
- if( an[0]>=an[1] ){
+void *sqlite3ArrayAllocate(
+ void *pArray, /* Array of objects. Might be reallocated */
+ int szEntry, /* Size of each object in the array */
+ int initSize, /* Suggested initial allocation, in elements */
+ int *pnEntry, /* Number of objects currently in use */
+ int *pnAlloc, /* Current size of the allocation, in elements */
+ int *pIdx /* Write the index of a new slot here */
+){
+ char *z;
+ if( *pnEntry >= *pnAlloc ){
void *pNew;
int newSize;
- newSize = an[1]*2 + initSize;
- pNew = sqliteRealloc(*ppArray, newSize*szEntry);
+ newSize = (*pnAlloc)*2 + initSize;
+ pNew = sqliteRealloc(pArray, newSize*szEntry);
if( pNew==0 ){
- return -1;
+ *pIdx = -1;
+ return pArray;
}
- an[1] = newSize;
- *ppArray = pNew;
+ *pnAlloc = newSize;
+ pArray = pNew;
}
- p = *ppArray;
- memset(&p[an[0]*szEntry], 0, szEntry);
- return an[0]++;
+ z = (char*)pArray;
+ memset(&z[*pnEntry * szEntry], 0, szEntry);
+ *pIdx = *pnEntry;
+ ++*pnEntry;
+ return pArray;
}
/*
@@ -2821,7 +2820,14 @@ IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){
if( pList==0 ) return 0;
pList->nAlloc = 0;
}
- i = sqlite3ArrayAllocate((void**)&pList->a, sizeof(pList->a[0]), 5);
+ pList->a = sqlite3ArrayAllocate(
+ pList->a,
+ sizeof(pList->a[0]),
+ 5,
+ &pList->nId,
+ &pList->nAlloc,
+ &i
+ );
if( i<0 ){
sqlite3IdListDelete(pList);
return 0;
@@ -2936,15 +2942,6 @@ void sqlite3SrcListAssignCursors(Parse *pParse, SrcList *pList){
}
/*
-** Add an alias to the last identifier on the given identifier list.
-*/
-void sqlite3SrcListAddAlias(SrcList *pList, Token *pToken){
- if( pList && pList->nSrc>0 ){
- pList->a[pList->nSrc-1].zAlias = sqlite3NameFromToken(pToken);
- }
-}
-
-/*
** Delete an entire SrcList including all its substructure.
*/
void sqlite3SrcListDelete(SrcList *pList){
@@ -2955,7 +2952,7 @@ void sqlite3SrcListDelete(SrcList *pList){
sqliteFree(pItem->zDatabase);
sqliteFree(pItem->zName);
sqliteFree(pItem->zAlias);
- sqlite3DeleteTable(0, pItem->pTab);
+ sqlite3DeleteTable(pItem->pTab);
sqlite3SelectDelete(pItem->pSelect);
sqlite3ExprDelete(pItem->pOn);
sqlite3IdListDelete(pItem->pUsing);
@@ -2964,6 +2961,74 @@ void sqlite3SrcListDelete(SrcList *pList){
}
/*
+** This routine is called by the parser to add a new term to the
+** end of a growing FROM clause. The "p" parameter is the part of
+** the FROM clause that has already been constructed. "p" is NULL
+** if this is the first term of the FROM clause. pTable and pDatabase
+** are the name of the table and database named in the FROM clause term.
+** pDatabase is NULL if the database name qualifier is missing - the
+** usual case. If the term has a alias, then pAlias points to the
+** alias token. If the term is a subquery, then pSubquery is the
+** SELECT statement that the subquery encodes. The pTable and
+** pDatabase parameters are NULL for subqueries. The pOn and pUsing
+** parameters are the content of the ON and USING clauses.
+**
+** Return a new SrcList which encodes is the FROM with the new
+** term added.
+*/
+SrcList *sqlite3SrcListAppendFromTerm(
+ SrcList *p, /* The left part of the FROM clause already seen */
+ Token *pTable, /* Name of the table to add to the FROM clause */
+ Token *pDatabase, /* Name of the database containing pTable */
+ Token *pAlias, /* The right-hand side of the AS subexpression */
+ Select *pSubquery, /* A subquery used in place of a table name */
+ Expr *pOn, /* The ON clause of a join */
+ IdList *pUsing /* The USING clause of a join */
+){
+ struct SrcList_item *pItem;
+ p = sqlite3SrcListAppend(p, pTable, pDatabase);
+ if( p==0 || p->nSrc==0 ){
+ sqlite3ExprDelete(pOn);
+ sqlite3IdListDelete(pUsing);
+ sqlite3SelectDelete(pSubquery);
+ return p;
+ }
+ pItem = &p->a[p->nSrc-1];
+ if( pAlias && pAlias->n ){
+ pItem->zAlias = sqlite3NameFromToken(pAlias);
+ }
+ pItem->pSelect = pSubquery;
+ pItem->pOn = pOn;
+ pItem->pUsing = pUsing;
+ return p;
+}
+
+/*
+** When building up a FROM clause in the parser, the join operator
+** is initially attached to the left operand. But the code generator
+** expects the join operator to be on the right operand. This routine
+** Shifts all join operators from left to right for an entire FROM
+** clause.
+**
+** Example: Suppose the join is like this:
+**
+** A natural cross join B
+**
+** The operator is "natural cross join". The A and B operands are stored
+** in p->a[0] and p->a[1], respectively. The parser initially stores the
+** operator with A. This routine shifts that operator over to B.
+*/
+void sqlite3SrcListShiftJoinType(SrcList *p){
+ if( p && p->a ){
+ int i;
+ for(i=p->nSrc-1; i>0; i--){
+ p->a[i].jointype = p->a[i-1].jointype;
+ }
+ p->a[0].jointype = 0;
+ }
+}
+
+/*
** Begin a transaction
*/
void sqlite3BeginTransaction(Parse *pParse, int type){
diff --git a/ext/pdo_sqlite/sqlite/src/callback.c b/ext/pdo_sqlite/sqlite/src/callback.c
index ff8bfb010..587ac2397 100644
--- a/ext/pdo_sqlite/sqlite/src/callback.c
+++ b/ext/pdo_sqlite/sqlite/src/callback.c
@@ -13,7 +13,7 @@
** This file contains functions used to access the internal hash tables
** of user defined functions and collation sequences.
**
-** $Id: callback.c,v 1.1.2.2.2.1 2006/08/14 16:15:28 iliaa Exp $
+** $Id: callback.c,v 1.1.2.2.2.3 2007/04/18 22:53:45 iliaa Exp $
*/
#include "sqliteInt.h"
@@ -195,6 +195,11 @@ static CollSeq *findCollSeqEntry(
**
** If the entry specified is not found and 'create' is true, then create a
** new entry. Otherwise return NULL.
+**
+** A separate function sqlite3LocateCollSeq() is a wrapper around
+** this routine. sqlite3LocateCollSeq() invokes the collation factory
+** if necessary and generates an error message if the collating sequence
+** cannot be found.
*/
CollSeq *sqlite3FindCollSeq(
sqlite3 *db,
@@ -339,7 +344,7 @@ void sqlite3SchemaFree(void *p){
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
Table *pTab = sqliteHashData(pElem);
- sqlite3DeleteTable(0, pTab);
+ sqlite3DeleteTable(pTab);
}
sqlite3HashClear(&temp1);
pSchema->pSeqTab = 0;
diff --git a/ext/pdo_sqlite/sqlite/src/date.c b/ext/pdo_sqlite/sqlite/src/date.c
index 914690618..a5446e128 100644
--- a/ext/pdo_sqlite/sqlite/src/date.c
+++ b/ext/pdo_sqlite/sqlite/src/date.c
@@ -53,6 +53,9 @@
#include <stdlib.h>
#include <assert.h>
#include <time.h>
+#ifndef PHP_WIN32
+#include "main/php_reentrancy.h"
+#endif
#ifndef SQLITE_OMIT_DATETIME_FUNCS
@@ -234,11 +237,11 @@ static void computeJD(DateTime *p){
X2 = 30.6001*(M+1);
p->rJD = X1 + X2 + D + B - 1524.5;
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->validYMD = 0;
p->validHMS = 0;
p->validTZ = 0;
}
@@ -357,6 +360,7 @@ static void computeYMD(DateTime *p){
static void computeHMS(DateTime *p){
int Z, s;
if( p->validHMS ) return;
+ computeJD(p);
Z = p->rJD + 0.5;
s = (p->rJD + 0.5 - Z)*86400000.0 + 0.5;
p->s = 0.001*s;
@@ -393,7 +397,7 @@ static void clearYMD_HMS_TZ(DateTime *p){
static double localtimeOffset(DateTime *p){
DateTime x, y;
time_t t;
- struct tm *pTm;
+ struct tm *pTm, tmbuf;
x = *p;
computeYMD_HMS(&x);
if( x.Y<1971 || x.Y>=2038 ){
@@ -412,7 +416,7 @@ static double localtimeOffset(DateTime *p){
computeJD(&x);
t = (x.rJD-2440587.5)*86400.0 + 0.5;
sqlite3OsEnterMutex();
- pTm = localtime(&t);
+ pTm = php_localtime_r(&t, &tmbuf);
y.Y = pTm->tm_year + 1900;
y.M = pTm->tm_mon + 1;
y.D = pTm->tm_mday;
@@ -561,7 +565,7 @@ static int parseModifier(const char *zMod, DateTime *p){
case '8':
case '9': {
n = getValue(z, &r);
- if( n<=0 ) break;
+ assert( n>=1 );
if( z[n]==':' ){
/* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
** specified number of hours, minutes, seconds, and fractional seconds
@@ -581,7 +585,7 @@ static int parseModifier(const char *zMod, DateTime *p){
if( z[0]=='-' ) tx.rJD = -tx.rJD;
computeJD(p);
clearYMD_HMS_TZ(p);
- p->rJD += tx.rJD;
+ p->rJD += tx.rJD;
rc = 0;
break;
}
@@ -809,9 +813,9 @@ static void strftimeFunc(
switch( zFmt[i] ){
case 'd': sprintf(&z[j],"%02d",x.D); j+=2; break;
case 'f': {
- int s = x.s;
- int ms = (x.s - s)*1000.0;
- sprintf(&z[j],"%02d.%03d",s,ms);
+ double s = x.s;
+ if( s>59.999 ) s = 59.999;
+ sqlite3_snprintf(7, &z[j],"%06.3f", s);
j += strlen(&z[j]);
break;
}
@@ -824,7 +828,7 @@ static void strftimeFunc(
y.M = 1;
y.D = 1;
computeJD(&y);
- nDay = x.rJD - y.rJD;
+ nDay = x.rJD - y.rJD + 0.5;
if( zFmt[i]=='W' ){
int wd; /* 0=Monday, 1=Tuesday, ... 6=Sunday */
wd = ((int)(x.rJD+0.5)) % 7;
@@ -844,7 +848,7 @@ static void strftimeFunc(
j += strlen(&z[j]);
break;
}
- case 'S': sprintf(&z[j],"%02d",(int)(x.s+0.5)); j+=2; break;
+ case 'S': sprintf(&z[j],"%02d",(int)x.s); j+=2; break;
case 'w': z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break;
case 'Y': sprintf(&z[j],"%04d",x.Y); j+=strlen(&z[j]); break;
case '%': z[j++] = '%'; break;
@@ -944,9 +948,21 @@ static void currentTimeFunc(
}
#endif
- sqlite3OsEnterMutex();
- strftime(zBuf, 20, zFormat, gmtime(&t));
- sqlite3OsLeaveMutex();
+#ifdef HAVE_GMTIME_R
+ {
+ struct tm sNow;
+ gmtime_r(&t, &sNow);
+ strftime(zBuf, 20, zFormat, &sNow);
+ }
+#else
+ {
+ struct tm *pTm;
+ sqlite3OsEnterMutex();
+ pTm = gmtime(&t);
+ strftime(zBuf, 20, zFormat, pTm);
+ sqlite3OsLeaveMutex();
+ }
+#endif
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
}
diff --git a/ext/pdo_sqlite/sqlite/src/delete.c b/ext/pdo_sqlite/sqlite/src/delete.c
index ee1bc930b..64199b02e 100644
--- a/ext/pdo_sqlite/sqlite/src/delete.c
+++ b/ext/pdo_sqlite/sqlite/src/delete.c
@@ -27,7 +27,7 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){
struct SrcList_item *pItem;
for(i=0, pItem=pSrc->a; i<pSrc->nSrc; i++, pItem++){
pTab = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
- sqlite3DeleteTable(pParse->db, pItem->pTab);
+ sqlite3DeleteTable(pItem->pTab);
pItem->pTab = pTab;
if( pTab ){
pTab->nRef++;
@@ -106,7 +106,8 @@ void sqlite3DeleteFrom(
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;
+ int iDb; /* Database number */
+ int memCnt = 0; /* Memory cell used for change counting */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
@@ -204,7 +205,8 @@ void sqlite3DeleteFrom(
** we are counting rows.
*/
if( db->flags & SQLITE_CountRows ){
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
+ memCnt = pParse->nMem++;
+ sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
}
/* Special case: A DELETE without a WHERE clause deletes everything.
@@ -221,7 +223,7 @@ void sqlite3DeleteFrom(
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
}
sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
- addr2 = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
+ addr2 = sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
sqlite3VdbeAddOp(v, OP_Next, iCur, addr2);
sqlite3VdbeResolveLabel(v, endOfLoop);
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
@@ -251,7 +253,7 @@ void sqlite3DeleteFrom(
sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
if( db->flags & SQLITE_CountRows ){
- sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
+ sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
}
/* End the database scan loop.
@@ -354,6 +356,7 @@ void sqlite3DeleteFrom(
** invoke the callback function.
*/
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
+ sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC);
diff --git a/ext/pdo_sqlite/sqlite/src/expr.c b/ext/pdo_sqlite/sqlite/src/expr.c
index e26aba5b3..4ba63d54b 100644
--- a/ext/pdo_sqlite/sqlite/src/expr.c
+++ b/ext/pdo_sqlite/sqlite/src/expr.c
@@ -50,6 +50,24 @@ char sqlite3ExprAffinity(Expr *pExpr){
}
/*
+** Set the collating sequence for expression pExpr to be the collating
+** sequence named by pToken. Return a pointer to the revised expression.
+** The collating sequence is marked as "explicit" using the EP_ExpCollate
+** flag. An explicit collating sequence will override implicit
+** collating sequences.
+*/
+Expr *sqlite3ExprSetColl(Parse *pParse, Expr *pExpr, Token *pName){
+ CollSeq *pColl;
+ if( pExpr==0 ) return 0;
+ pColl = sqlite3LocateCollSeq(pParse, (char*)pName->z, pName->n);
+ if( pColl ){
+ pExpr->pColl = pColl;
+ pExpr->flags |= EP_ExpCollate;
+ }
+ return pExpr;
+}
+
+/*
** Return the default collation sequence for the expression pExpr. If
** there is no default collation type, return 0.
*/
@@ -113,7 +131,7 @@ static char comparisonAffinity(Expr *pExpr){
aff = sqlite3CompareAffinity(pExpr->pSelect->pEList->a[0].pExpr, aff);
}
else if( !aff ){
- aff = SQLITE_AFF_NUMERIC;
+ aff = SQLITE_AFF_NONE;
}
return aff;
}
@@ -158,9 +176,20 @@ static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
** type.
*/
static CollSeq* binaryCompareCollSeq(Parse *pParse, Expr *pLeft, Expr *pRight){
- CollSeq *pColl = sqlite3ExprCollSeq(pParse, pLeft);
- if( !pColl ){
- pColl = sqlite3ExprCollSeq(pParse, pRight);
+ CollSeq *pColl;
+ assert( pLeft );
+ assert( pRight );
+ if( pLeft->flags & EP_ExpCollate ){
+ assert( pLeft->pColl );
+ pColl = pLeft->pColl;
+ }else if( pRight->flags & EP_ExpCollate ){
+ assert( pRight->pColl );
+ pColl = pRight->pColl;
+ }else{
+ pColl = sqlite3ExprCollSeq(pParse, pLeft);
+ if( !pColl ){
+ pColl = sqlite3ExprCollSeq(pParse, pRight);
+ }
}
return pColl;
}
@@ -205,8 +234,18 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
if( pToken ){
assert( pToken->dyn==0 );
pNew->span = pNew->token = *pToken;
- }else if( pLeft && pRight ){
- sqlite3ExprSpan(pNew, &pLeft->span, &pRight->span);
+ }else if( pLeft ){
+ if( pRight ){
+ sqlite3ExprSpan(pNew, &pLeft->span, &pRight->span);
+ if( pRight->flags && EP_ExpCollate ){
+ pNew->flags |= EP_ExpCollate;
+ pNew->pColl = pRight->pColl;
+ }
+ }
+ if( pLeft->flags && EP_ExpCollate ){
+ pNew->flags |= EP_ExpCollate;
+ pNew->pColl = pLeft->pColl;
+ }
}
return pNew;
}
@@ -365,7 +404,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
pExpr->iTable = ++pParse->nVar;
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
- sqliteReallocOrFree((void**)&pParse->apVarExpr,
+ pParse->apVarExpr = sqliteReallocOrFree(pParse->apVarExpr,
pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
}
if( !sqlite3MallocFailed() ){
@@ -890,23 +929,26 @@ static int lookupName(
/* 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 = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
- if( pItem->jointype & JT_NATURAL ){
- /* If this match occurred in the left table of a natural join,
- ** then skip the right table to avoid a duplicate match */
- pItem++;
- i++;
+ if( (pExpr->flags & EP_ExpCollate)==0 ){
+ pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
}
- if( (pUsing = pItem->pUsing)!=0 ){
- /* If this match occurs on a column that is in the USING clause
- ** of a join, skip the search of the right table of the join
- ** to avoid a duplicate match there. */
- int k;
- for(k=0; k<pUsing->nId; k++){
- if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){
- pItem++;
- i++;
- break;
+ if( i<pSrcList->nSrc-1 ){
+ if( pItem[1].jointype & JT_NATURAL ){
+ /* If this match occurred in the left table of a natural join,
+ ** then skip the right table to avoid a duplicate match */
+ pItem++;
+ i++;
+ }else if( (pUsing = pItem[1].pUsing)!=0 ){
+ /* If this match occurs on a column that is in the USING clause
+ ** of a join, skip the search of the right table of the join
+ ** to avoid a duplicate match there. */
+ int k;
+ for(k=0; k<pUsing->nId; k++){
+ if( sqlite3StrICmp(pUsing->a[k].zName, zCol)==0 ){
+ pItem++;
+ i++;
+ break;
+ }
}
}
}
@@ -945,7 +987,9 @@ static int lookupName(
cnt++;
pExpr->iColumn = iCol==pTab->iPKey ? -1 : iCol;
pExpr->affinity = pTab->aCol[iCol].affinity;
- pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
+ if( (pExpr->flags & EP_ExpCollate)==0 ){
+ pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
+ }
pExpr->pTab = pTab;
break;
}
@@ -1045,7 +1089,7 @@ static int lookupName(
n = sizeof(Bitmask)*8-1;
}
assert( pMatch->iCursor==pExpr->iTable );
- pMatch->colUsed |= 1<<n;
+ pMatch->colUsed |= ((Bitmask)1)<<n;
}
lookupname_end:
@@ -1161,6 +1205,7 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
int i;
+ int auth; /* Authorization to use the function */
int nId; /* Number of characters in function name */
const char *zId; /* The function name. */
FuncDef *pDef; /* Information about the function */
@@ -1179,6 +1224,20 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
}else{
is_agg = pDef->xFunc==0;
}
+#ifndef SQLITE_OMIT_AUTHORIZATION
+ if( pDef ){
+ auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
+ if( auth!=SQLITE_OK ){
+ if( auth==SQLITE_DENY ){
+ sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
+ pDef->zName);
+ pNC->nErr++;
+ }
+ pExpr->op = TK_NULL;
+ return 1;
+ }
+ }
+#endif
if( is_agg && !pNC->allowAgg ){
sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
pNC->nErr++;
@@ -1361,7 +1420,9 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
int iParm = pExpr->iTable + (((int)affinity)<<16);
ExprList *pEList;
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
- sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0);
+ if( sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0) ){
+ return;
+ }
pEList = pExpr->pSelect->pEList;
if( pEList && pEList->nExpr>0 ){
keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft,
@@ -1432,7 +1493,9 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
}
sqlite3ExprDelete(pSel->pLimit);
pSel->pLimit = sqlite3Expr(TK_INTEGER, 0, 0, &one);
- sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0);
+ if( sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0) ){
+ return;
+ }
break;
}
}
@@ -1459,6 +1522,31 @@ static void codeInteger(Vdbe *v, const char *z, int n){
}
}
+
+/*
+** Generate code that will extract the iColumn-th column from
+** table pTab and push that column value on the stack. There
+** is an open cursor to pTab in iTable. If iColumn<0 then
+** code is generated that extracts the rowid.
+*/
+void sqlite3ExprCodeGetColumn(Vdbe *v, Table *pTab, int iColumn, int iTable){
+ if( iColumn<0 ){
+ int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid;
+ sqlite3VdbeAddOp(v, op, iTable, 0);
+ }else if( pTab==0 ){
+ sqlite3VdbeAddOp(v, OP_Column, iTable, iColumn);
+ }else{
+ int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;
+ sqlite3VdbeAddOp(v, op, iTable, iColumn);
+ sqlite3ColumnDefault(v, pTab, iColumn);
+#ifndef SQLITE_OMIT_FLOATING_POINT
+ if( pTab->aCol[iColumn].affinity==SQLITE_AFF_REAL ){
+ sqlite3VdbeAddOp(v, OP_RealAffinity, 0, 0);
+ }
+#endif
+ }
+}
+
/*
** Generate code into the current Vdbe to evaluate the given
** expression and leave the result on the top of stack.
@@ -1499,21 +1587,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
/* 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;
- int op = (pTab && IsVirtual(pTab)) ? OP_VColumn : OP_Column;
- sqlite3VdbeAddOp(v, op, 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{
- Table *pTab = pExpr->pTab;
- int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid;
- sqlite3VdbeAddOp(v, op, pExpr->iTable, 0);
+ sqlite3ExprCodeGetColumn(v, pExpr->pTab, pExpr->iColumn, pExpr->iTable);
}
break;
}
@@ -2116,6 +2191,16 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
/*
** 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.
+**
+** Sometimes this routine will return FALSE even if the two expressions
+** really are equivalent. If we cannot prove that the expressions are
+** identical, we return FALSE just to be safe. So if this routine
+** returns false, then you do not really know for certain if the two
+** expressions are the same. But if you get a TRUE return, then you
+** can be sure the expressions are the same. In the places where
+** this routine is used, it does not hurt to get an extra FALSE - that
+** just might result in some slightly slower code. But returning
+** an incorrect TRUE could lead to a malfunction.
*/
int sqlite3ExprCompare(Expr *pA, Expr *pB){
int i;
@@ -2139,7 +2224,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
}
if( pA->pSelect || pB->pSelect ) return 0;
if( pA->iTable!=pB->iTable || pA->iColumn!=pB->iColumn ) return 0;
- if( pA->token.z ){
+ if( pA->op!=TK_COLUMN && pA->token.z ){
if( pB->token.z==0 ) return 0;
if( pB->token.n!=pA->token.n ) return 0;
if( sqlite3StrNICmp((char*)pA->token.z,(char*)pB->token.z,pB->token.n)!=0 ){
@@ -2156,10 +2241,14 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
*/
static int addAggInfoColumn(AggInfo *pInfo){
int i;
- i = sqlite3ArrayAllocate((void**)&pInfo->aCol, sizeof(pInfo->aCol[0]), 3);
- if( i<0 ){
- return -1;
- }
+ pInfo->aCol = sqlite3ArrayAllocate(
+ pInfo->aCol,
+ sizeof(pInfo->aCol[0]),
+ 3,
+ &pInfo->nColumn,
+ &pInfo->nColumnAlloc,
+ &i
+ );
return i;
}
@@ -2169,10 +2258,14 @@ static int addAggInfoColumn(AggInfo *pInfo){
*/
static int addAggInfoFunc(AggInfo *pInfo){
int i;
- i = sqlite3ArrayAllocate((void**)&pInfo->aFunc, sizeof(pInfo->aFunc[0]), 2);
- if( i<0 ){
- return -1;
- }
+ pInfo->aFunc = sqlite3ArrayAllocate(
+ pInfo->aFunc,
+ sizeof(pInfo->aFunc[0]),
+ 3,
+ &pInfo->nFunc,
+ &pInfo->nFuncAlloc,
+ &i
+ );
return i;
}
@@ -2192,6 +2285,7 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
switch( pExpr->op ){
+ case TK_AGG_COLUMN:
case TK_COLUMN: {
/* Check to see if the column is in one of the tables in the FROM
** clause of the aggregate query */
@@ -2206,15 +2300,17 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
** Make an entry for the column in pAggInfo->aCol[] if there
** is not an entry there already.
*/
+ int k;
pCol = pAggInfo->aCol;
- for(i=0; i<pAggInfo->nColumn; i++, pCol++){
+ for(k=0; k<pAggInfo->nColumn; k++, pCol++){
if( pCol->iTable==pExpr->iTable &&
pCol->iColumn==pExpr->iColumn ){
break;
}
}
- if( i>=pAggInfo->nColumn && (i = addAggInfoColumn(pAggInfo))>=0 ){
- pCol = &pAggInfo->aCol[i];
+ if( k>=pAggInfo->nColumn && (k = addAggInfoColumn(pAggInfo))>=0 ){
+ pCol = &pAggInfo->aCol[k];
+ pCol->pTab = pExpr->pTab;
pCol->iTable = pExpr->iTable;
pCol->iColumn = pExpr->iColumn;
pCol->iMem = pParse->nMem++;
@@ -2245,7 +2341,7 @@ static int analyzeAggregate(void *pArg, Expr *pExpr){
*/
pExpr->pAggInfo = pAggInfo;
pExpr->op = TK_AGG_COLUMN;
- pExpr->iAgg = i;
+ pExpr->iAgg = k;
break;
} /* endif pExpr->iTable==pItem->iCursor */
} /* end loop over pSrcList */
diff --git a/ext/pdo_sqlite/sqlite/src/func.c b/ext/pdo_sqlite/sqlite/src/func.c
index bf422f92c..5b3d0e037 100644
--- a/ext/pdo_sqlite/sqlite/src/func.c
+++ b/ext/pdo_sqlite/sqlite/src/func.c
@@ -272,6 +272,25 @@ static void randomFunc(
}
/*
+** Implementation of randomblob(N). Return a random blob
+** that is N bytes long.
+*/
+static void randomBlob(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int n;
+ unsigned char *p;
+ assert( argc==1 );
+ n = sqlite3_value_int(argv[0]);
+ if( n<1 ) n = 1;
+ p = sqlite3_malloc(n);
+ sqlite3Randomness(n, p);
+ sqlite3_result_blob(context, (char*)p, n, sqlite3_free);
+}
+
+/*
** Implementation of the last_insert_rowid() SQL function. The return
** value is the same as the sqlite3_last_insert_rowid() API function.
*/
@@ -547,19 +566,12 @@ static void versionFunc(
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
}
-/*
-** The MATCH() function is unimplemented. If anybody tries to use it,
-** return an error.
-*/
-static void matchStub(
- sqlite3_context *context,
- int argc,
- sqlite3_value **argv
-){
- static const char zErr[] = "MATCH is not implemented";
- sqlite3_result_error(context, zErr, sizeof(zErr)-1);
-}
-
+/* Array for converting from half-bytes (nybbles) into ASCII hex
+** digits. */
+static const char hexdigits[] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
/*
** EXPERIMENTAL - This is not an official function. The interface may
@@ -585,10 +597,6 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
break;
}
case SQLITE_BLOB: {
- static const char hexdigits[] = {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
char *zText = 0;
int nBlob = sqlite3_value_bytes(argv[0]);
char const *zBlob = sqlite3_value_blob(argv[0]);
@@ -634,11 +642,149 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
}
}
+/*
+** The hex() function. Interpret the argument as a blob. Return
+** a hexadecimal rendering as text.
+*/
+static void hexFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int i, n;
+ const unsigned char *pBlob;
+ char *zHex, *z;
+ assert( argc==1 );
+ n = sqlite3_value_bytes(argv[0]);
+ pBlob = sqlite3_value_blob(argv[0]);
+ z = zHex = sqlite3_malloc(n*2 + 1);
+ if( zHex==0 ) return;
+ for(i=0; i<n; i++, pBlob++){
+ unsigned char c = *pBlob;
+ *(z++) = hexdigits[(c>>4)&0xf];
+ *(z++) = hexdigits[c&0xf];
+ }
+ *z = 0;
+ sqlite3_result_text(context, zHex, n*2, sqlite3_free);
+}
+
+/*
+** The replace() function. Three arguments are all strings: call
+** them A, B, and C. The result is also a string which is derived
+** from A by replacing every occurance of B with C. The match
+** must be exact. Collating sequences are not used.
+*/
+static void replaceFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *zStr; /* The input string A */
+ const unsigned char *zPattern; /* The pattern string B */
+ const unsigned char *zRep; /* The replacement string C */
+ unsigned char *zOut; /* The output */
+ int nStr; /* Size of zStr */
+ int nPattern; /* Size of zPattern */
+ int nRep; /* Size of zRep */
+ int nOut; /* Maximum size of zOut */
+ int loopLimit; /* Last zStr[] that might match zPattern[] */
+ int i, j; /* Loop counters */
+
+ assert( argc==3 );
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ||
+ sqlite3_value_type(argv[1])==SQLITE_NULL ||
+ sqlite3_value_type(argv[2])==SQLITE_NULL ){
+ return;
+ }
+ zStr = sqlite3_value_text(argv[0]);
+ nStr = sqlite3_value_bytes(argv[0]);
+ zPattern = sqlite3_value_text(argv[1]);
+ nPattern = sqlite3_value_bytes(argv[1]);
+ zRep = sqlite3_value_text(argv[2]);
+ nRep = sqlite3_value_bytes(argv[2]);
+ if( nPattern>=nRep ){
+ nOut = nStr;
+ }else{
+ nOut = (nStr/nPattern + 1)*nRep;
+ }
+ zOut = sqlite3_malloc(nOut+1);
+ if( zOut==0 ) return;
+ loopLimit = nStr - nPattern;
+ for(i=j=0; i<=loopLimit; i++){
+ if( zStr[i]!=zPattern[0] || memcmp(&zStr[i], zPattern, nPattern) ){
+ zOut[j++] = zStr[i];
+ }else{
+ memcpy(&zOut[j], zRep, nRep);
+ j += nRep;
+ i += nPattern-1;
+ }
+ }
+ memcpy(&zOut[j], &zStr[i], nStr-i);
+ j += nStr - i;
+ assert( j<=nOut );
+ zOut[j] = 0;
+ sqlite3_result_text(context, (char*)zOut, j, sqlite3_free);
+}
+
+/*
+** Implementation of the TRIM(), LTRIM(), and RTRIM() functions.
+** The userdata is 0x1 for left trim, 0x2 for right trim, 0x3 for both.
+*/
+static void trimFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ const unsigned char *zIn; /* Input string */
+ const unsigned char *zCharSet; /* Set of characters to trim */
+ int nIn; /* Number of bytes in input */
+ int flags;
+ int i;
+ unsigned char cFirst, cNext;
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
+ return;
+ }
+ zIn = sqlite3_value_text(argv[0]);
+ nIn = sqlite3_value_bytes(argv[0]);
+ if( argc==1 ){
+ static const unsigned char zSpace[] = " ";
+ zCharSet = zSpace;
+ }else if( sqlite3_value_type(argv[1])==SQLITE_NULL ){
+ return;
+ }else{
+ zCharSet = sqlite3_value_text(argv[1]);
+ }
+ cFirst = zCharSet[0];
+ if( cFirst ){
+ flags = (int)sqlite3_user_data(context);
+ if( flags & 1 ){
+ for(; nIn>0; nIn--, zIn++){
+ if( cFirst==zIn[0] ) continue;
+ for(i=1; zCharSet[i] && zCharSet[i]!=zIn[0]; i++){}
+ if( zCharSet[i]==0 ) break;
+ }
+ }
+ if( flags & 2 ){
+ for(; nIn>0; nIn--){
+ cNext = zIn[nIn-1];
+ if( cFirst==cNext ) continue;
+ for(i=1; zCharSet[i] && zCharSet[i]!=cNext; i++){}
+ if( zCharSet[i]==0 ) break;
+ }
+ }
+ }
+ sqlite3_result_text(context, (char*)zIn, nIn, SQLITE_TRANSIENT);
+}
+
#ifdef SQLITE_SOUNDEX
/*
** Compute the soundex encoding of a word.
*/
-static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
+static void soundexFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
char zResult[8];
const u8 *zIn;
int i, j;
@@ -654,14 +800,20 @@ static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv
};
assert( argc==1 );
zIn = (u8*)sqlite3_value_text(argv[0]);
- if( zIn==0 ) zIn = "";
+ if( zIn==0 ) zIn = (u8*)"";
for(i=0; zIn[i] && !isalpha(zIn[i]); i++){}
if( zIn[i] ){
+ u8 prevcode = iCode[zIn[i]&0x7f];
zResult[0] = toupper(zIn[i]);
for(j=1; j<4 && zIn[i]; i++){
int code = iCode[zIn[i]&0x7f];
if( code>0 ){
- zResult[j++] = code + '0';
+ if( code!=prevcode ){
+ prevcode = code;
+ zResult[j++] = code + '0';
+ }
+ }else{
+ prevcode = 0;
}
}
while( j<4 ){
@@ -975,7 +1127,7 @@ static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv)
** Therefore the next statement sets variable 'max' to 1 for the max()
** aggregate, or 0 for min().
*/
- max = ((sqlite3_user_data(context)==(void *)-1)?1:0);
+ max = sqlite3_user_data(context)!=0;
cmp = sqlite3MemCompare(pBest, pArg, pColl);
if( (max && cmp<0) || (!max && cmp>0) ){
sqlite3VdbeMemCopy(pBest, pArg);
@@ -1005,15 +1157,15 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
static const struct {
char *zName;
signed char nArg;
- u8 argType; /* 0: none. 1: db 2: (-1) */
+ u8 argType; /* ff: db 1: 0, 2: 1, 3: 2,... N: N-1. */
u8 eTextRep; /* 1: UTF-16. 0: UTF-8 */
u8 needCollSeq;
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
} aFuncs[] = {
{ "min", -1, 0, SQLITE_UTF8, 1, minmaxFunc },
{ "min", 0, 0, SQLITE_UTF8, 1, 0 },
- { "max", -1, 2, SQLITE_UTF8, 1, minmaxFunc },
- { "max", 0, 2, SQLITE_UTF8, 1, 0 },
+ { "max", -1, 1, SQLITE_UTF8, 1, minmaxFunc },
+ { "max", 0, 1, SQLITE_UTF8, 1, 0 },
{ "typeof", 1, 0, SQLITE_UTF8, 0, typeofFunc },
{ "length", 1, 0, SQLITE_UTF8, 0, lengthFunc },
{ "substr", 3, 0, SQLITE_UTF8, 0, substrFunc },
@@ -1028,28 +1180,36 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
{ "coalesce", -1, 0, SQLITE_UTF8, 0, ifnullFunc },
{ "coalesce", 0, 0, SQLITE_UTF8, 0, 0 },
{ "coalesce", 1, 0, SQLITE_UTF8, 0, 0 },
+ { "hex", 1, 0, SQLITE_UTF8, 0, hexFunc },
{ "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
{ "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
+ { "randomblob", 1, 0, SQLITE_UTF8, 0, randomBlob },
{ "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
{ "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
- { "last_insert_rowid", 0, 1, SQLITE_UTF8, 0, last_insert_rowid },
- { "changes", 0, 1, SQLITE_UTF8, 0, changes },
- { "total_changes", 0, 1, SQLITE_UTF8, 0, total_changes },
- { "match", 2, 0, SQLITE_UTF8, 0, matchStub },
+ { "last_insert_rowid", 0, 0xff, SQLITE_UTF8, 0, last_insert_rowid },
+ { "changes", 0, 0xff, SQLITE_UTF8, 0, changes },
+ { "total_changes", 0, 0xff, SQLITE_UTF8, 0, total_changes },
+ { "replace", 3, 0, SQLITE_UTF8, 0, replaceFunc },
+ { "ltrim", 1, 1, SQLITE_UTF8, 0, trimFunc },
+ { "ltrim", 2, 1, SQLITE_UTF8, 0, trimFunc },
+ { "rtrim", 1, 2, SQLITE_UTF8, 0, trimFunc },
+ { "rtrim", 2, 2, SQLITE_UTF8, 0, trimFunc },
+ { "trim", 1, 3, SQLITE_UTF8, 0, trimFunc },
+ { "trim", 2, 3, SQLITE_UTF8, 0, trimFunc },
#ifdef SQLITE_SOUNDEX
- { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
+ { "soundex", 1, 0, SQLITE_UTF8, 0, soundexFunc},
#endif
#ifndef SQLITE_OMIT_LOAD_EXTENSION
- { "load_extension", 1, 1, SQLITE_UTF8, 0, loadExt },
- { "load_extension", 2, 1, SQLITE_UTF8, 0, loadExt },
+ { "load_extension", 1, 0xff, SQLITE_UTF8, 0, loadExt },
+ { "load_extension", 2, 0xff, SQLITE_UTF8, 0, loadExt },
#endif
#ifdef SQLITE_TEST
- { "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
- { "test_destructor", 1, 1, SQLITE_UTF8, 0, test_destructor},
- { "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count},
- { "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata},
- { "test_error", 1, 0, SQLITE_UTF8, 0, test_error},
+ { "randstr", 2, 0, SQLITE_UTF8, 0, randStr },
+ { "test_destructor", 1, 0xff, SQLITE_UTF8, 0, test_destructor},
+ { "test_destructor_count", 0, 0, SQLITE_UTF8, 0, test_destructor_count},
+ { "test_auxdata", -1, 0, SQLITE_UTF8, 0, test_auxdata},
+ { "test_error", 1, 0, SQLITE_UTF8, 0, test_error},
#endif
};
static const struct {
@@ -1061,7 +1221,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
void (*xFinalize)(sqlite3_context*);
} aAggs[] = {
{ "min", 1, 0, 1, minmaxStep, minMaxFinalize },
- { "max", 1, 2, 1, minmaxStep, minMaxFinalize },
+ { "max", 1, 1, 1, minmaxStep, minMaxFinalize },
{ "sum", 1, 0, 0, sumStep, sumFinalize },
{ "total", 1, 0, 0, sumStep, totalFinalize },
{ "avg", 1, 0, 0, sumStep, avgFinalize },
@@ -1071,10 +1231,12 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
- void *pArg = 0;
- switch( aFuncs[i].argType ){
- case 1: pArg = db; break;
- case 2: pArg = (void *)(-1); break;
+ void *pArg;
+ u8 argType = aFuncs[i].argType;
+ if( argType==0xff ){
+ pArg = db;
+ }else{
+ pArg = (void*)(int)argType;
}
sqlite3CreateFunc(db, aFuncs[i].zName, aFuncs[i].nArg,
aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0);
@@ -1093,11 +1255,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
sqlite3AttachFunctions(db);
#endif
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
- void *pArg = 0;
- switch( aAggs[i].argType ){
- case 1: pArg = db; break;
- case 2: pArg = (void *)(-1); break;
- }
+ void *pArg = (void*)(int)aAggs[i].argType;
sqlite3CreateFunc(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
if( aAggs[i].needCollSeq ){
@@ -1109,6 +1267,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
}
}
sqlite3RegisterDateTimeFunctions(db);
+ sqlite3_overload_function(db, "MATCH", 2);
#ifdef SQLITE_SSE
(void)sqlite3SseFunctions(db);
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/hash.c b/ext/pdo_sqlite/sqlite/src/hash.c
index 1c32c1b7c..8f34caba4 100644
--- a/ext/pdo_sqlite/sqlite/src/hash.c
+++ b/ext/pdo_sqlite/sqlite/src/hash.c
@@ -291,7 +291,7 @@ static void removeElementGivenHash(
if( pEntry->count<=0 ){
pEntry->chain = 0;
}
- if( pH->copyKey && elem->pKey ){
+ if( pH->copyKey ){
pH->xFree(elem->pKey);
}
pH->xFree( elem );
@@ -378,6 +378,9 @@ void *sqlite3HashInsert(Hash *pH, const void *pKey, int nKey, void *data){
rehash(pH,8);
if( pH->htsize==0 ){
pH->count = 0;
+ if( pH->copyKey ){
+ pH->xFree(new_elem->pKey);
+ }
pH->xFree(new_elem);
return data;
}
diff --git a/ext/pdo_sqlite/sqlite/src/insert.c b/ext/pdo_sqlite/sqlite/src/insert.c
index d4cf74a3d..df9f609a2 100644
--- a/ext/pdo_sqlite/sqlite/src/insert.c
+++ b/ext/pdo_sqlite/sqlite/src/insert.c
@@ -118,6 +118,117 @@ static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
return 0;
}
+#ifndef SQLITE_OMIT_AUTOINCREMENT
+/*
+** Write out code to initialize the autoincrement logic. This code
+** looks up the current autoincrement value in the sqlite_sequence
+** table and stores that value in a memory cell. Code generated by
+** autoIncStep() will keep that memory cell holding the largest
+** rowid value. Code generated by autoIncEnd() will write the new
+** largest value of the counter back into the sqlite_sequence table.
+**
+** This routine returns the index of the mem[] cell that contains
+** the maximum rowid counter.
+**
+** Two memory cells are allocated. The next memory cell after the
+** one returned holds the rowid in sqlite_sequence where we will
+** write back the revised maximum rowid.
+*/
+static int autoIncBegin(
+ Parse *pParse, /* Parsing context */
+ int iDb, /* Index of the database holding pTab */
+ Table *pTab /* The table we are writing to */
+){
+ int memId = 0;
+ if( pTab->autoInc ){
+ Vdbe *v = pParse->pVdbe;
+ Db *pDb = &pParse->db->aDb[iDb];
+ int iCur = pParse->nTab;
+ int addr;
+ assert( v );
+ addr = sqlite3VdbeCurrentAddr(v);
+ memId = pParse->nMem+1;
+ pParse->nMem += 2;
+ sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
+ sqlite3VdbeAddOp(v, OP_Rewind, iCur, addr+13);
+ sqlite3VdbeAddOp(v, OP_Column, iCur, 0);
+ sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
+ sqlite3VdbeAddOp(v, OP_Ne, 0x100, addr+12);
+ sqlite3VdbeAddOp(v, OP_Rowid, iCur, 0);
+ sqlite3VdbeAddOp(v, OP_MemStore, memId-1, 1);
+ sqlite3VdbeAddOp(v, OP_Column, iCur, 1);
+ sqlite3VdbeAddOp(v, OP_MemStore, memId, 1);
+ sqlite3VdbeAddOp(v, OP_Goto, 0, addr+13);
+ sqlite3VdbeAddOp(v, OP_Next, iCur, addr+4);
+ sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
+ }
+ return memId;
+}
+
+/*
+** Update the maximum rowid for an autoincrement calculation.
+**
+** This routine should be called when the top of the stack holds a
+** new rowid that is about to be inserted. If that new rowid is
+** larger than the maximum rowid in the memId memory cell, then the
+** memory cell is updated. The stack is unchanged.
+*/
+static void autoIncStep(Parse *pParse, int memId){
+ if( memId>0 ){
+ sqlite3VdbeAddOp(pParse->pVdbe, OP_MemMax, memId, 0);
+ }
+}
+
+/*
+** After doing one or more inserts, the maximum rowid is stored
+** in mem[memId]. Generate code to write this value back into the
+** the sqlite_sequence table.
+*/
+static void autoIncEnd(
+ Parse *pParse, /* The parsing context */
+ int iDb, /* Index of the database holding pTab */
+ Table *pTab, /* Table we are inserting into */
+ int memId /* Memory cell holding the maximum rowid */
+){
+ if( pTab->autoInc ){
+ int iCur = pParse->nTab;
+ Vdbe *v = pParse->pVdbe;
+ Db *pDb = &pParse->db->aDb[iDb];
+ int addr;
+ assert( v );
+ addr = sqlite3VdbeCurrentAddr(v);
+ sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
+ sqlite3VdbeAddOp(v, OP_MemLoad, memId-1, 0);
+ sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+7);
+ sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+ sqlite3VdbeAddOp(v, OP_NewRowid, iCur, 0);
+ sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
+ sqlite3VdbeAddOp(v, OP_MemLoad, memId, 0);
+ sqlite3VdbeAddOp(v, OP_MakeRecord, 2, 0);
+ sqlite3VdbeAddOp(v, OP_Insert, iCur, OPFLAG_APPEND);
+ sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
+ }
+}
+#else
+/*
+** If SQLITE_OMIT_AUTOINCREMENT is defined, then the three routines
+** above are all no-ops
+*/
+# define autoIncBegin(A,B,C) (0)
+# define autoIncStep(A,B)
+# define autoIncEnd(A,B,C,D)
+#endif /* SQLITE_OMIT_AUTOINCREMENT */
+
+
+/* Forward declaration */
+static int xferOptimization(
+ Parse *pParse, /* Parser context */
+ Table *pDest, /* The table we are inserting into */
+ Select *pSelect, /* A SELECT statement to use as the data source */
+ int onError, /* How to handle constraint errors */
+ int iDbDest /* The database of pDest */
+);
+
/*
** This routine is call to handle SQL of the following forms:
**
@@ -133,7 +244,7 @@ static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
** NULL and pSelect is a pointer to the select statement used to generate
** data for the insert.
**
-** The code generated follows one of three templates. For a simple
+** The code generated follows one of four templates. For a simple
** select with data coming from a VALUES clause, the code executes
** once straight down through. The template looks like this:
**
@@ -142,16 +253,37 @@ static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
** write the resulting record into <table>
** cleanup
**
-** If the statement is of the form
+** The three remaining templates assume the statement is of the form
**
** INSERT INTO <table> SELECT ...
**
-** And the SELECT clause does not read from <table> at any time, then
-** the generated code follows this template:
+** If the SELECT clause is of the restricted form "SELECT * FROM <table2>" -
+** in other words if the SELECT pulls all columns from a single table
+** and there is no WHERE or LIMIT or GROUP BY or ORDER BY clauses, and
+** if <table2> and <table1> are distinct tables but have identical
+** schemas, including all the same indices, then a special optimization
+** is invoked that copies raw records from <table2> over to <table1>.
+** See the xferOptimization() function for the implementation of this
+** template. This is the second template.
+**
+** open a write cursor to <table>
+** open read cursor on <table2>
+** transfer all records in <table2> over to <table>
+** close cursors
+** foreach index on <table>
+** open a write cursor on the <table> index
+** open a read cursor on the corresponding <table2> index
+** transfer all records from the read to the write cursors
+** close cursors
+** end foreach
+**
+** The third template is for when the second template does not apply
+** and the SELECT clause does not read from <table> at any time.
+** The generated code follows this template:
**
** goto B
** A: setup for the SELECT
-** loop over the tables in the SELECT
+** loop over the rows in the SELECT
** gosub C
** end loop
** cleanup after the SELECT
@@ -162,7 +294,7 @@ static int selectReadsTable(Select *p, Schema *pSchema, int iTab){
** return
** D: cleanup
**
-** The third template is used if the insert statement takes its
+** The fourth template is used if the insert statement takes its
** values from a SELECT but the data is being inserted into a table
** that is also read as part of the SELECT. In the third form,
** we have to use a intermediate table to store the results of
@@ -214,6 +346,7 @@ void sqlite3Insert(
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 appendFlag = 0; /* True if the insert is likely to be an append */
int iDb;
#ifndef SQLITE_OMIT_TRIGGER
@@ -221,10 +354,6 @@ void sqlite3Insert(
int triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
#endif
-#ifndef SQLITE_OMIT_AUTOINCREMENT
- int counterRowid = 0; /* Memory cell holding rowid of autoinc counter */
-#endif
-
if( pParse->nErr || sqlite3MallocFailed() ){
goto insert_cleanup;
}
@@ -291,31 +420,27 @@ void sqlite3Insert(
newIdx = pParse->nTab++;
}
-#ifndef SQLITE_OMIT_AUTOINCREMENT
+#ifndef SQLITE_OMIT_XFER_OPT
+ /* If the statement is of the form
+ **
+ ** INSERT INTO <table1> SELECT * FROM <table2>;
+ **
+ ** Then special optimizations can be applied that make the transfer
+ ** very fast and which reduce fragmentation of indices.
+ */
+ if( pColumn==0 && xferOptimization(pParse, pTab, pSelect, onError, iDb) ){
+ assert( !triggers_exist );
+ assert( pList==0 );
+ goto insert_cleanup;
+ }
+#endif /* SQLITE_OMIT_XFER_OPT */
+
/* If this is an AUTOINCREMENT table, look up the sequence number in the
** sqlite_sequence table and store it in memory cell counterMem. Also
** remember the rowid of the sqlite_sequence table entry in memory cell
** counterRowid.
*/
- if( pTab->autoInc ){
- int iCur = pParse->nTab;
- int addr = sqlite3VdbeCurrentAddr(v);
- counterRowid = pParse->nMem++;
- counterMem = pParse->nMem++;
- sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead);
- sqlite3VdbeAddOp(v, OP_Rewind, iCur, addr+13);
- sqlite3VdbeAddOp(v, OP_Column, iCur, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
- sqlite3VdbeAddOp(v, OP_Ne, 0x100, addr+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, addr+13);
- sqlite3VdbeAddOp(v, OP_Next, iCur, addr+4);
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
-#endif /* SQLITE_OMIT_AUTOINCREMENT */
+ counterMem = autoIncBegin(pParse, iDb, pTab);
/* Figure out how many columns of data are supplied. If the data
** is coming from a SELECT statement, then this step also generates
@@ -365,7 +490,7 @@ void sqlite3Insert(
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
sqlite3VdbeAddOp(v, OP_NewRowid, srcTab, 0);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- sqlite3VdbeAddOp(v, OP_Insert, srcTab, 0);
+ sqlite3VdbeAddOp(v, OP_Insert, srcTab, OPFLAG_APPEND);
sqlite3VdbeAddOp(v, OP_Return, 0, 0);
/* The following code runs first because the GOTO at the very top
@@ -387,11 +512,9 @@ void sqlite3Insert(
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
- assert( pList!=0 );
srcTab = -1;
useTempTable = 0;
- assert( pList );
- nColumn = pList->nExpr;
+ nColumn = pList ? pList->nExpr : 0;
for(i=0; i<nColumn; i++){
if( sqlite3ExprResolveNames(&sNC, pList->a[i].pExpr) ){
goto insert_cleanup;
@@ -402,7 +525,7 @@ void sqlite3Insert(
/* Make sure the number of columns in the source data matches the number
** of columns to be inserted into the table.
*/
- if( pColumn==0 && nColumn!=pTab->nCol ){
+ if( pColumn==0 && nColumn && nColumn!=pTab->nCol ){
sqlite3ErrorMsg(pParse,
"table %S has %d columns but %d values were supplied",
pTabList, 0, pTab->nCol, nColumn);
@@ -455,7 +578,7 @@ void sqlite3Insert(
** key, the set the keyColumn variable to the primary key column index
** in the original table definition.
*/
- if( pColumn==0 ){
+ if( pColumn==0 && nColumn>0 ){
keyColumn = pTab->iPKey;
}
@@ -579,25 +702,32 @@ void sqlite3Insert(
}else if( pSelect ){
sqlite3VdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
}else{
+ VdbeOp *pOp;
sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr);
+ pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1);
+ if( pOp && pOp->opcode==OP_Null ){
+ appendFlag = 1;
+ pOp->opcode = OP_NewRowid;
+ pOp->p1 = base;
+ pOp->p2 = counterMem;
+ }
}
/* If the PRIMARY KEY expression is NULL, then use OP_NewRowid
** to generate a unique primary key value.
*/
- sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
+ if( !appendFlag ){
+ sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3);
+ sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
+ sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
+ sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0);
+ }
}else if( IsVirtual(pTab) ){
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
}else{
sqlite3VdbeAddOp(v, OP_NewRowid, base, counterMem);
+ appendFlag = 1;
}
-#ifndef SQLITE_OMIT_AUTOINCREMENT
- if( pTab->autoInc ){
- sqlite3VdbeAddOp(v, OP_MemMax, counterMem, 0);
- }
-#endif /* SQLITE_OMIT_AUTOINCREMENT */
+ autoIncStep(pParse, counterMem);
/* Push onto the stack, data for all columns of the new entry, beginning
** with the first column.
@@ -618,12 +748,12 @@ void sqlite3Insert(
if( pColumn->a[j].idx==i ) break;
}
}
- if( pColumn && j>=pColumn->nId ){
+ if( nColumn==0 || (pColumn && j>=pColumn->nId) ){
sqlite3ExprCode(pParse, pTab->aCol[i].pDflt);
}else if( useTempTable ){
sqlite3VdbeAddOp(v, OP_Column, srcTab, j);
}else if( pSelect ){
- sqlite3VdbeAddOp(v, OP_Dup, i+nColumn-j, 1);
+ sqlite3VdbeAddOp(v, OP_Dup, i+nColumn-j+IsVirtual(pTab), 1);
}else{
sqlite3ExprCode(pParse, pList->a[j].pExpr);
}
@@ -643,7 +773,8 @@ void sqlite3Insert(
sqlite3GenerateConstraintChecks(pParse, pTab, base, 0, keyColumn>=0,
0, onError, endOfLoop);
sqlite3CompleteInsertion(pParse, pTab, base, 0,0,0,
- (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1);
+ (triggers_exist & TRIGGER_AFTER)!=0 ? newIdx : -1,
+ appendFlag);
}
}
@@ -690,26 +821,11 @@ void sqlite3Insert(
}
}
-#ifndef SQLITE_OMIT_AUTOINCREMENT
/* Update the sqlite_sequence table by storing the content of the
** counter value in memory counterMem back into the sqlite_sequence
** table.
*/
- if( pTab->autoInc ){
- int iCur = pParse->nTab;
- int addr = sqlite3VdbeCurrentAddr(v);
- sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite);
- sqlite3VdbeAddOp(v, OP_MemLoad, counterRowid, 0);
- sqlite3VdbeAddOp(v, OP_NotNull, -1, addr+7);
- sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
- sqlite3VdbeAddOp(v, OP_NewRowid, iCur, 0);
- sqlite3VdbeOp3(v, OP_String8, 0, 0, pTab->zName, 0);
- sqlite3VdbeAddOp(v, OP_MemLoad, counterMem, 0);
- sqlite3VdbeAddOp(v, OP_MakeRecord, 2, 0);
- sqlite3VdbeAddOp(v, OP_Insert, iCur, 0);
- sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
- }
-#endif
+ autoIncEnd(pParse, iDb, pTab, counterMem);
/*
** Return the number of rows inserted. If this routine is
@@ -1069,7 +1185,8 @@ void sqlite3CompleteInsertion(
char *aIdxUsed, /* Which indices are used. NULL means all are used */
int rowidChng, /* True if the record number will change */
int isUpdate, /* True for UPDATE, False for INSERT */
- int newIdx /* Index of NEW table for triggers. -1 if none */
+ int newIdx, /* Index of NEW table for triggers. -1 if none */
+ int appendBias /* True if this is likely to be an append */
){
int i;
Vdbe *v;
@@ -1100,6 +1217,9 @@ void sqlite3CompleteInsertion(
pik_flags = OPFLAG_NCHANGE;
pik_flags |= (isUpdate?OPFLAG_ISUPDATE:OPFLAG_LASTROWID);
}
+ if( appendBias ){
+ pik_flags |= OPFLAG_APPEND;
+ }
sqlite3VdbeAddOp(v, OP_Insert, base, pik_flags);
if( !pParse->nested ){
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
@@ -1142,3 +1262,323 @@ void sqlite3OpenTableAndIndices(
pParse->nTab = base+i;
}
}
+
+
+#ifdef SQLITE_TEST
+/*
+** The following global variable is incremented whenever the
+** transfer optimization is used. This is used for testing
+** purposes only - to make sure the transfer optimization really
+** is happening when it is suppose to.
+*/
+int sqlite3_xferopt_count;
+#endif /* SQLITE_TEST */
+
+
+#ifndef SQLITE_OMIT_XFER_OPT
+/*
+** Check to collation names to see if they are compatible.
+*/
+static int xferCompatibleCollation(const char *z1, const char *z2){
+ if( z1==0 ){
+ return z2==0;
+ }
+ if( z2==0 ){
+ return 0;
+ }
+ return sqlite3StrICmp(z1, z2)==0;
+}
+
+
+/*
+** Check to see if index pSrc is compatible as a source of data
+** for index pDest in an insert transfer optimization. The rules
+** for a compatible index:
+**
+** * The index is over the same set of columns
+** * The same DESC and ASC markings occurs on all columns
+** * The same onError processing (OE_Abort, OE_Ignore, etc)
+** * The same collating sequence on each column
+*/
+static int xferCompatibleIndex(Index *pDest, Index *pSrc){
+ int i;
+ assert( pDest && pSrc );
+ assert( pDest->pTable!=pSrc->pTable );
+ if( pDest->nColumn!=pSrc->nColumn ){
+ return 0; /* Different number of columns */
+ }
+ if( pDest->onError!=pSrc->onError ){
+ return 0; /* Different conflict resolution strategies */
+ }
+ for(i=0; i<pSrc->nColumn; i++){
+ if( pSrc->aiColumn[i]!=pDest->aiColumn[i] ){
+ return 0; /* Different columns indexed */
+ }
+ if( pSrc->aSortOrder[i]!=pDest->aSortOrder[i] ){
+ return 0; /* Different sort orders */
+ }
+ if( pSrc->azColl[i]!=pDest->azColl[i] ){
+ return 0; /* Different sort orders */
+ }
+ }
+
+ /* If no test above fails then the indices must be compatible */
+ return 1;
+}
+
+/*
+** Attempt the transfer optimization on INSERTs of the form
+**
+** INSERT INTO tab1 SELECT * FROM tab2;
+**
+** This optimization is only attempted if
+**
+** (1) tab1 and tab2 have identical schemas including all the
+** same indices and constraints
+**
+** (2) tab1 and tab2 are different tables
+**
+** (3) There must be no triggers on tab1
+**
+** (4) The result set of the SELECT statement is "*"
+**
+** (5) The SELECT statement has no WHERE, HAVING, ORDER BY, GROUP BY,
+** or LIMIT clause.
+**
+** (6) The SELECT statement is a simple (not a compound) select that
+** contains only tab2 in its FROM clause
+**
+** This method for implementing the INSERT transfers raw records from
+** tab2 over to tab1. The columns are not decoded. Raw records from
+** the indices of tab2 are transfered to tab1 as well. In so doing,
+** the resulting tab1 has much less fragmentation.
+**
+** This routine returns TRUE if the optimization is attempted. If any
+** of the conditions above fail so that the optimization should not
+** be attempted, then this routine returns FALSE.
+*/
+static int xferOptimization(
+ Parse *pParse, /* Parser context */
+ Table *pDest, /* The table we are inserting into */
+ Select *pSelect, /* A SELECT statement to use as the data source */
+ int onError, /* How to handle constraint errors */
+ int iDbDest /* The database of pDest */
+){
+ ExprList *pEList; /* The result set of the SELECT */
+ Table *pSrc; /* The table in the FROM clause of SELECT */
+ Index *pSrcIdx, *pDestIdx; /* Source and destination indices */
+ struct SrcList_item *pItem; /* An element of pSelect->pSrc */
+ int i; /* Loop counter */
+ int iDbSrc; /* The database of pSrc */
+ int iSrc, iDest; /* Cursors from source and destination */
+ int addr1, addr2; /* Loop addresses */
+ int emptyDestTest; /* Address of test for empty pDest */
+ int emptySrcTest; /* Address of test for empty pSrc */
+ Vdbe *v; /* The VDBE we are building */
+ KeyInfo *pKey; /* Key information for an index */
+ int counterMem; /* Memory register used by AUTOINC */
+ int destHasUniqueIdx = 0; /* True if pDest has a UNIQUE index */
+
+ if( pSelect==0 ){
+ return 0; /* Must be of the form INSERT INTO ... SELECT ... */
+ }
+ if( pDest->pTrigger ){
+ return 0; /* tab1 must not have triggers */
+ }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pDest->isVirtual ){
+ return 0; /* tab1 must not be a virtual table */
+ }
+#endif
+ if( onError==OE_Default ){
+ onError = OE_Abort;
+ }
+ if( onError!=OE_Abort && onError!=OE_Rollback ){
+ return 0; /* Cannot do OR REPLACE or OR IGNORE or OR FAIL */
+ }
+ if( pSelect->pSrc==0 ){
+ return 0; /* SELECT must have a FROM clause */
+ }
+ if( pSelect->pSrc->nSrc!=1 ){
+ return 0; /* FROM clause must have exactly one term */
+ }
+ if( pSelect->pSrc->a[0].pSelect ){
+ return 0; /* FROM clause cannot contain a subquery */
+ }
+ if( pSelect->pWhere ){
+ return 0; /* SELECT may not have a WHERE clause */
+ }
+ if( pSelect->pOrderBy ){
+ return 0; /* SELECT may not have an ORDER BY clause */
+ }
+ /* Do not need to test for a HAVING clause. If HAVING is present but
+ ** there is no ORDER BY, we will get an error. */
+ if( pSelect->pGroupBy ){
+ return 0; /* SELECT may not have a GROUP BY clause */
+ }
+ if( pSelect->pLimit ){
+ return 0; /* SELECT may not have a LIMIT clause */
+ }
+ assert( pSelect->pOffset==0 ); /* Must be so if pLimit==0 */
+ if( pSelect->pPrior ){
+ return 0; /* SELECT may not be a compound query */
+ }
+ if( pSelect->isDistinct ){
+ return 0; /* SELECT may not be DISTINCT */
+ }
+ pEList = pSelect->pEList;
+ assert( pEList!=0 );
+ if( pEList->nExpr!=1 ){
+ return 0; /* The result set must have exactly one column */
+ }
+ assert( pEList->a[0].pExpr );
+ if( pEList->a[0].pExpr->op!=TK_ALL ){
+ return 0; /* The result set must be the special operator "*" */
+ }
+
+ /* At this point we have established that the statement is of the
+ ** correct syntactic form to participate in this optimization. Now
+ ** we have to check the semantics.
+ */
+ pItem = pSelect->pSrc->a;
+ pSrc = sqlite3LocateTable(pParse, pItem->zName, pItem->zDatabase);
+ if( pSrc==0 ){
+ return 0; /* FROM clause does not contain a real table */
+ }
+ if( pSrc==pDest ){
+ return 0; /* tab1 and tab2 may not be the same table */
+ }
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ if( pSrc->isVirtual ){
+ return 0; /* tab2 must not be a virtual table */
+ }
+#endif
+ if( pSrc->pSelect ){
+ return 0; /* tab2 may not be a view */
+ }
+ if( pDest->nCol!=pSrc->nCol ){
+ return 0; /* Number of columns must be the same in tab1 and tab2 */
+ }
+ if( pDest->iPKey!=pSrc->iPKey ){
+ return 0; /* Both tables must have the same INTEGER PRIMARY KEY */
+ }
+ for(i=0; i<pDest->nCol; i++){
+ if( pDest->aCol[i].affinity!=pSrc->aCol[i].affinity ){
+ return 0; /* Affinity must be the same on all columns */
+ }
+ if( !xferCompatibleCollation(pDest->aCol[i].zColl, pSrc->aCol[i].zColl) ){
+ return 0; /* Collating sequence must be the same on all columns */
+ }
+ if( pDest->aCol[i].notNull && !pSrc->aCol[i].notNull ){
+ return 0; /* tab2 must be NOT NULL if tab1 is */
+ }
+ }
+ for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
+ if( pDestIdx->onError!=OE_None ){
+ destHasUniqueIdx = 1;
+ }
+ for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
+ if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
+ }
+ if( pSrcIdx==0 ){
+ return 0; /* pDestIdx has no corresponding index in pSrc */
+ }
+ }
+#ifndef SQLITE_OMIT_CHECK
+ if( pDest->pCheck && !sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){
+ return 0; /* Tables have different CHECK constraints. Ticket #2252 */
+ }
+#endif
+
+ /* If we get this far, it means either:
+ **
+ ** * We can always do the transfer if the table contains an
+ ** an integer primary key
+ **
+ ** * We can conditionally do the transfer if the destination
+ ** table is empty.
+ */
+#ifdef SQLITE_TEST
+ sqlite3_xferopt_count++;
+#endif
+ iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema);
+ v = sqlite3GetVdbe(pParse);
+ iSrc = pParse->nTab++;
+ iDest = pParse->nTab++;
+ counterMem = autoIncBegin(pParse, iDbDest, pDest);
+ sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite);
+ if( (pDest->iPKey<0 && pDest->pIndex!=0) || destHasUniqueIdx ){
+ /* If tables do not have an INTEGER PRIMARY KEY and there
+ ** are indices to be copied and the destination is not empty,
+ ** we have to disallow the transfer optimization because the
+ ** the rowids might change which will mess up indexing.
+ **
+ ** Or if the destination has a UNIQUE index and is not empty,
+ ** we also disallow the transfer optimization because we cannot
+ ** insure that all entries in the union of DEST and SRC will be
+ ** unique.
+ */
+ addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iDest, 0);
+ emptyDestTest = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
+ sqlite3VdbeJumpHere(v, addr1);
+ }else{
+ emptyDestTest = 0;
+ }
+ sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead);
+ emptySrcTest = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0);
+ if( pDest->iPKey>=0 ){
+ addr1 = sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0);
+ sqlite3VdbeAddOp(v, OP_Dup, 0, 0);
+ addr2 = sqlite3VdbeAddOp(v, OP_NotExists, iDest, 0);
+ sqlite3VdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError,
+ "PRIMARY KEY must be unique", P3_STATIC);
+ sqlite3VdbeJumpHere(v, addr2);
+ autoIncStep(pParse, counterMem);
+ }else if( pDest->pIndex==0 ){
+ addr1 = sqlite3VdbeAddOp(v, OP_NewRowid, iDest, 0);
+ }else{
+ addr1 = sqlite3VdbeAddOp(v, OP_Rowid, iSrc, 0);
+ assert( pDest->autoInc==0 );
+ }
+ sqlite3VdbeAddOp(v, OP_RowData, iSrc, 0);
+ sqlite3VdbeOp3(v, OP_Insert, iDest,
+ OPFLAG_NCHANGE|OPFLAG_LASTROWID|OPFLAG_APPEND,
+ pDest->zName, 0);
+ sqlite3VdbeAddOp(v, OP_Next, iSrc, addr1);
+ autoIncEnd(pParse, iDbDest, pDest, counterMem);
+ for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){
+ for(pSrcIdx=pSrc->pIndex; pSrcIdx; pSrcIdx=pSrcIdx->pNext){
+ if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break;
+ }
+ assert( pSrcIdx );
+ sqlite3VdbeAddOp(v, OP_Close, iSrc, 0);
+ sqlite3VdbeAddOp(v, OP_Close, iDest, 0);
+ sqlite3VdbeAddOp(v, OP_Integer, iDbSrc, 0);
+ pKey = sqlite3IndexKeyinfo(pParse, pSrcIdx);
+ VdbeComment((v, "# %s", pSrcIdx->zName));
+ sqlite3VdbeOp3(v, OP_OpenRead, iSrc, pSrcIdx->tnum,
+ (char*)pKey, P3_KEYINFO_HANDOFF);
+ sqlite3VdbeAddOp(v, OP_Integer, iDbDest, 0);
+ pKey = sqlite3IndexKeyinfo(pParse, pDestIdx);
+ VdbeComment((v, "# %s", pDestIdx->zName));
+ sqlite3VdbeOp3(v, OP_OpenWrite, iDest, pDestIdx->tnum,
+ (char*)pKey, P3_KEYINFO_HANDOFF);
+ addr1 = sqlite3VdbeAddOp(v, OP_Rewind, iSrc, 0);
+ sqlite3VdbeAddOp(v, OP_RowKey, iSrc, 0);
+ sqlite3VdbeAddOp(v, OP_IdxInsert, iDest, 1);
+ sqlite3VdbeAddOp(v, OP_Next, iSrc, addr1+1);
+ sqlite3VdbeJumpHere(v, addr1);
+ }
+ sqlite3VdbeJumpHere(v, emptySrcTest);
+ sqlite3VdbeAddOp(v, OP_Close, iSrc, 0);
+ sqlite3VdbeAddOp(v, OP_Close, iDest, 0);
+ if( emptyDestTest ){
+ sqlite3VdbeAddOp(v, OP_Halt, SQLITE_OK, 0);
+ sqlite3VdbeJumpHere(v, emptyDestTest);
+ sqlite3VdbeAddOp(v, OP_Close, iDest, 0);
+ return 0;
+ }else{
+ return 1;
+ }
+}
+#endif /* SQLITE_OMIT_XFER_OPT */
diff --git a/ext/pdo_sqlite/sqlite/src/keywordhash.h b/ext/pdo_sqlite/sqlite/src/keywordhash.h
index bc0898f3b..11b40e47f 100644
--- a/ext/pdo_sqlite/sqlite/src/keywordhash.h
+++ b/ext/pdo_sqlite/sqlite/src/keywordhash.h
@@ -1,85 +1,98 @@
-/* Hash score: 167 */
+/***** This file contains automatically generated code ******
+**
+** The code in this file has been automatically generated by
+**
+** $Header: /repository/php-src/ext/pdo_sqlite/sqlite/src/keywordhash.h,v 1.2.2.1.2.3 2007/04/18 22:53:46 iliaa Exp $
+**
+** The code in this file implements a function that determines whether
+** or not a given identifier is really an SQL keyword. The same thing
+** might be implemented more directly using a hand-written hash table.
+** But by using this automatically generated code, the size of the code
+** is substantially reduced. This is important for embedded applications
+** on platforms with limited memory.
+*/
+/* Hash score: 165 */
static int keywordCode(const char *z, int n){
- static const char zText[544] =
+ static const char zText[536] =
"ABORTABLEFTEMPORARYADDATABASELECTHENDEFAULTRANSACTIONATURALTER"
"AISEACHECKEYAFTEREFERENCESCAPELSEXCEPTRIGGEREGEXPLAINITIALLYANALYZE"
- "XCLUSIVEXISTSTATEMENTANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEX"
- "AUTOINCREMENTBEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETE"
- "CASECASTCOLLATECOLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSS"
- "CURRENT_DATECURRENT_TIMESTAMPLANDESCDETACHDISTINCTDROPRAGMATCH"
- "FAILIMITFROMFULLGROUPDATEIFIMMEDIATEINSERTINSTEADINTOFFSETISNULL"
- "JOINORDEREPLACEOUTERESTRICTPRIMARYQUERYRIGHTROLLBACKROWHENUNION"
- "UNIQUEUSINGVACUUMVALUESVIEWHEREVIRTUAL";
+ "XCLUSIVEXISTSANDEFERRABLEATTACHAVINGLOBEFOREIGNOREINDEXAUTOINCREMENT"
+ "BEGINNERENAMEBETWEENOTNULLIKEBYCASCADEFERREDELETECASECASTCOLLATE"
+ "COLUMNCOMMITCONFLICTCONSTRAINTERSECTCREATECROSSCURRENT_DATECURRENT_TIMESTAMP"
+ "LANDESCDETACHDISTINCTDROPRAGMATCHFAILIMITFROMFULLGROUPDATEIFIMMEDIATE"
+ "INSERTINSTEADINTOFFSETISNULLJOINORDEREPLACEOUTERESTRICTPRIMARY"
+ "QUERYRIGHTROLLBACKROWHENUNIONUNIQUEUSINGVACUUMVALUESVIEWHEREVIRTUAL"
+ ;
static const unsigned char aHash[127] = {
- 92, 80, 107, 91, 0, 4, 0, 0, 114, 0, 83, 0, 0,
- 95, 44, 76, 93, 0, 106, 109, 97, 90, 0, 10, 0, 0,
- 113, 0, 117, 103, 0, 28, 48, 0, 41, 0, 0, 65, 71,
- 0, 63, 19, 0, 105, 36, 104, 0, 108, 74, 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, 101, 58, 18, 0, 112, 82, 99,
- 54, 6, 85, 0, 0, 49, 94, 0, 102, 0, 70, 0, 0,
- 15, 0, 116, 51, 56, 0, 2, 55, 0, 111,
+ 91, 79, 106, 90, 0, 4, 0, 0, 113, 0, 82, 0, 0,
+ 94, 43, 75, 92, 0, 105, 108, 96, 89, 0, 10, 0, 0,
+ 112, 0, 116, 102, 0, 28, 47, 0, 40, 0, 0, 64, 70,
+ 0, 62, 19, 0, 104, 35, 103, 0, 107, 73, 0, 0, 33,
+ 0, 60, 36, 0, 8, 0, 114, 37, 12, 0, 76, 39, 25,
+ 65, 0, 0, 31, 80, 52, 30, 49, 20, 87, 0, 34, 0,
+ 74, 26, 0, 71, 0, 0, 0, 63, 46, 66, 22, 86, 29,
+ 68, 85, 0, 1, 0, 9, 100, 57, 18, 0, 111, 81, 98,
+ 53, 6, 84, 0, 0, 48, 93, 0, 101, 0, 69, 0, 0,
+ 15, 0, 115, 50, 55, 0, 2, 54, 0, 110,
};
- static const unsigned char aNext[117] = {
+ 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,
- 21, 0, 79, 0, 0, 68, 0, 0, 84, 46, 0, 0, 0,
- 0, 0, 0, 0, 0, 39, 96, 98, 0, 0, 100, 0, 32,
- 0, 14, 27, 78, 0, 57, 89, 0, 35, 0, 62, 0, 110,
+ 0, 11, 0, 0, 0, 0, 5, 13, 7, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0,
+ 0, 16, 0, 23, 51, 0, 0, 0, 0, 44, 0, 58, 0,
+ 0, 0, 0, 0, 0, 0, 0, 72, 41, 0, 24, 59, 21,
+ 0, 78, 0, 0, 67, 0, 0, 83, 45, 0, 0, 0, 0,
+ 0, 0, 0, 0, 38, 95, 97, 0, 0, 99, 0, 32, 0,
+ 14, 27, 77, 0, 56, 88, 0, 0, 0, 61, 0, 109,
};
- static const unsigned char aLen[117] = {
+ 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, 2, 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, 7,
+ 7, 6, 7, 9, 3, 7, 9, 6, 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, 2, 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, 7,
};
- static const unsigned short int aOffset[117] = {
+ 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, 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, 536,
+ 99, 105, 108, 113, 118, 122, 128, 136, 142, 144, 154, 159, 164,
+ 167, 169, 169, 173, 177, 179, 184, 186, 188, 197, 200, 204, 210,
+ 216, 216, 219, 222, 226, 228, 229, 233, 240, 246, 250, 254, 261,
+ 267, 273, 281, 288, 297, 303, 308, 320, 320, 336, 340, 344, 350,
+ 351, 358, 361, 365, 370, 373, 378, 382, 386, 389, 395, 397, 406,
+ 412, 419, 422, 422, 425, 428, 434, 438, 442, 449, 453, 461, 468,
+ 473, 478, 486, 488, 492, 497, 503, 508, 514, 520, 523, 528,
};
- static const unsigned char aCode[117] = {
+ 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_INDEX, TK_AUTOINCR, TK_TO, TK_IN, TK_BEGIN,
- TK_JOIN_KW, TK_RENAME, TK_BETWEEN, TK_NOT, TK_NOTNULL,
- 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_IF,
- 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_VIRTUAL,
+ TK_ALL, TK_ANALYZE, TK_EXCLUSIVE, TK_EXISTS, TK_AND,
+ TK_DEFERRABLE, TK_ATTACH, TK_HAVING, TK_LIKE_KW, TK_BEFORE,
+ TK_FOR, TK_FOREIGN, 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_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_IF, 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_VIRTUAL,
};
int h, i;
if( n<2 ) return TK_ID;
diff --git a/ext/pdo_sqlite/sqlite/src/legacy.c b/ext/pdo_sqlite/sqlite/src/legacy.c
index c75791e1b..00c0f9eef 100644
--- a/ext/pdo_sqlite/sqlite/src/legacy.c
+++ b/ext/pdo_sqlite/sqlite/src/legacy.c
@@ -131,5 +131,6 @@ exec_out:
*pzErrMsg = 0;
}
+ assert( (rc&db->errMask)==rc );
return rc;
}
diff --git a/ext/pdo_sqlite/sqlite/src/loadext.c b/ext/pdo_sqlite/sqlite/src/loadext.c
index 60ec053cf..dc4dc7e28 100644
--- a/ext/pdo_sqlite/sqlite/src/loadext.c
+++ b/ext/pdo_sqlite/sqlite/src/loadext.c
@@ -17,6 +17,7 @@
#define SQLITE_CORE 1 /* Disable the API redefinition in sqlite3ext.h */
#include "sqlite3ext.h"
#include "sqliteInt.h"
+#include "os.h"
#include <string.h>
#include <ctype.h>
@@ -74,6 +75,20 @@
# define sqlite3_declare_vtab 0
#endif
+#ifdef SQLITE_OMIT_SHARED_CACHE
+# define sqlite3_enable_shared_cache 0
+#endif
+
+#ifdef SQLITE_OMIT_TRACE
+# define sqlite3_profile 0
+# define sqlite3_trace 0
+#endif
+
+#ifdef SQLITE_OMIT_GET_TABLE
+# define sqlite3_free_table 0
+# define sqlite3_get_table 0
+#endif
+
/*
** The following structure contains pointers to all SQLite API routines.
** A pointer to this structure is passed into extensions when they are
@@ -89,7 +104,7 @@
** also check to make sure that the pointer to the function is
** not NULL before calling it.
*/
-const sqlite3_api_routines sqlite3_api = {
+const sqlite3_api_routines sqlite3_apis = {
sqlite3_aggregate_context,
sqlite3_aggregate_count,
sqlite3_bind_blob,
@@ -153,7 +168,7 @@ const sqlite3_api_routines sqlite3_api = {
sqlite3_get_autocommit,
sqlite3_get_auxdata,
sqlite3_get_table,
- sqlite3_global_recover,
+ 0, /* Was sqlite3_global_recover(), but that function is deprecated */
sqlite3_interrupt,
sqlite3_last_insert_rowid,
sqlite3_libversion,
@@ -213,29 +228,15 @@ const sqlite3_api_routines sqlite3_api = {
** a library that is new enough to support that API.
*************************************************************************
*/
-};
-
-/*
-** The windows implementation of shared-library loaders
-*/
-#if defined(_WIN32) || defined(WIN32) || defined(__MINGW32__) || defined(__BORLANDC__)
-# include <windows.h>
-# define SQLITE_LIBRARY_TYPE HANDLE
-# define SQLITE_OPEN_LIBRARY(A) LoadLibrary(A)
-# define SQLITE_FIND_SYMBOL(A,B) GetProcAddress(A,B)
-# define SQLITE_CLOSE_LIBRARY(A) FreeLibrary(A)
-#endif /* windows */
+ sqlite3_overload_function,
-/*
-** The unix implementation of shared-library loaders
-*/
-#if defined(HAVE_DLOPEN) && !defined(SQLITE_LIBRARY_TYPE)
-# include <dlfcn.h>
-# define SQLITE_LIBRARY_TYPE void*
-# define SQLITE_OPEN_LIBRARY(A) dlopen(A, RTLD_NOW | RTLD_GLOBAL)
-# define SQLITE_FIND_SYMBOL(A,B) dlsym(A,B)
-# define SQLITE_CLOSE_LIBRARY(A) dlclose(A)
-#endif
+ /*
+ ** Added after 3.3.13
+ */
+ sqlite3_prepare_v2,
+ sqlite3_prepare16_v2,
+ sqlite3_clear_bindings,
+};
/*
** Attempt to load an SQLite extension library contained in the file
@@ -255,11 +256,10 @@ int sqlite3_load_extension(
const char *zProc, /* Entry point. Use "sqlite3_extension_init" if 0 */
char **pzErrMsg /* Put error message here if not 0 */
){
-#ifdef SQLITE_LIBRARY_TYPE
- SQLITE_LIBRARY_TYPE handle;
+ void *handle;
int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
char *zErrmsg = 0;
- SQLITE_LIBRARY_TYPE *aHandle;
+ void **aHandle;
/* Ticket #1863. To avoid a creating security problems for older
** applications that relink against newer versions of SQLite, the
@@ -278,7 +278,7 @@ int sqlite3_load_extension(
zProc = "sqlite3_extension_init";
}
- handle = SQLITE_OPEN_LIBRARY(zFile);
+ handle = sqlite3OsDlopen(zFile);
if( handle==0 ){
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("unable to open shared library [%s]", zFile);
@@ -286,20 +286,20 @@ int sqlite3_load_extension(
return SQLITE_ERROR;
}
xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
- SQLITE_FIND_SYMBOL(handle, zProc);
+ sqlite3OsDlsym(handle, zProc);
if( xInit==0 ){
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("no entry point [%s] in shared library [%s]",
zProc, zFile);
}
- SQLITE_CLOSE_LIBRARY(handle);
+ sqlite3OsDlclose(handle);
return SQLITE_ERROR;
- }else if( xInit(db, &zErrmsg, &sqlite3_api) ){
+ }else if( xInit(db, &zErrmsg, &sqlite3_apis) ){
if( pzErrMsg ){
*pzErrMsg = sqlite3_mprintf("error during initialization: %s", zErrmsg);
}
sqlite3_free(zErrmsg);
- SQLITE_CLOSE_LIBRARY(handle);
+ sqlite3OsDlclose(handle);
return SQLITE_ERROR;
}
@@ -315,14 +315,8 @@ int sqlite3_load_extension(
sqliteFree(db->aExtension);
db->aExtension = aHandle;
- ((SQLITE_LIBRARY_TYPE*)db->aExtension)[db->nExtension-1] = handle;
+ db->aExtension[db->nExtension-1] = handle;
return SQLITE_OK;
-#else
- if( pzErrMsg ){
- *pzErrMsg = sqlite3_mprintf("extension loading is disabled");
- }
- return SQLITE_ERROR;
-#endif
}
/*
@@ -330,13 +324,11 @@ int sqlite3_load_extension(
** to clean up loaded extensions
*/
void sqlite3CloseExtensions(sqlite3 *db){
-#ifdef SQLITE_LIBRARY_TYPE
int i;
for(i=0; i<db->nExtension; i++){
- SQLITE_CLOSE_LIBRARY(((SQLITE_LIBRARY_TYPE*)db->aExtension)[i]);
+ sqlite3OsDlclose(db->aExtension[i]);
}
sqliteFree(db->aExtension);
-#endif
}
/*
@@ -352,4 +344,86 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff){
return SQLITE_OK;
}
+/*
+** A list of automatically loaded extensions.
+**
+** This list is shared across threads, so be sure to hold the
+** mutex while accessing or changing it.
+*/
+static int nAutoExtension = 0;
+static void **aAutoExtension = 0;
+
+
+/*
+** Register a statically linked extension that is automatically
+** loaded by every new database connection.
+*/
+int sqlite3_auto_extension(void *xInit){
+ int i;
+ int rc = SQLITE_OK;
+ sqlite3OsEnterMutex();
+ for(i=0; i<nAutoExtension; i++){
+ if( aAutoExtension[i]==xInit ) break;
+ }
+ if( i==nAutoExtension ){
+ nAutoExtension++;
+ aAutoExtension = sqlite3Realloc( aAutoExtension,
+ nAutoExtension*sizeof(aAutoExtension[0]) );
+ if( aAutoExtension==0 ){
+ nAutoExtension = 0;
+ rc = SQLITE_NOMEM;
+ }else{
+ aAutoExtension[nAutoExtension-1] = xInit;
+ }
+ }
+ sqlite3OsLeaveMutex();
+ assert( (rc&0xff)==rc );
+ return rc;
+}
+
+/*
+** Reset the automatic extension loading mechanism.
+*/
+void sqlite3_reset_auto_extension(void){
+ sqlite3OsEnterMutex();
+ sqliteFree(aAutoExtension);
+ aAutoExtension = 0;
+ nAutoExtension = 0;
+ sqlite3OsLeaveMutex();
+}
+
+/*
+** Load all automatic extensions.
+*/
+int sqlite3AutoLoadExtensions(sqlite3 *db){
+ int i;
+ int go = 1;
+ int rc = SQLITE_OK;
+ int (*xInit)(sqlite3*,char**,const sqlite3_api_routines*);
+
+ if( nAutoExtension==0 ){
+ /* Common case: early out without every having to acquire a mutex */
+ return SQLITE_OK;
+ }
+ for(i=0; go; i++){
+ char *zErrmsg = 0;
+ sqlite3OsEnterMutex();
+ if( i>=nAutoExtension ){
+ xInit = 0;
+ go = 0;
+ }else{
+ xInit = (int(*)(sqlite3*,char**,const sqlite3_api_routines*))
+ aAutoExtension[i];
+ }
+ sqlite3OsLeaveMutex();
+ if( xInit && xInit(db, &zErrmsg, &sqlite3_apis) ){
+ sqlite3Error(db, SQLITE_ERROR,
+ "automatic extension loading failed: %s", zErrmsg);
+ go = 0;
+ rc = SQLITE_ERROR;
+ }
+ }
+ return rc;
+}
+
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
diff --git a/ext/pdo_sqlite/sqlite/src/main.c b/ext/pdo_sqlite/sqlite/src/main.c
index eccf83be6..daac62f8c 100644
--- a/ext/pdo_sqlite/sqlite/src/main.c
+++ b/ext/pdo_sqlite/sqlite/src/main.c
@@ -21,12 +21,6 @@
#include <ctype.h>
/*
-** The following constant value is used by the SQLITE_BIGENDIAN and
-** SQLITE_LITTLEENDIAN macros.
-*/
-const int sqlite3one = 1;
-
-/*
** The version of the library
*/
const char sqlite3_version[] = SQLITE_VERSION;
@@ -34,6 +28,24 @@ const char *sqlite3_libversion(void){ return sqlite3_version; }
int sqlite3_libversion_number(void){ return SQLITE_VERSION_NUMBER; }
/*
+** If the following function pointer is not NULL and if
+** SQLITE_ENABLE_IOTRACE is enabled, then messages describing
+** I/O active are written using this function. These messages
+** are intended for debugging activity only.
+*/
+void (*sqlite3_io_trace)(const char*, ...) = 0;
+
+/*
+** If the following global variable points to a string which is the
+** name of a directory, then that directory will be used to store
+** temporary files.
+**
+** See also the "PRAGMA temp_store_directory" SQL command.
+*/
+char *sqlite3_temp_directory = 0;
+
+
+/*
** This is the default collating function named "BINARY" which is always
** available.
*/
@@ -115,8 +127,18 @@ int sqlite3_close(sqlite3 *db){
}
#endif
- /* If there are any outstanding VMs, return SQLITE_BUSY. */
sqlite3ResetInternalSchema(db, 0);
+
+ /* If a transaction is open, the ResetInternalSchema() call above
+ ** will not have called the xDisconnect() method on any virtual
+ ** tables in the db->aVTrans[] array. The following sqlite3VtabRollback()
+ ** call will do so. We need to do this before the check for active
+ ** SQL statements below, as the v-table implementation may be storing
+ ** some prepared statements internally.
+ */
+ sqlite3VtabRollback(db);
+
+ /* If there are any outstanding VMs, return SQLITE_BUSY. */
if( db->pVdbe ){
sqlite3Error(db, SQLITE_BUSY,
"Unable to close due to unfinalised statements");
@@ -128,14 +150,15 @@ int sqlite3_close(sqlite3 *db){
** cannot be opened for some reason. So this routine needs to run in
** that case. But maybe there should be an extra magic value for the
** "failed to open" state.
+ **
+ ** TODO: Coverage tests do not test the case where this condition is
+ ** true. It's hard to see how to cause it without messing with threads.
*/
if( db->magic!=SQLITE_MAGIC_CLOSED && sqlite3SafetyOn(db) ){
/* printf("DID NOT CLOSE\n"); fflush(stdout); */
return SQLITE_ERROR;
}
- sqlite3VtabRollback(db);
-
for(j=0; j<db->nDb; j++){
struct Db *pDb = &db->aDb[j];
if( pDb->pBt ){
@@ -223,7 +246,7 @@ void sqlite3RollbackAll(sqlite3 *db){
*/
const char *sqlite3ErrStr(int rc){
const char *z;
- switch( rc ){
+ switch( rc & 0xff ){
case SQLITE_ROW:
case SQLITE_DONE:
case SQLITE_OK: z = "not an error"; break;
@@ -239,7 +262,6 @@ const char *sqlite3ErrStr(int rc){
case SQLITE_CORRUPT: z = "database disk image is malformed"; break;
case SQLITE_FULL: z = "database or disk is full"; break;
case SQLITE_CANTOPEN: z = "unable to open database file"; break;
- case SQLITE_PROTOCOL: z = "database locking protocol failure"; break;
case SQLITE_EMPTY: z = "table contains no data"; break;
case SQLITE_SCHEMA: z = "database schema has changed"; break;
case SQLITE_CONSTRAINT: z = "constraint failed"; break;
@@ -541,6 +563,32 @@ int sqlite3_create_function16(
}
#endif
+
+/*
+** Declare that a function has been overloaded by a virtual table.
+**
+** If the function already exists as a regular global function, then
+** this routine is a no-op. If the function does not exist, then create
+** a new one that always throws a run-time error.
+**
+** When virtual tables intend to provide an overloaded function, they
+** should call this routine to make sure the global function exists.
+** A global function must exist in order for name resolution to work
+** properly.
+*/
+int sqlite3_overload_function(
+ sqlite3 *db,
+ const char *zName,
+ int nArg
+){
+ int nName = strlen(zName);
+ if( sqlite3FindFunction(db, zName, nName, nArg, SQLITE_UTF8, 0)==0 ){
+ sqlite3CreateFunc(db, zName, nArg, SQLITE_UTF8,
+ 0, sqlite3InvalidFunction, 0, 0);
+ }
+ return sqlite3ApiExit(db, SQLITE_OK);
+}
+
#ifndef SQLITE_OMIT_TRACE
/*
** Register a trace function. The pArg from the previously registered trace
@@ -696,7 +744,8 @@ int sqlite3BtreeFactory(
*/
const char *sqlite3_errmsg(sqlite3 *db){
const char *z;
- if( !db || sqlite3MallocFailed() ){
+ assert( !sqlite3MallocFailed() );
+ if( !db ){
return sqlite3ErrStr(SQLITE_NOMEM);
}
if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
@@ -735,7 +784,8 @@ const void *sqlite3_errmsg16(sqlite3 *db){
};
const void *z;
- if( sqlite3MallocFailed() ){
+ assert( !sqlite3MallocFailed() );
+ if( !db ){
return (void *)(&outOfMemBe[SQLITE_UTF16NATIVE==SQLITE_UTF16LE?1:0]);
}
if( sqlite3SafetyCheck(db) || db->errCode==SQLITE_MISUSE ){
@@ -763,7 +813,7 @@ int sqlite3_errcode(sqlite3 *db){
if( sqlite3SafetyCheck(db) ){
return SQLITE_MISUSE;
}
- return db->errCode;
+ return db->errCode & db->errMask;
}
/*
@@ -841,6 +891,7 @@ static int openDatabase(
/* Allocate the sqlite data structure */
db = sqliteMalloc( sizeof(sqlite3) );
if( db==0 ) goto opendb_out;
+ db->errMask = 0xff;
db->priorNewRowid = 0;
db->magic = SQLITE_MAGIC_BUSY;
db->nDb = 2;
@@ -850,6 +901,9 @@ static int openDatabase(
#if SQLITE_DEFAULT_FILE_FORMAT<4
| SQLITE_LegacyFileFmt
#endif
+#ifdef SQLITE_ENABLE_LOAD_EXTENSION
+ | SQLITE_LoadExtension
+#endif
;
sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0);
sqlite3HashInit(&db->aCollSeq, SQLITE_HASH_STRING, 0);
@@ -907,11 +961,40 @@ static int openDatabase(
** is accessed.
*/
if( !sqlite3MallocFailed() ){
- sqlite3RegisterBuiltinFunctions(db);
sqlite3Error(db, SQLITE_OK, 0);
+ sqlite3RegisterBuiltinFunctions(db);
}
db->magic = SQLITE_MAGIC_OPEN;
+ /* Load automatic extensions - extensions that have been registered
+ ** using the sqlite3_automatic_extension() API.
+ */
+ (void)sqlite3AutoLoadExtensions(db);
+
+#ifdef SQLITE_ENABLE_FTS1
+ {
+ extern int sqlite3Fts1Init(sqlite3*);
+ sqlite3Fts1Init(db);
+ }
+#endif
+
+#ifdef SQLITE_ENABLE_FTS2
+ {
+ extern int sqlite3Fts2Init(sqlite3*);
+ sqlite3Fts2Init(db);
+ }
+#endif
+
+ /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
+ ** mode. -DSQLITE_DEFAULT_LOCKING_MODE=0 make NORMAL the default locking
+ ** mode. Doing nothing at all also makes NORMAL the default.
+ */
+#ifdef SQLITE_DEFAULT_LOCKING_MODE
+ db->dfltLockMode = SQLITE_DEFAULT_LOCKING_MODE;
+ sqlite3PagerLockingMode(sqlite3BtreePager(db->aDb[0].pBt),
+ SQLITE_DEFAULT_LOCKING_MODE);
+#endif
+
opendb_out:
if( SQLITE_NOMEM==(rc = sqlite3_errcode(db)) ){
sqlite3_close(db);
@@ -999,6 +1082,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
}else{
rc = sqlite3VdbeReset((Vdbe*)pStmt);
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
+ assert( (rc & (sqlite3_db_handle(pStmt)->errMask))==rc );
}
return rc;
}
@@ -1285,3 +1369,11 @@ int sqlite3_clear_bindings(sqlite3_stmt *pStmt){
int sqlite3_sleep(int ms){
return sqlite3OsSleep(ms);
}
+
+/*
+** Enable or disable the extended result codes.
+*/
+int sqlite3_extended_result_codes(sqlite3 *db, int onoff){
+ db->errMask = onoff ? 0xffffffff : 0xff;
+ return SQLITE_OK;
+}
diff --git a/ext/pdo_sqlite/sqlite/src/opcodes.c b/ext/pdo_sqlite/sqlite/src/opcodes.c
index 734d1a540..d96285214 100644
--- a/ext/pdo_sqlite/sqlite/src/opcodes.c
+++ b/ext/pdo_sqlite/sqlite/src/opcodes.c
@@ -2,136 +2,147 @@
/* See the mkopcodec.awk script for details. */
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG)
const char *const sqlite3OpcodeNames[] = { "?",
- /* 1 */ "MemLoad",
- /* 2 */ "Column",
- /* 3 */ "SetCookie",
- /* 4 */ "IfMemPos",
- /* 5 */ "MoveGt",
- /* 6 */ "AggFocus",
- /* 7 */ "RowKey",
- /* 8 */ "IdxRecno",
- /* 9 */ "AggNext",
- /* 10 */ "OpenWrite",
- /* 11 */ "If",
- /* 12 */ "PutStrKey",
- /* 13 */ "Pop",
- /* 14 */ "SortPut",
- /* 15 */ "AggContextPush",
- /* 16 */ "CollSeq",
- /* 17 */ "OpenRead",
- /* 18 */ "Expire",
- /* 19 */ "SortReset",
- /* 20 */ "AutoCommit",
- /* 21 */ "Sort",
- /* 22 */ "ListRewind",
- /* 23 */ "IntegrityCk",
- /* 24 */ "Function",
- /* 25 */ "Noop",
- /* 26 */ "Return",
- /* 27 */ "Variable",
- /* 28 */ "String",
- /* 29 */ "ParseSchema",
- /* 30 */ "PutIntKey",
- /* 31 */ "AggFunc",
- /* 32 */ "Close",
- /* 33 */ "ListWrite",
- /* 34 */ "CreateIndex",
- /* 35 */ "IsUnique",
- /* 36 */ "IdxIsNull",
- /* 37 */ "NotFound",
- /* 38 */ "MustBeInt",
- /* 39 */ "Halt",
- /* 40 */ "IdxLT",
- /* 41 */ "AddImm",
- /* 42 */ "Statement",
- /* 43 */ "RowData",
- /* 44 */ "MemMax",
- /* 45 */ "Push",
- /* 46 */ "KeyAsData",
- /* 47 */ "NotExists",
- /* 48 */ "OpenTemp",
- /* 49 */ "MemIncr",
- /* 50 */ "Gosub",
- /* 51 */ "AggSet",
- /* 52 */ "Integer",
- /* 53 */ "SortNext",
- /* 54 */ "Prev",
- /* 55 */ "CreateTable",
- /* 56 */ "Last",
- /* 57 */ "ResetCount",
- /* 58 */ "Callback",
- /* 59 */ "ContextPush",
- /* 60 */ "DropTrigger",
- /* 61 */ "DropIndex",
- /* 62 */ "FullKey",
- /* 63 */ "IdxGE",
- /* 64 */ "Or",
- /* 65 */ "And",
- /* 66 */ "Not",
- /* 67 */ "IdxDelete",
- /* 68 */ "Vacuum",
- /* 69 */ "MoveLe",
- /* 70 */ "IsNull",
- /* 71 */ "NotNull",
- /* 72 */ "Ne",
- /* 73 */ "Eq",
- /* 74 */ "Gt",
- /* 75 */ "Le",
- /* 76 */ "Lt",
- /* 77 */ "Ge",
- /* 78 */ "IfNot",
- /* 79 */ "BitAnd",
- /* 80 */ "BitOr",
- /* 81 */ "ShiftLeft",
- /* 82 */ "ShiftRight",
- /* 83 */ "Add",
- /* 84 */ "Subtract",
- /* 85 */ "Multiply",
- /* 86 */ "Divide",
- /* 87 */ "Remainder",
- /* 88 */ "Concat",
- /* 89 */ "Negative",
- /* 90 */ "DropTable",
- /* 91 */ "BitNot",
- /* 92 */ "String8",
- /* 93 */ "MakeRecord",
- /* 94 */ "Delete",
- /* 95 */ "AggContextPop",
- /* 96 */ "ListRead",
- /* 97 */ "ListReset",
- /* 98 */ "Dup",
- /* 99 */ "Goto",
- /* 100 */ "Clear",
- /* 101 */ "IdxGT",
- /* 102 */ "MoveLt",
- /* 103 */ "VerifyCookie",
- /* 104 */ "Pull",
- /* 105 */ "SetNumColumns",
- /* 106 */ "AbsValue",
- /* 107 */ "Transaction",
- /* 108 */ "AggGet",
- /* 109 */ "ContextPop",
- /* 110 */ "Next",
- /* 111 */ "AggInit",
- /* 112 */ "Distinct",
- /* 113 */ "NewRecno",
- /* 114 */ "AggReset",
- /* 115 */ "Destroy",
- /* 116 */ "ReadCookie",
- /* 117 */ "ForceInt",
- /* 118 */ "Recno",
- /* 119 */ "OpenPseudo",
- /* 120 */ "Blob",
- /* 121 */ "MemStore",
- /* 122 */ "Rewind",
- /* 123 */ "MoveGe",
- /* 124 */ "IdxPut",
- /* 125 */ "Found",
- /* 126 */ "NullRow",
- /* 127 */ "NotUsed_127",
- /* 128 */ "NotUsed_128",
- /* 129 */ "NotUsed_129",
- /* 130 */ "Real",
- /* 131 */ "HexBlob",
+ /* 1 */ "NotExists",
+ /* 2 */ "Dup",
+ /* 3 */ "MoveLt",
+ /* 4 */ "VCreate",
+ /* 5 */ "DropTrigger",
+ /* 6 */ "OpenPseudo",
+ /* 7 */ "MemInt",
+ /* 8 */ "IntegrityCk",
+ /* 9 */ "RowKey",
+ /* 10 */ "LoadAnalysis",
+ /* 11 */ "IdxGT",
+ /* 12 */ "Last",
+ /* 13 */ "MemLoad",
+ /* 14 */ "SetCookie",
+ /* 15 */ "Sequence",
+ /* 16 */ "Not",
+ /* 17 */ "Pull",
+ /* 18 */ "VUpdate",
+ /* 19 */ "VColumn",
+ /* 20 */ "DropTable",
+ /* 21 */ "MemStore",
+ /* 22 */ "ContextPush",
+ /* 23 */ "Rowid",
+ /* 24 */ "VFilter",
+ /* 25 */ "NullRow",
+ /* 26 */ "Noop",
+ /* 27 */ "VRowid",
+ /* 28 */ "ParseSchema",
+ /* 29 */ "Statement",
+ /* 30 */ "CollSeq",
+ /* 31 */ "ContextPop",
+ /* 32 */ "MemIncr",
+ /* 33 */ "MoveGe",
+ /* 34 */ "If",
+ /* 35 */ "IfNot",
+ /* 36 */ "Destroy",
+ /* 37 */ "Distinct",
+ /* 38 */ "CreateIndex",
+ /* 39 */ "SetNumColumns",
+ /* 40 */ "ResetCount",
+ /* 41 */ "MakeIdxRec",
+ /* 42 */ "Goto",
+ /* 43 */ "IdxDelete",
+ /* 44 */ "MemMove",
+ /* 45 */ "Found",
+ /* 46 */ "MoveGt",
+ /* 47 */ "IfMemZero",
+ /* 48 */ "MustBeInt",
+ /* 49 */ "Prev",
+ /* 50 */ "MemNull",
+ /* 51 */ "AutoCommit",
+ /* 52 */ "String",
+ /* 53 */ "FifoWrite",
+ /* 54 */ "Return",
+ /* 55 */ "Callback",
+ /* 56 */ "AddImm",
+ /* 57 */ "Function",
+ /* 58 */ "NewRowid",
+ /* 59 */ "Blob",
+ /* 60 */ "Or",
+ /* 61 */ "And",
+ /* 62 */ "Next",
+ /* 63 */ "ForceInt",
+ /* 64 */ "ReadCookie",
+ /* 65 */ "IsNull",
+ /* 66 */ "NotNull",
+ /* 67 */ "Ne",
+ /* 68 */ "Eq",
+ /* 69 */ "Gt",
+ /* 70 */ "Le",
+ /* 71 */ "Lt",
+ /* 72 */ "Ge",
+ /* 73 */ "Halt",
+ /* 74 */ "BitAnd",
+ /* 75 */ "BitOr",
+ /* 76 */ "ShiftLeft",
+ /* 77 */ "ShiftRight",
+ /* 78 */ "Add",
+ /* 79 */ "Subtract",
+ /* 80 */ "Multiply",
+ /* 81 */ "Divide",
+ /* 82 */ "Remainder",
+ /* 83 */ "Concat",
+ /* 84 */ "Expire",
+ /* 85 */ "Negative",
+ /* 86 */ "DropIndex",
+ /* 87 */ "BitNot",
+ /* 88 */ "String8",
+ /* 89 */ "IdxInsert",
+ /* 90 */ "FifoRead",
+ /* 91 */ "Column",
+ /* 92 */ "Int64",
+ /* 93 */ "Gosub",
+ /* 94 */ "IfMemNeg",
+ /* 95 */ "RowData",
+ /* 96 */ "MemMax",
+ /* 97 */ "Close",
+ /* 98 */ "VerifyCookie",
+ /* 99 */ "IfMemPos",
+ /* 100 */ "Null",
+ /* 101 */ "Integer",
+ /* 102 */ "Transaction",
+ /* 103 */ "IdxLT",
+ /* 104 */ "Delete",
+ /* 105 */ "Rewind",
+ /* 106 */ "Push",
+ /* 107 */ "RealAffinity",
+ /* 108 */ "Clear",
+ /* 109 */ "AggStep",
+ /* 110 */ "Explain",
+ /* 111 */ "Vacuum",
+ /* 112 */ "VDestroy",
+ /* 113 */ "IsUnique",
+ /* 114 */ "VOpen",
+ /* 115 */ "AggFinal",
+ /* 116 */ "OpenWrite",
+ /* 117 */ "VNext",
+ /* 118 */ "AbsValue",
+ /* 119 */ "Sort",
+ /* 120 */ "NotFound",
+ /* 121 */ "MoveLe",
+ /* 122 */ "MakeRecord",
+ /* 123 */ "Variable",
+ /* 124 */ "CreateTable",
+ /* 125 */ "Real",
+ /* 126 */ "HexBlob",
+ /* 127 */ "Insert",
+ /* 128 */ "IdxGE",
+ /* 129 */ "OpenRead",
+ /* 130 */ "IdxRowid",
+ /* 131 */ "VBegin",
+ /* 132 */ "TableLock",
+ /* 133 */ "OpenEphemeral",
+ /* 134 */ "Pop",
+ /* 135 */ "NotUsed_135",
+ /* 136 */ "NotUsed_136",
+ /* 137 */ "NotUsed_137",
+ /* 138 */ "ToText",
+ /* 139 */ "ToBlob",
+ /* 140 */ "ToNumeric",
+ /* 141 */ "ToInt",
+ /* 142 */ "ToReal",
};
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/opcodes.h b/ext/pdo_sqlite/sqlite/src/opcodes.h
index c113f8f1c..f8c0f19fb 100644
--- a/ext/pdo_sqlite/sqlite/src/opcodes.h
+++ b/ext/pdo_sqlite/sqlite/src/opcodes.h
@@ -1,161 +1,160 @@
/* Automatically generated. Do not edit */
/* See the mkopcodeh.awk script for details */
-#define OP_MemLoad 1
-#define OP_VNext 2
-#define OP_HexBlob 127 /* same as TK_BLOB */
-#define OP_Column 3
-#define OP_SetCookie 4
-#define OP_IfMemPos 5
-#define OP_Real 126 /* same as TK_FLOAT */
-#define OP_Sequence 6
-#define OP_MoveGt 7
-#define OP_Ge 73 /* same as TK_GE */
-#define OP_RowKey 8
-#define OP_Eq 69 /* same as TK_EQ */
-#define OP_OpenWrite 9
-#define OP_NotNull 67 /* same as TK_NOTNULL */
-#define OP_If 10
-#define OP_ToInt 142 /* same as TK_TO_INT */
+#define OP_NotExists 1
+#define OP_Dup 2
+#define OP_MoveLt 3
+#define OP_Multiply 80 /* same as TK_STAR */
+#define OP_VCreate 4
+#define OP_BitAnd 74 /* same as TK_BITAND */
+#define OP_DropTrigger 5
+#define OP_OpenPseudo 6
+#define OP_MemInt 7
+#define OP_IntegrityCk 8
+#define OP_RowKey 9
+#define OP_LoadAnalysis 10
+#define OP_IdxGT 11
+#define OP_Last 12
+#define OP_Subtract 79 /* same as TK_MINUS */
+#define OP_MemLoad 13
+#define OP_Remainder 82 /* same as TK_REM */
+#define OP_SetCookie 14
+#define OP_Sequence 15
+#define OP_Pull 17
+#define OP_VUpdate 18
+#define OP_VColumn 19
+#define OP_DropTable 20
+#define OP_MemStore 21
+#define OP_ContextPush 22
+#define OP_NotNull 66 /* same as TK_NOTNULL */
+#define OP_Rowid 23
+#define OP_Real 125 /* same as TK_FLOAT */
#define OP_String8 88 /* same as TK_STRING */
-#define OP_Pop 11
-#define OP_VRowid 12
-#define OP_CollSeq 13
-#define OP_OpenRead 14
-#define OP_Expire 15
-#define OP_AutoCommit 17
-#define OP_Gt 70 /* same as TK_GT */
-#define OP_IntegrityCk 18
-#define OP_Sort 19
-#define OP_Function 20
-#define OP_And 62 /* same as TK_AND */
-#define OP_Subtract 80 /* same as TK_MINUS */
-#define OP_Noop 21
-#define OP_Return 22
-#define OP_Remainder 83 /* same as TK_REM */
-#define OP_NewRowid 23
-#define OP_Multiply 81 /* same as TK_STAR */
-#define OP_IfMemNeg 24
-#define OP_Variable 25
-#define OP_String 26
-#define OP_RealAffinity 27
+#define OP_And 61 /* same as TK_AND */
+#define OP_BitNot 87 /* same as TK_BITNOT */
+#define OP_VFilter 24
+#define OP_NullRow 25
+#define OP_Noop 26
+#define OP_VRowid 27
+#define OP_Ge 72 /* same as TK_GE */
+#define OP_HexBlob 126 /* same as TK_BLOB */
#define OP_ParseSchema 28
-#define OP_VOpen 29
-#define OP_Close 30
-#define OP_CreateIndex 31
-#define OP_IsUnique 32
-#define OP_IdxIsNull 33
-#define OP_NotFound 34
-#define OP_Int64 35
-#define OP_MustBeInt 36
-#define OP_Halt 37
-#define OP_Rowid 38
-#define OP_IdxLT 39
-#define OP_AddImm 40
-#define OP_Statement 41
-#define OP_RowData 42
-#define OP_MemMax 43
-#define OP_Push 44
-#define OP_Or 61 /* same as TK_OR */
-#define OP_NotExists 45
-#define OP_MemIncr 46
-#define OP_Gosub 47
-#define OP_Divide 82 /* same as TK_SLASH */
-#define OP_Integer 48
-#define OP_ToNumeric 141 /* same as TK_TO_NUMERIC*/
-#define OP_MemInt 49
-#define OP_Prev 50
-#define OP_Concat 84 /* same as TK_CONCAT */
-#define OP_BitAnd 75 /* same as TK_BITAND */
-#define OP_VColumn 51
-#define OP_CreateTable 52
-#define OP_Last 53
-#define OP_IsNull 66 /* same as TK_ISNULL */
-#define OP_IdxRowid 54
-#define OP_MakeIdxRec 55
-#define OP_ShiftRight 78 /* same as TK_RSHIFT */
-#define OP_ResetCount 56
-#define OP_FifoWrite 57
-#define OP_Callback 58
-#define OP_ContextPush 59
-#define OP_DropTrigger 60
-#define OP_DropIndex 63
-#define OP_IdxGE 64
-#define OP_IdxDelete 65
-#define OP_Vacuum 74
-#define OP_MoveLe 86
-#define OP_IfNot 89
-#define OP_DropTable 90
-#define OP_MakeRecord 91
-#define OP_ToBlob 140 /* same as TK_TO_BLOB */
-#define OP_Delete 92
-#define OP_AggFinal 93
-#define OP_ShiftLeft 77 /* same as TK_LSHIFT */
-#define OP_Dup 94
-#define OP_Goto 95
-#define OP_TableLock 96
-#define OP_FifoRead 97
-#define OP_Clear 98
-#define OP_IdxGT 99
-#define OP_MoveLt 100
-#define OP_Le 71 /* same as TK_LE */
-#define OP_VerifyCookie 101
-#define OP_AggStep 102
-#define OP_Pull 103
-#define OP_ToText 139 /* same as TK_TO_TEXT */
+#define OP_Statement 29
+#define OP_CollSeq 30
+#define OP_ContextPop 31
+#define OP_ToText 138 /* same as TK_TO_TEXT */
+#define OP_MemIncr 32
+#define OP_MoveGe 33
+#define OP_Eq 68 /* same as TK_EQ */
+#define OP_ToNumeric 140 /* same as TK_TO_NUMERIC*/
+#define OP_If 34
+#define OP_IfNot 35
+#define OP_ShiftRight 77 /* same as TK_RSHIFT */
+#define OP_Destroy 36
+#define OP_Distinct 37
+#define OP_CreateIndex 38
+#define OP_SetNumColumns 39
#define OP_Not 16 /* same as TK_NOT */
-#define OP_ToReal 143 /* same as TK_TO_REAL */
-#define OP_SetNumColumns 104
-#define OP_AbsValue 105
-#define OP_Transaction 106
-#define OP_VFilter 107
+#define OP_Gt 69 /* same as TK_GT */
+#define OP_ResetCount 40
+#define OP_MakeIdxRec 41
+#define OP_Goto 42
+#define OP_IdxDelete 43
+#define OP_MemMove 44
+#define OP_Found 45
+#define OP_MoveGt 46
+#define OP_IfMemZero 47
+#define OP_MustBeInt 48
+#define OP_Prev 49
+#define OP_MemNull 50
+#define OP_AutoCommit 51
+#define OP_String 52
+#define OP_FifoWrite 53
+#define OP_ToInt 141 /* same as TK_TO_INT */
+#define OP_Return 54
+#define OP_Callback 55
+#define OP_AddImm 56
+#define OP_Function 57
+#define OP_Concat 83 /* same as TK_CONCAT */
+#define OP_NewRowid 58
+#define OP_Blob 59
+#define OP_IsNull 65 /* same as TK_ISNULL */
+#define OP_Next 62
+#define OP_ForceInt 63
+#define OP_ReadCookie 64
+#define OP_Halt 73
+#define OP_Expire 84
+#define OP_Or 60 /* same as TK_OR */
+#define OP_DropIndex 86
+#define OP_IdxInsert 89
+#define OP_ShiftLeft 76 /* same as TK_LSHIFT */
+#define OP_FifoRead 90
+#define OP_Column 91
+#define OP_Int64 92
+#define OP_Gosub 93
+#define OP_IfMemNeg 94
+#define OP_RowData 95
+#define OP_BitOr 75 /* same as TK_BITOR */
+#define OP_MemMax 96
+#define OP_Close 97
+#define OP_ToReal 142 /* same as TK_TO_REAL */
+#define OP_VerifyCookie 98
+#define OP_IfMemPos 99
+#define OP_Null 100
+#define OP_Integer 101
+#define OP_Transaction 102
+#define OP_Divide 81 /* same as TK_SLASH */
+#define OP_IdxLT 103
+#define OP_Delete 104
+#define OP_Rewind 105
+#define OP_Push 106
+#define OP_RealAffinity 107
+#define OP_Clear 108
+#define OP_AggStep 109
+#define OP_Explain 110
+#define OP_Vacuum 111
+#define OP_VDestroy 112
+#define OP_IsUnique 113
+#define OP_VOpen 114
+#define OP_AggFinal 115
+#define OP_OpenWrite 116
#define OP_Negative 85 /* same as TK_UMINUS */
-#define OP_Ne 68 /* same as TK_NE */
-#define OP_VDestroy 108
-#define OP_ContextPop 109
-#define OP_BitOr 76 /* same as TK_BITOR */
-#define OP_Next 110
-#define OP_IdxInsert 111
-#define OP_Distinct 112
-#define OP_Lt 72 /* same as TK_LT */
-#define OP_Insert 113
-#define OP_Destroy 114
-#define OP_ReadCookie 115
-#define OP_ForceInt 116
-#define OP_LoadAnalysis 117
-#define OP_Explain 118
-#define OP_IfMemZero 119
-#define OP_OpenPseudo 120
-#define OP_OpenEphemeral 121
-#define OP_Null 122
-#define OP_Blob 123
-#define OP_Add 79 /* same as TK_PLUS */
-#define OP_MemStore 124
-#define OP_Rewind 125
-#define OP_MoveGe 128
-#define OP_VBegin 129
-#define OP_VUpdate 130
-#define OP_BitNot 87 /* same as TK_BITNOT */
-#define OP_VCreate 131
-#define OP_MemMove 132
-#define OP_MemNull 133
-#define OP_Found 134
-#define OP_NullRow 135
+#define OP_Le 70 /* same as TK_LE */
+#define OP_VNext 117
+#define OP_AbsValue 118
+#define OP_Sort 119
+#define OP_NotFound 120
+#define OP_MoveLe 121
+#define OP_MakeRecord 122
+#define OP_Add 78 /* same as TK_PLUS */
+#define OP_Ne 67 /* same as TK_NE */
+#define OP_Variable 123
+#define OP_CreateTable 124
+#define OP_Insert 127
+#define OP_IdxGE 128
+#define OP_OpenRead 129
+#define OP_IdxRowid 130
+#define OP_ToBlob 139 /* same as TK_TO_BLOB */
+#define OP_VBegin 131
+#define OP_TableLock 132
+#define OP_OpenEphemeral 133
+#define OP_Lt 71 /* same as TK_LT */
+#define OP_Pop 134
/* The following opcode values are never used */
+#define OP_NotUsed_135 135
#define OP_NotUsed_136 136
#define OP_NotUsed_137 137
-#define OP_NotUsed_138 138
/* Opcodes that are guaranteed to never push a value onto the stack
** contain a 1 their corresponding position of the following mask
** set. See the opcodeNoPush() function in vdbeaux.c */
-#define NOPUSH_MASK_0 0xeeb4
-#define NOPUSH_MASK_1 0x796b
-#define NOPUSH_MASK_2 0xfbb7
-#define NOPUSH_MASK_3 0xff24
-#define NOPUSH_MASK_4 0xffff
-#define NOPUSH_MASK_5 0xb6ef
-#define NOPUSH_MASK_6 0xfdfd
-#define NOPUSH_MASK_7 0x33b3
-#define NOPUSH_MASK_8 0xf8cf
+#define NOPUSH_MASK_0 0x5c7a
+#define NOPUSH_MASK_1 0xf777
+#define NOPUSH_MASK_2 0xedaf
+#define NOPUSH_MASK_3 0xf1eb
+#define NOPUSH_MASK_4 0xfffe
+#define NOPUSH_MASK_5 0x62f7
+#define NOPUSH_MASK_6 0xbfcf
+#define NOPUSH_MASK_7 0x83bf
+#define NOPUSH_MASK_8 0x7c7b
#define NOPUSH_MASK_9 0x0000
diff --git a/ext/pdo_sqlite/sqlite/src/os.c b/ext/pdo_sqlite/sqlite/src/os.c
index ec482fe0e..bc65ae32b 100644
--- a/ext/pdo_sqlite/sqlite/src/os.c
+++ b/ext/pdo_sqlite/sqlite/src/os.c
@@ -16,6 +16,7 @@
#define _SQLITE_OS_C_ 1
#include "sqliteInt.h"
#include "os.h"
+#undef _SQLITE_OS_C_
/*
** The following routines are convenience wrappers around methods
@@ -75,6 +76,10 @@ int sqlite3OsLockState(OsFile *id){
int sqlite3OsCheckReservedLock(OsFile *id){
return id->pMethod->xCheckReservedLock(id);
}
+int sqlite3OsSectorSize(OsFile *id){
+ int (*xSectorSize)(OsFile*) = id->pMethod->xSectorSize;
+ return xSectorSize ? xSectorSize(id) : SQLITE_DEFAULT_SECTOR_SIZE;
+}
#ifdef SQLITE_ENABLE_REDEF_IO
/*
diff --git a/ext/pdo_sqlite/sqlite/src/os.h b/ext/pdo_sqlite/sqlite/src/os.h
index 4433f5d02..006ed5e13 100644
--- a/ext/pdo_sqlite/sqlite/src/os.h
+++ b/ext/pdo_sqlite/sqlite/src/os.h
@@ -21,6 +21,18 @@
** Figure out if we are dealing with Unix, Windows, or some other
** operating system.
*/
+#if defined(OS_OTHER)
+# if OS_OTHER==1
+# undef OS_UNIX
+# define OS_UNIX 0
+# undef OS_WIN
+# define OS_WIN 0
+# undef OS_OS2
+# define OS_OS2 0
+# else
+# undef OS_OTHER
+# endif
+#endif
#if !defined(OS_UNIX) && !defined(OS_OTHER)
# define OS_OTHER 0
# ifndef OS_WIN
@@ -74,6 +86,13 @@
#endif
/*
+** The default size of a disk sector
+*/
+#ifndef SQLITE_DEFAULT_SECTOR_SIZE
+# define SQLITE_DEFAULT_SECTOR_SIZE 512
+#endif
+
+/*
** Temporary files are named starting with this prefix followed by 16 random
** alphanumeric characters, and no file extension. They are stored in the
** OS's standard temporary file directory, and are deleted prior to exit.
@@ -81,9 +100,21 @@
** prefix to reflect your program's name, so that if your program exits
** prematurely, old temporary files can be easily identified. This can be done
** using -DTEMP_FILE_PREFIX=myprefix_ on the compiler command line.
+**
+** 2006-10-31: The default prefix used to be "sqlite_". But then
+** Mcafee started using SQLite in their anti-virus product and it
+** started putting files with the "sqlite" name in the c:/temp folder.
+** This annoyed many windows users. Those users would then do a
+** Google search for "sqlite", find the telephone numbers of the
+** developers and call to wake them up at night and complain.
+** For this reason, the default name prefix is changed to be "sqlite"
+** spelled backwards. So the temp files are still identified, but
+** anybody smart enough to figure out the code is also likely smart
+** enough to know that calling the developer will not help get rid
+** of the file.
*/
#ifndef TEMP_FILE_PREFIX
-# define TEMP_FILE_PREFIX "sqlite_"
+# define TEMP_FILE_PREFIX "etilqs_"
#endif
/*
@@ -110,6 +141,9 @@
#define sqlite3OsRealloc sqlite3GenericRealloc
#define sqlite3OsFree sqlite3GenericFree
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
+#define sqlite3OsDlopen sqlite3UnixDlopen
+#define sqlite3OsDlsym sqlite3UnixDlsym
+#define sqlite3OsDlclose sqlite3UnixDlclose
#endif
#if OS_WIN
#define sqlite3OsOpenReadWrite sqlite3WinOpenReadWrite
@@ -132,6 +166,9 @@
#define sqlite3OsRealloc sqlite3GenericRealloc
#define sqlite3OsFree sqlite3GenericFree
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
+#define sqlite3OsDlopen sqlite3WinDlopen
+#define sqlite3OsDlsym sqlite3WinDlsym
+#define sqlite3OsDlclose sqlite3WinDlclose
#endif
#if OS_OS2
#define sqlite3OsOpenReadWrite sqlite3Os2OpenReadWrite
@@ -154,6 +191,9 @@
#define sqlite3OsRealloc sqlite3GenericRealloc
#define sqlite3OsFree sqlite3GenericFree
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
+#define sqlite3OsDlopen sqlite3Os2Dlopen
+#define sqlite3OsDlsym sqlite3Os2Dlsym
+#define sqlite3OsDlclose sqlite3Os2Dlclose
#endif
@@ -195,6 +235,7 @@ struct IoMethod {
int (*xUnlock)(OsFile*, int);
int (*xLockState)(OsFile *id);
int (*xCheckReservedLock)(OsFile *id);
+ int (*xSectorSize)(OsFile *id);
};
/*
@@ -325,6 +366,7 @@ int sqlite3OsFileExists(const char*);
char *sqlite3OsFullPathname(const char*);
int sqlite3OsIsDirWritable(char*);
int sqlite3OsSyncDirectory(const char*);
+int sqlite3OsSectorSize(OsFile *id);
int sqlite3OsTempFileName(char*);
int sqlite3OsRandomSeed(char*);
int sqlite3OsSleep(int ms);
@@ -337,6 +379,9 @@ void *sqlite3OsMalloc(int);
void *sqlite3OsRealloc(void *, int);
void sqlite3OsFree(void *);
int sqlite3OsAllocationSize(void *);
+void *sqlite3OsDlopen(const char*);
+void *sqlite3OsDlsym(void*, const char*);
+int sqlite3OsDlclose(void*);
/*
** If the SQLITE_ENABLE_REDEF_IO macro is defined, then the OS-layer
@@ -381,20 +426,33 @@ struct sqlite3OsVtbl {
void *(*xRealloc)(void *, int);
void (*xFree)(void *);
int (*xAllocationSize)(void *);
+
+ void *(*xDlopen)(const char*);
+ void *(*xDlsym)(void*, const char*);
+ int (*xDlclose)(void*);
};
/* Macro used to comment out routines that do not exists when there is
-** no disk I/O
+** no disk I/O or extension loading
*/
#ifdef SQLITE_OMIT_DISKIO
# define IF_DISKIO(X) 0
#else
# define IF_DISKIO(X) X
#endif
+#ifdef SQLITE_OMIT_LOAD_EXTENSION
+# define IF_DLOPEN(X) 0
+#else
+# define IF_DLOPEN(X) X
+#endif
+
-#ifdef _SQLITE_OS_C_
+#if defined(_SQLITE_OS_C_) || defined(SQLITE_AMALGAMATION)
/*
** The os.c file implements the global virtual function table.
+ ** We have to put this file here because the initializers
+ ** (ex: sqlite3OsRandomSeed) are macros that are about to be
+ ** redefined.
*/
struct sqlite3OsVtbl sqlite3Os = {
IF_DISKIO( sqlite3OsOpenReadWrite ),
@@ -416,7 +474,10 @@ struct sqlite3OsVtbl {
sqlite3OsMalloc,
sqlite3OsRealloc,
sqlite3OsFree,
- sqlite3OsAllocationSize
+ sqlite3OsAllocationSize,
+ IF_DLOPEN( sqlite3OsDlopen ),
+ IF_DLOPEN( sqlite3OsDlsym ),
+ IF_DLOPEN( sqlite3OsDlclose ),
};
#else
/*
diff --git a/ext/pdo_sqlite/sqlite/src/os_common.h b/ext/pdo_sqlite/sqlite/src/os_common.h
index d65c352dd..ba52314ce 100644
--- a/ext/pdo_sqlite/sqlite/src/os_common.h
+++ b/ext/pdo_sqlite/sqlite/src/os_common.h
@@ -38,25 +38,23 @@ unsigned int sqlite3_pending_byte = 0x40000000;
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)
-#define TRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A)
-#define TRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B)
-#define TRACE6(X,Y,Z,A,B,C) if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
-#define TRACE7(X,Y,Z,A,B,C,D) \
+#define OSTRACE1(X) if( sqlite3_os_trace ) sqlite3DebugPrintf(X)
+#define OSTRACE2(X,Y) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y)
+#define OSTRACE3(X,Y,Z) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z)
+#define OSTRACE4(X,Y,Z,A) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A)
+#define OSTRACE5(X,Y,Z,A,B) if( sqlite3_os_trace ) sqlite3DebugPrintf(X,Y,Z,A,B)
+#define OSTRACE6(X,Y,Z,A,B,C) \
+ if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C)
+#define OSTRACE7(X,Y,Z,A,B,C,D) \
if(sqlite3_os_trace) sqlite3DebugPrintf(X,Y,Z,A,B,C,D)
#else
-#define SEEK(X)
-#define TRACE1(X)
-#define TRACE2(X,Y)
-#define TRACE3(X,Y,Z)
-#define TRACE4(X,Y,Z,A)
-#define TRACE5(X,Y,Z,A,B)
-#define TRACE6(X,Y,Z,A,B,C)
-#define TRACE7(X,Y,Z,A,B,C,D)
+#define OSTRACE1(X)
+#define OSTRACE2(X,Y)
+#define OSTRACE3(X,Y,Z)
+#define OSTRACE4(X,Y,Z,A)
+#define OSTRACE5(X,Y,Z,A,B)
+#define OSTRACE6(X,Y,Z,A,B,C)
+#define OSTRACE7(X,Y,Z,A,B,C,D)
#endif
/*
@@ -90,27 +88,32 @@ static unsigned int elapse;
#ifdef SQLITE_TEST
int sqlite3_io_error_hit = 0;
int sqlite3_io_error_pending = 0;
+int sqlite3_io_error_persist = 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; }
+#define SimulateIOError(CODE) \
+ if( sqlite3_io_error_pending || sqlite3_io_error_hit ) \
+ if( sqlite3_io_error_pending-- == 1 \
+ || (sqlite3_io_error_persist && sqlite3_io_error_hit) ) \
+ { local_ioerr(); CODE; }
static void local_ioerr(){
- sqlite3_io_error_hit = 1; /* Really just a place to set a breakpoint */
+ IOTRACE(("IOERR\n"));
+ sqlite3_io_error_hit = 1;
}
-#define SimulateDiskfullError \
+#define SimulateDiskfullError(CODE) \
if( sqlite3_diskfull_pending ){ \
if( sqlite3_diskfull_pending == 1 ){ \
local_ioerr(); \
sqlite3_diskfull = 1; \
- return SQLITE_FULL; \
+ sqlite3_io_error_hit = 1; \
+ CODE; \
}else{ \
sqlite3_diskfull_pending--; \
} \
}
#else
#define SimulateIOError(A)
-#define SimulateDiskfullError
+#define SimulateDiskfullError(A)
#endif
/*
@@ -186,3 +189,10 @@ void sqlite3GenericFree(void *p){
/* Never actually used, but needed for the linker */
int sqlite3GenericAllocationSize(void *p){ return 0; }
#endif
+
+/*
+** The default size of a disk sector
+*/
+#ifndef PAGER_SECTOR_SIZE
+# define PAGER_SECTOR_SIZE 512
+#endif
diff --git a/ext/pdo_sqlite/sqlite/src/os_unix.c b/ext/pdo_sqlite/sqlite/src/os_unix.c
index 5b58cb7aa..281348b79 100644
--- a/ext/pdo_sqlite/sqlite/src/os_unix.c
+++ b/ext/pdo_sqlite/sqlite/src/os_unix.c
@@ -16,6 +16,8 @@
#include "os.h"
#if OS_UNIX /* This file is used on unix only */
+/* #define SQLITE_ENABLE_LOCKING_STYLE 0 */
+
/*
** These #defines should enable >2GB file support on Posix if the
** underlying operating system supports it. If the OS lacks
@@ -47,12 +49,20 @@
#include <time.h>
#include <sys/time.h>
#include <errno.h>
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
/*
** If we are to be thread-safe, include the pthreads header and define
** the SQLITE_UNIX_THREADS macro.
*/
-#if defined(THREADSAFE) && THREADSAFE
+#ifndef THREADSAFE
+# define THREADSAFE 1
+#endif
+#if THREADSAFE
# include <pthread.h>
# define SQLITE_UNIX_THREADS 1
#endif
@@ -75,6 +85,9 @@ 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 */
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+ void *lockingContext; /* Locking style specific state */
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
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 */
@@ -346,6 +359,32 @@ static Hash lockHash = {SQLITE_HASH_BINARY, 0, 0, 0,
static Hash openHash = {SQLITE_HASH_BINARY, 0, 0, 0,
sqlite3ThreadSafeMalloc, sqlite3ThreadSafeFree, 0, 0};
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+/*
+** The locking styles are associated with the different file locking
+** capabilities supported by different file systems.
+**
+** POSIX locking style fully supports shared and exclusive byte-range locks
+** ADP locking only supports exclusive byte-range locks
+** FLOCK only supports a single file-global exclusive lock
+** DOTLOCK isn't a true locking style, it refers to the use of a special
+** file named the same as the database file with a '.lock' extension, this
+** can be used on file systems that do not offer any reliable file locking
+** NO locking means that no locking will be attempted, this is only used for
+** read-only file systems currently
+** UNSUPPORTED means that no locking will be attempted, this is only used for
+** file systems that are known to be unsupported
+*/
+typedef enum {
+ posixLockingStyle = 0, /* standard posix-advisory locks */
+ afpLockingStyle, /* use afp locks */
+ flockLockingStyle, /* use flock() */
+ dotlockLockingStyle, /* use <file>.lock files */
+ noLockingStyle, /* useful for read-only file system */
+ unsupportedLockingStyle /* indicates unsupported file system */
+} sqlite3LockingStyle;
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
#ifdef SQLITE_UNIX_THREADS
/*
** This variable records whether or not threads can override each others
@@ -421,7 +460,7 @@ static int lockTrace(int fd, int op, struct flock *p){
sqlite3DebugPrintf("fcntl %d %d %s %s %d %d %d %d\n",
threadid, fd, zOpName, zType, (int)p->l_start, (int)p->l_len,
(int)p->l_pid, s);
- if( s && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
+ if( s==(-1) && op==F_SETLK && (p->l_type==F_RDLCK || p->l_type==F_WRLCK) ){
struct flock l2;
l2 = *p;
fcntl(fd, F_GETLK, &l2);
@@ -490,6 +529,8 @@ static void testThreadLockingBehavior(int fd_orig){
*/
static void releaseLockInfo(struct lockInfo *pLock){
assert( sqlite3OsInMutex(1) );
+ if (pLock == NULL)
+ return;
pLock->nRef--;
if( pLock->nRef==0 ){
sqlite3HashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
@@ -502,6 +543,8 @@ static void releaseLockInfo(struct lockInfo *pLock){
*/
static void releaseOpenCnt(struct openCnt *pOpen){
assert( sqlite3OsInMutex(1) );
+ if (pOpen == NULL)
+ return;
pOpen->nRef--;
if( pOpen->nRef==0 ){
sqlite3HashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0);
@@ -510,6 +553,77 @@ static void releaseOpenCnt(struct openCnt *pOpen){
}
}
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+/*
+** Tests a byte-range locking query to see if byte range locks are
+** supported, if not we fall back to dotlockLockingStyle.
+*/
+static sqlite3LockingStyle sqlite3TestLockingStyle(const char *filePath,
+ int fd) {
+ /* test byte-range lock using fcntl */
+ struct flock lockInfo;
+
+ lockInfo.l_len = 1;
+ lockInfo.l_start = 0;
+ lockInfo.l_whence = SEEK_SET;
+ lockInfo.l_type = F_RDLCK;
+
+ if (fcntl(fd, F_GETLK, &lockInfo) != -1) {
+ return posixLockingStyle;
+ }
+
+ /* testing for flock can give false positives. So if if the above test
+ ** fails, then we fall back to using dot-lock style locking.
+ */
+ return dotlockLockingStyle;
+}
+
+/*
+** Examines the f_fstypename entry in the statfs structure as returned by
+** stat() for the file system hosting the database file, assigns the
+** appropriate locking style based on it's value. These values and
+** assignments are based on Darwin/OSX behavior and have not been tested on
+** other systems.
+*/
+static sqlite3LockingStyle sqlite3DetectLockingStyle(const char *filePath,
+ int fd) {
+
+#ifdef SQLITE_FIXED_LOCKING_STYLE
+ return (sqlite3LockingStyle)SQLITE_FIXED_LOCKING_STYLE;
+#else
+ struct statfs fsInfo;
+
+ if (statfs(filePath, &fsInfo) == -1)
+ return sqlite3TestLockingStyle(filePath, fd);
+
+ if (fsInfo.f_flags & MNT_RDONLY)
+ return noLockingStyle;
+
+ if( (!strcmp(fsInfo.f_fstypename, "hfs")) ||
+ (!strcmp(fsInfo.f_fstypename, "ufs")) )
+ return posixLockingStyle;
+
+ if(!strcmp(fsInfo.f_fstypename, "afpfs"))
+ return afpLockingStyle;
+
+ if(!strcmp(fsInfo.f_fstypename, "nfs"))
+ return sqlite3TestLockingStyle(filePath, fd);
+
+ if(!strcmp(fsInfo.f_fstypename, "smbfs"))
+ return flockLockingStyle;
+
+ if(!strcmp(fsInfo.f_fstypename, "msdos"))
+ return dotlockLockingStyle;
+
+ if(!strcmp(fsInfo.f_fstypename, "webdav"))
+ return unsupportedLockingStyle;
+
+ return sqlite3TestLockingStyle(filePath, fd);
+#endif // SQLITE_FIXED_LOCKING_STYLE
+}
+
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
/*
** Given a file descriptor, locate lockInfo and openCnt structures that
** describes that file descriptor. Create new ones if necessary. The
@@ -642,21 +756,26 @@ static int transferOwnership(unixFile *pFile){
hSelf = pthread_self();
if( pthread_equal(pFile->tid, hSelf) ){
/* We are still in the same thread */
- TRACE1("No-transfer, same thread\n");
+ OSTRACE1("No-transfer, same thread\n");
return SQLITE_OK;
}
if( pFile->locktype!=NO_LOCK ){
/* We cannot change ownership while we are holding a lock! */
return SQLITE_MISUSE;
}
- TRACE4("Transfer ownership of %d from %d to %d\n", pFile->h,pFile->tid,hSelf);
+ OSTRACE4("Transfer ownership of %d from %d to %d\n",
+ pFile->h, pFile->tid, hSelf);
pFile->tid = hSelf;
- releaseLockInfo(pFile->pLock);
- rc = findLockInfo(pFile->h, &pFile->pLock, 0);
- TRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h,
- locktypeName(pFile->locktype),
- locktypeName(pFile->pLock->locktype), pFile->pLock->cnt);
- return rc;
+ if (pFile->pLock != NULL) {
+ releaseLockInfo(pFile->pLock);
+ rc = findLockInfo(pFile->h, &pFile->pLock, 0);
+ OSTRACE5("LOCK %d is now %s(%s,%d)\n", pFile->h,
+ locktypeName(pFile->locktype),
+ locktypeName(pFile->pLock->locktype), pFile->pLock->cnt);
+ return rc;
+ } else {
+ return SQLITE_OK;
+ }
}
#else
/* On single-threaded builds, ownership transfer is a no-op */
@@ -667,6 +786,7 @@ static int transferOwnership(unixFile *pFile){
** Delete the named file
*/
int sqlite3UnixDelete(const char *zFilename){
+ SimulateIOError(return SQLITE_IOERR_DELETE);
unlink(zFilename);
return SQLITE_OK;
}
@@ -679,7 +799,12 @@ int sqlite3UnixFileExists(const char *zFilename){
}
/* Forward declaration */
-static int allocateUnixFile(unixFile *pInit, OsFile **pId);
+static int allocateUnixFile(
+ int h, /* File descriptor of the open file */
+ OsFile **pId, /* Write the real file descriptor here */
+ const char *zFilename, /* Name of the file being opened */
+ int delFlag /* If true, make sure the file deletes on close */
+);
/*
** Attempt to open a file for both reading and writing. If that
@@ -699,36 +824,27 @@ int sqlite3UnixOpenReadWrite(
OsFile **pId,
int *pReadonly
){
- int rc;
- unixFile f;
-
+ int h;
+
CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadWrite, zFilename, pId, pReadonly);
assert( 0==*pId );
- f.h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY,
- SQLITE_DEFAULT_FILE_PERMISSIONS);
- if( f.h<0 ){
+ h = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY,
+ SQLITE_DEFAULT_FILE_PERMISSIONS);
+ if( h<0 ){
#ifdef EISDIR
if( errno==EISDIR ){
return SQLITE_CANTOPEN;
}
#endif
- f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
- if( f.h<0 ){
+ h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
+ if( h<0 ){
return SQLITE_CANTOPEN;
}
*pReadonly = 1;
}else{
*pReadonly = 0;
}
- sqlite3OsEnterMutex();
- rc = findLockInfo(f.h, &f.pLock, &f.pOpen);
- sqlite3OsLeaveMutex();
- if( rc ){
- close(f.h);
- return SQLITE_NOMEM;
- }
- TRACE3("OPEN %-3d %s\n", f.h, zFilename);
- return allocateUnixFile(&f, pId);
+ return allocateUnixFile(h, pId, zFilename, 0);
}
@@ -747,30 +863,17 @@ int sqlite3UnixOpenReadWrite(
** On failure, return SQLITE_CANTOPEN.
*/
int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
- int rc;
- unixFile f;
+ int h;
CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag);
assert( 0==*pId );
- f.h = open(zFilename,
+ h = open(zFilename,
O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY,
- SQLITE_DEFAULT_FILE_PERMISSIONS);
- if( f.h<0 ){
+ delFlag ? 0600 : SQLITE_DEFAULT_FILE_PERMISSIONS);
+ if( h<0 ){
return SQLITE_CANTOPEN;
}
- sqlite3OsEnterMutex();
- rc = findLockInfo(f.h, &f.pLock, &f.pOpen);
- sqlite3OsLeaveMutex();
- if( rc ){
- close(f.h);
- unlink(zFilename);
- return SQLITE_NOMEM;
- }
- if( delFlag ){
- unlink(zFilename);
- }
- TRACE3("OPEN-EX %-3d %s\n", f.h, zFilename);
- return allocateUnixFile(&f, pId);
+ return allocateUnixFile(h, pId, zFilename, delFlag);
}
/*
@@ -781,24 +884,15 @@ int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
** On failure, return SQLITE_CANTOPEN.
*/
int sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){
- int rc;
- unixFile f;
-
+ int h;
+
CRASH_TEST_OVERRIDE(sqlite3CrashOpenReadOnly, zFilename, pId, 0);
assert( 0==*pId );
- f.h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
- if( f.h<0 ){
+ h = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
+ if( h<0 ){
return SQLITE_CANTOPEN;
}
- sqlite3OsEnterMutex();
- rc = findLockInfo(f.h, &f.pLock, &f.pOpen);
- sqlite3OsLeaveMutex();
- if( rc ){
- close(f.h);
- return SQLITE_NOMEM;
- }
- TRACE3("OPEN-RO %-3d %s\n", f.h, zFilename);
- return allocateUnixFile(&f, pId);
+ return allocateUnixFile(h, pId, zFilename, 0);
}
/*
@@ -810,6 +904,9 @@ int sqlite3UnixOpenReadOnly(const char *zFilename, OsFile **pId){
** This routine is only meaningful for Unix. It is a no-op under
** windows since windows does not support hard links.
**
+** If FULL_FSYNC is enabled, this function is not longer useful,
+** a FULL_FSYNC sync applies to all pending disk operations.
+**
** On success, a handle for a previously open file at *id is
** updated with the new directory file descriptor and SQLITE_OK is
** returned.
@@ -822,31 +919,18 @@ static int unixOpenDirectory(
const char *zDirname
){
unixFile *pFile = (unixFile*)id;
- if( pFile==0 ){
- /* Do not open the directory if the corresponding file is not already
- ** open. */
- return SQLITE_CANTOPEN;
- }
+ assert( pFile!=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", pFile->dirfd, zDirname);
+ OSTRACE3("OPENDIR %-3d %s\n", pFile->dirfd, zDirname);
return SQLITE_OK;
}
/*
-** If the following global variable points to a string which is the
-** name of a directory, then that directory will be used to store
-** temporary files.
-**
-** See also the "PRAGMA temp_store_directory" SQL command.
-*/
-char *sqlite3_temp_directory = 0;
-
-/*
** Create a temporary file name in zBuf. zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
*/
@@ -908,12 +992,24 @@ int sqlite3UnixIsDirWritable(char *zBuf){
*/
static int seekAndRead(unixFile *id, void *pBuf, int cnt){
int got;
-#ifdef USE_PREAD
+ i64 newOffset;
+ TIMER_START;
+#if defined(USE_PREAD)
got = pread(id->h, pBuf, cnt, id->offset);
+ SimulateIOError( got = -1 );
+#elif defined(USE_PREAD64)
+ got = pread64(id->h, pBuf, cnt, id->offset);
+ SimulateIOError( got = -1 );
#else
- lseek(id->h, id->offset, SEEK_SET);
+ newOffset = lseek(id->h, id->offset, SEEK_SET);
+ SimulateIOError( newOffset-- );
+ if( newOffset!=id->offset ){
+ return -1;
+ }
got = read(id->h, pBuf, cnt);
#endif
+ TIMER_END;
+ OSTRACE5("READ %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED);
if( got>0 ){
id->offset += got;
}
@@ -928,18 +1024,14 @@ static int seekAndRead(unixFile *id, void *pBuf, int cnt){
static int unixRead(OsFile *id, void *pBuf, int amt){
int got;
assert( id );
- SimulateIOError(SQLITE_IOERR);
- TIMER_START;
got = seekAndRead((unixFile*)id, pBuf, amt);
- TIMER_END;
- 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 if( got<0 ){
+ return SQLITE_IOERR_READ;
}else{
- return SQLITE_IOERR;
+ memset(&((char*)pBuf)[got], 0, amt-got);
+ return SQLITE_IOERR_SHORT_READ;
}
}
@@ -949,12 +1041,21 @@ static int unixRead(OsFile *id, void *pBuf, int amt){
*/
static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){
int got;
-#ifdef USE_PREAD
+ i64 newOffset;
+ TIMER_START;
+#if defined(USE_PREAD)
got = pwrite(id->h, pBuf, cnt, id->offset);
+#elif defined(USE_PREAD64)
+ got = pwrite64(id->h, pBuf, cnt, id->offset);
#else
- lseek(id->h, id->offset, SEEK_SET);
+ newOffset = lseek(id->h, id->offset, SEEK_SET);
+ if( newOffset!=id->offset ){
+ return -1;
+ }
got = write(id->h, pBuf, cnt);
#endif
+ TIMER_END;
+ OSTRACE5("WRITE %-3d %5d %7lld %d\n", id->h, got, id->offset, TIMER_ELAPSED);
if( got>0 ){
id->offset += got;
}
@@ -970,19 +1071,18 @@ static int unixWrite(OsFile *id, const void *pBuf, int amt){
int wrote = 0;
assert( id );
assert( amt>0 );
- SimulateIOError(SQLITE_IOERR);
- SimulateDiskfullError;
- TIMER_START;
while( amt>0 && (wrote = seekAndWrite((unixFile*)id, pBuf, amt))>0 ){
amt -= wrote;
pBuf = &((char*)pBuf)[wrote];
}
- TIMER_END;
- TRACE5("WRITE %-3d %5d %7d %d\n", ((unixFile*)id)->h, wrote,
- last_page, TIMER_ELAPSED);
- SEEK(0);
+ SimulateIOError(( wrote=(-1), amt=1 ));
+ SimulateDiskfullError(( wrote=0, amt=1 ));
if( amt>0 ){
- return SQLITE_FULL;
+ if( wrote<0 ){
+ return SQLITE_IOERR_WRITE;
+ }else{
+ return SQLITE_FULL;
+ }
}
return SQLITE_OK;
}
@@ -992,9 +1092,8 @@ static int unixWrite(OsFile *id, const void *pBuf, int amt){
*/
static int unixSeek(OsFile *id, i64 offset){
assert( id );
- SEEK(offset/1024 + 1);
#ifdef SQLITE_TEST
- if( offset ) SimulateDiskfullError
+ if( offset ) SimulateDiskfullError(return SQLITE_FULL);
#endif
((unixFile*)id)->offset = offset;
return SQLITE_OK;
@@ -1065,16 +1164,23 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
}else{
rc = 1;
}
- /* If the FULLSYNC failed, try to do a normal fsync() */
+ /* If the FULLFSYNC failed, fall back to attempting an fsync().
+ * It shouldn't be possible for fullfsync to fail on the local
+ * file system (on OSX), so failure indicates that FULLFSYNC
+ * isn't supported for this file system. So, attempt an fsync
+ * and (for now) ignore the overhead of a superfluous fcntl call.
+ * It'd be better to detect fullfsync support once and avoid
+ * the fcntl call every time sync is called.
+ */
if( rc ) rc = fsync(fd);
-#else /* if !defined(F_FULLSYNC) */
+#else
if( dataOnly ){
rc = fdatasync(fd);
}else{
rc = fsync(fd);
}
-#endif /* defined(F_FULLFSYNC) */
+#endif /* HAVE_FULLFSYNC */
#endif /* defined(SQLITE_NO_SYNC) */
return rc;
@@ -1096,15 +1202,17 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
** will not roll back - possibly leading to database corruption.
*/
static int unixSync(OsFile *id, int dataOnly){
+ int rc;
unixFile *pFile = (unixFile*)id;
assert( pFile );
- SimulateIOError(SQLITE_IOERR);
- TRACE2("SYNC %-3d\n", pFile->h);
- if( full_fsync(pFile->h, pFile->fullSync, dataOnly) ){
- return SQLITE_IOERR;
+ OSTRACE2("SYNC %-3d\n", pFile->h);
+ rc = full_fsync(pFile->h, pFile->fullSync, dataOnly);
+ SimulateIOError( rc=1 );
+ if( rc ){
+ return SQLITE_IOERR_FSYNC;
}
if( pFile->dirfd>=0 ){
- TRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
+ OSTRACE4("DIRSYNC %-3d (have_fullfsync=%d fullsync=%d)\n", pFile->dirfd,
HAVE_FULLFSYNC, pFile->fullSync);
#ifndef SQLITE_DISABLE_DIRSYNC
/* The directory sync is only attempted if full_fsync is
@@ -1141,15 +1249,19 @@ int sqlite3UnixSyncDirectory(const char *zDirname){
#else
int fd;
int r;
- SimulateIOError(SQLITE_IOERR);
fd = open(zDirname, O_RDONLY|O_BINARY, 0);
- TRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname);
+ OSTRACE3("DIRSYNC %-3d (%s)\n", fd, zDirname);
if( fd<0 ){
return SQLITE_CANTOPEN;
}
r = fsync(fd);
close(fd);
- return ((r==0)?SQLITE_OK:SQLITE_IOERR);
+ SimulateIOError( r=1 );
+ if( r ){
+ return SQLITE_IOERR_DIR_FSYNC;
+ }else{
+ return SQLITE_OK;
+ }
#endif
}
@@ -1157,20 +1269,28 @@ int sqlite3UnixSyncDirectory(const char *zDirname){
** Truncate an open file to a specified size
*/
static int unixTruncate(OsFile *id, i64 nByte){
+ int rc;
assert( id );
- SimulateIOError(SQLITE_IOERR);
- return ftruncate(((unixFile*)id)->h, nByte)==0 ? SQLITE_OK : SQLITE_IOERR;
+ rc = ftruncate(((unixFile*)id)->h, nByte);
+ SimulateIOError( rc=1 );
+ if( rc ){
+ return SQLITE_IOERR_TRUNCATE;
+ }else{
+ return SQLITE_OK;
+ }
}
/*
** Determine the current size of a file in bytes
*/
static int unixFileSize(OsFile *id, i64 *pSize){
+ int rc;
struct stat buf;
assert( id );
- SimulateIOError(SQLITE_IOERR);
- if( fstat(((unixFile*)id)->h, &buf)!=0 ){
- return SQLITE_IOERR;
+ rc = fstat(((unixFile*)id)->h, &buf);
+ SimulateIOError( rc=1 );
+ if( rc!=0 ){
+ return SQLITE_IOERR_FSTAT;
}
*pSize = buf.st_size;
return SQLITE_OK;
@@ -1209,7 +1329,7 @@ static int unixCheckReservedLock(OsFile *id){
}
sqlite3OsLeaveMutex();
- TRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
+ OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
return r;
}
@@ -1284,7 +1404,7 @@ static int unixLock(OsFile *id, int locktype){
int s;
assert( pFile );
- TRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h,
+ OSTRACE7("LOCK %d %s was %s(%s,%d) pid=%d\n", pFile->h,
locktypeName(locktype), locktypeName(pFile->locktype),
locktypeName(pLock->locktype), pLock->cnt , getpid());
@@ -1293,7 +1413,7 @@ static int unixLock(OsFile *id, int locktype){
** sqlite3OsEnterMutex() hasn't been called yet.
*/
if( pFile->locktype>=locktype ){
- TRACE3("LOCK %d %s ok (already held)\n", pFile->h,
+ OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h,
locktypeName(locktype));
return SQLITE_OK;
}
@@ -1356,7 +1476,7 @@ static int unixLock(OsFile *id, int locktype){
lock.l_type = (locktype==SHARED_LOCK?F_RDLCK:F_WRLCK);
lock.l_start = PENDING_BYTE;
s = fcntl(pFile->h, F_SETLK, &lock);
- if( s ){
+ if( s==(-1) ){
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
goto end_lock;
}
@@ -1380,10 +1500,10 @@ static int unixLock(OsFile *id, int locktype){
lock.l_len = 1L;
lock.l_type = F_UNLCK;
if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
- rc = SQLITE_IOERR; /* This should never happen */
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
goto end_lock;
}
- if( s ){
+ if( s==(-1) ){
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
}else{
pFile->locktype = SHARED_LOCK;
@@ -1413,7 +1533,7 @@ static int unixLock(OsFile *id, int locktype){
assert(0);
}
s = fcntl(pFile->h, F_SETLK, &lock);
- if( s ){
+ if( s==(-1) ){
rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY;
}
}
@@ -1428,7 +1548,7 @@ static int unixLock(OsFile *id, int locktype){
end_lock:
sqlite3OsLeaveMutex();
- TRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
+ OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
rc==SQLITE_OK ? "ok" : "failed");
return rc;
}
@@ -1447,7 +1567,7 @@ static int unixUnlock(OsFile *id, int locktype){
unixFile *pFile = (unixFile*)id;
assert( pFile );
- TRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype,
+ OSTRACE7("UNLOCK %d %d was %d(%d,%d) pid=%d\n", pFile->h, locktype,
pFile->locktype, pFile->pLock->locktype, pFile->pLock->cnt, getpid());
assert( locktype<=SHARED_LOCK );
@@ -1467,19 +1587,19 @@ static int unixUnlock(OsFile *id, int locktype){
lock.l_whence = SEEK_SET;
lock.l_start = SHARED_FIRST;
lock.l_len = SHARED_SIZE;
- if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){
+ if( fcntl(pFile->h, F_SETLK, &lock)==(-1) ){
/* This should never happen */
- rc = SQLITE_IOERR;
+ rc = SQLITE_IOERR_RDLOCK;
}
}
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(pFile->h, F_SETLK, &lock)==0 ){
+ if( fcntl(pFile->h, F_SETLK, &lock)!=(-1) ){
pLock->locktype = SHARED_LOCK;
}else{
- rc = SQLITE_IOERR; /* This should never happen */
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
}
}
if( locktype==NO_LOCK ){
@@ -1494,10 +1614,10 @@ static int unixUnlock(OsFile *id, int locktype){
lock.l_type = F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = lock.l_len = 0L;
- if( fcntl(pFile->h, F_SETLK, &lock)==0 ){
+ if( fcntl(pFile->h, F_SETLK, &lock)!=(-1) ){
pLock->locktype = NO_LOCK;
}else{
- rc = SQLITE_IOERR; /* This should never happen */
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
}
}
@@ -1560,13 +1680,588 @@ static int unixClose(OsFile **pId){
sqlite3OsLeaveMutex();
id->isOpen = 0;
- TRACE2("CLOSE %-3d\n", id->h);
+ OSTRACE2("CLOSE %-3d\n", id->h);
OpenCounter(-1);
sqlite3ThreadSafeFree(id);
*pId = 0;
return SQLITE_OK;
}
+
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+#pragma mark AFP Support
+
+/*
+ ** The afpLockingContext structure contains all afp lock specific state
+ */
+typedef struct afpLockingContext afpLockingContext;
+struct afpLockingContext {
+ unsigned long long sharedLockByte;
+ char *filePath;
+};
+
+struct ByteRangeLockPB2
+{
+ unsigned long long offset; /* offset to first byte to lock */
+ unsigned long long length; /* nbr of bytes to lock */
+ unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */
+ unsigned char unLockFlag; /* 1 = unlock, 0 = lock */
+ unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */
+ int fd; /* file desc to assoc this lock with */
+};
+
+#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2)
+
+/* return 0 on success, 1 on failure. To match the behavior of the
+ normal posix file locking (used in unixLock for example), we should
+ provide 'richer' return codes - specifically to differentiate between
+ 'file busy' and 'file system error' results */
+static int _AFPFSSetLock(const char *path, int fd, unsigned long long offset,
+ unsigned long long length, int setLockFlag)
+{
+ struct ByteRangeLockPB2 pb;
+ int err;
+
+ pb.unLockFlag = setLockFlag ? 0 : 1;
+ pb.startEndFlag = 0;
+ pb.offset = offset;
+ pb.length = length;
+ pb.fd = fd;
+ OSTRACE5("AFPLOCK setting lock %s for %d in range %llx:%llx\n",
+ (setLockFlag?"ON":"OFF"), fd, offset, length);
+ err = fsctl(path, afpfsByteRangeLock2FSCTL, &pb, 0);
+ if ( err==-1 ) {
+ OSTRACE4("AFPLOCK failed to fsctl() '%s' %d %s\n", path, errno,
+ strerror(errno));
+ return 1; // error
+ } else {
+ return 0;
+ }
+}
+
+/*
+ ** This routine checks if there is a RESERVED lock held on the specified
+ ** file by this or any other process. If such a lock is held, return
+ ** non-zero. If the file is unlocked or holds only SHARED locks, then
+ ** return zero.
+ */
+static int afpUnixCheckReservedLock(OsFile *id){
+ int r = 0;
+ unixFile *pFile = (unixFile*)id;
+
+ assert( pFile );
+ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+
+ /* Check if a thread in this process holds such a lock */
+ if( pFile->locktype>SHARED_LOCK ){
+ r = 1;
+ }
+
+ /* Otherwise see if some other process holds it.
+ */
+ if ( !r ) {
+ // lock the byte
+ int failed = _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1,1);
+ if (failed) {
+ /* if we failed to get the lock then someone else must have it */
+ r = 1;
+ } else {
+ /* if we succeeded in taking the reserved lock, unlock it to restore
+ ** the original state */
+ _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0);
+ }
+ }
+ OSTRACE3("TEST WR-LOCK %d %d\n", pFile->h, r);
+
+ return r;
+}
+
+/* AFP-style locking following the behavior of unixLock, see the unixLock
+** function comments for details of lock management. */
+static int afpUnixLock(OsFile *id, int locktype)
+{
+ int rc = SQLITE_OK;
+ unixFile *pFile = (unixFile*)id;
+ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+ int gotPendingLock = 0;
+
+ assert( pFile );
+ OSTRACE5("LOCK %d %s was %s pid=%d\n", pFile->h,
+ locktypeName(locktype), locktypeName(pFile->locktype), getpid());
+ /* If there is already a lock of this type or more restrictive on the
+ ** OsFile, do nothing. Don't use the afp_end_lock: exit path, as
+ ** sqlite3OsEnterMutex() hasn't been called yet.
+ */
+ if( pFile->locktype>=locktype ){
+ OSTRACE3("LOCK %d %s ok (already held)\n", pFile->h,
+ locktypeName(locktype));
+ return SQLITE_OK;
+ }
+
+ /* Make sure the locking sequence is correct
+ */
+ assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK );
+ assert( locktype!=PENDING_LOCK );
+ assert( locktype!=RESERVED_LOCK || pFile->locktype==SHARED_LOCK );
+
+ /* This mutex is needed because pFile->pLock is shared across threads
+ */
+ sqlite3OsEnterMutex();
+
+ /* Make sure the current thread owns the pFile.
+ */
+ rc = transferOwnership(pFile);
+ if( rc!=SQLITE_OK ){
+ sqlite3OsLeaveMutex();
+ return rc;
+ }
+
+ /* 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 && pFile->locktype<PENDING_LOCK)
+ ){
+ int failed = _AFPFSSetLock(context->filePath, pFile->h,
+ PENDING_BYTE, 1, 1);
+ if (failed) {
+ rc = SQLITE_BUSY;
+ goto afp_end_lock;
+ }
+ }
+
+ /* If control gets to this point, then actually go ahead and make
+ ** operating system calls for the specified lock.
+ */
+ if( locktype==SHARED_LOCK ){
+ int lk, failed;
+ int tries = 0;
+
+ /* Now get the read-lock */
+ /* note that the quality of the randomness doesn't matter that much */
+ lk = random();
+ context->sharedLockByte = (lk & 0x7fffffff)%(SHARED_SIZE - 1);
+ failed = _AFPFSSetLock(context->filePath, pFile->h,
+ SHARED_FIRST+context->sharedLockByte, 1, 1);
+
+ /* Drop the temporary PENDING lock */
+ if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)) {
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
+ goto afp_end_lock;
+ }
+
+ if( failed ){
+ rc = SQLITE_BUSY;
+ } else {
+ pFile->locktype = SHARED_LOCK;
+ }
+ }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.
+ */
+ int failed = 0;
+ assert( 0!=pFile->locktype );
+ if (locktype >= RESERVED_LOCK && pFile->locktype < RESERVED_LOCK) {
+ /* Acquire a RESERVED lock */
+ failed = _AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1,1);
+ }
+ if (!failed && locktype == EXCLUSIVE_LOCK) {
+ /* Acquire an EXCLUSIVE lock */
+
+ /* Remove the shared lock before trying the range. we'll need to
+ ** reestablish the shared lock if we can't get the afpUnixUnlock
+ */
+ if (!_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST +
+ context->sharedLockByte, 1, 0)) {
+ /* now attemmpt to get the exclusive lock range */
+ failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST,
+ SHARED_SIZE, 1);
+ if (failed && _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST +
+ context->sharedLockByte, 1, 1)) {
+ rc = SQLITE_IOERR_RDLOCK; /* this should never happen */
+ }
+ } else {
+ /* */
+ rc = SQLITE_IOERR_UNLOCK; /* this should never happen */
+ }
+ }
+ if( failed && rc == SQLITE_OK){
+ rc = SQLITE_BUSY;
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ pFile->locktype = locktype;
+ }else if( locktype==EXCLUSIVE_LOCK ){
+ pFile->locktype = PENDING_LOCK;
+ }
+
+afp_end_lock:
+ sqlite3OsLeaveMutex();
+ OSTRACE4("LOCK %d %s %s\n", pFile->h, locktypeName(locktype),
+ rc==SQLITE_OK ? "ok" : "failed");
+ return rc;
+}
+
+/*
+ ** 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.
+ */
+static int afpUnixUnlock(OsFile *id, int locktype) {
+ struct flock lock;
+ int rc = SQLITE_OK;
+ unixFile *pFile = (unixFile*)id;
+ afpLockingContext *context = (afpLockingContext *) pFile->lockingContext;
+
+ assert( pFile );
+ OSTRACE5("UNLOCK %d %d was %d pid=%d\n", pFile->h, locktype,
+ pFile->locktype, getpid());
+
+ assert( locktype<=SHARED_LOCK );
+ if( pFile->locktype<=locktype ){
+ return SQLITE_OK;
+ }
+ if( CHECK_THREADID(pFile) ){
+ return SQLITE_MISUSE;
+ }
+ sqlite3OsEnterMutex();
+ if( pFile->locktype>SHARED_LOCK ){
+ if( locktype==SHARED_LOCK ){
+ int failed = 0;
+
+ /* unlock the exclusive range - then re-establish the shared lock */
+ if (pFile->locktype==EXCLUSIVE_LOCK) {
+ failed = _AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST,
+ SHARED_SIZE, 0);
+ if (!failed) {
+ /* successfully removed the exclusive lock */
+ if (_AFPFSSetLock(context->filePath, pFile->h, SHARED_FIRST+
+ context->sharedLockByte, 1, 1)) {
+ /* failed to re-establish our shared lock */
+ rc = SQLITE_IOERR_RDLOCK; /* This should never happen */
+ }
+ } else {
+ /* This should never happen - failed to unlock the exclusive range */
+ rc = SQLITE_IOERR_UNLOCK;
+ }
+ }
+ }
+ if (rc == SQLITE_OK && pFile->locktype>=PENDING_LOCK) {
+ if (_AFPFSSetLock(context->filePath, pFile->h, PENDING_BYTE, 1, 0)){
+ /* failed to release the pending lock */
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
+ }
+ }
+ if (rc == SQLITE_OK && pFile->locktype>=RESERVED_LOCK) {
+ if (_AFPFSSetLock(context->filePath, pFile->h, RESERVED_BYTE, 1, 0)) {
+ /* failed to release the reserved lock */
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
+ }
+ }
+ }
+ if( locktype==NO_LOCK ){
+ int failed = _AFPFSSetLock(context->filePath, pFile->h,
+ SHARED_FIRST + context->sharedLockByte, 1, 0);
+ if (failed) {
+ rc = SQLITE_IOERR_UNLOCK; /* This should never happen */
+ }
+ }
+ if (rc == SQLITE_OK)
+ pFile->locktype = locktype;
+ sqlite3OsLeaveMutex();
+ return rc;
+}
+
+/*
+ ** Close a file & cleanup AFP specific locking context
+ */
+static int afpUnixClose(OsFile **pId) {
+ unixFile *id = (unixFile*)*pId;
+
+ if( !id ) return SQLITE_OK;
+ afpUnixUnlock(*pId, NO_LOCK);
+ /* free the AFP locking structure */
+ if (id->lockingContext != NULL) {
+ if (((afpLockingContext *)id->lockingContext)->filePath != NULL)
+ sqlite3ThreadSafeFree(((afpLockingContext*)id->lockingContext)->filePath);
+ sqlite3ThreadSafeFree(id->lockingContext);
+ }
+
+ if( id->dirfd>=0 ) close(id->dirfd);
+ id->dirfd = -1;
+ close(id->h);
+ id->isOpen = 0;
+ OSTRACE2("CLOSE %-3d\n", id->h);
+ OpenCounter(-1);
+ sqlite3ThreadSafeFree(id);
+ *pId = 0;
+ return SQLITE_OK;
+}
+
+
+#pragma mark flock() style locking
+
+/*
+ ** The flockLockingContext is not used
+ */
+typedef void flockLockingContext;
+
+static int flockUnixCheckReservedLock(OsFile *id) {
+ unixFile *pFile = (unixFile*)id;
+
+ if (pFile->locktype == RESERVED_LOCK) {
+ return 1; // already have a reserved lock
+ } else {
+ // attempt to get the lock
+ int rc = flock(pFile->h, LOCK_EX | LOCK_NB);
+ if (!rc) {
+ // got the lock, unlock it
+ flock(pFile->h, LOCK_UN);
+ return 0; // no one has it reserved
+ }
+ return 1; // someone else might have it reserved
+ }
+}
+
+static int flockUnixLock(OsFile *id, int locktype) {
+ unixFile *pFile = (unixFile*)id;
+
+ // if we already have a lock, it is exclusive.
+ // Just adjust level and punt on outta here.
+ if (pFile->locktype > NO_LOCK) {
+ pFile->locktype = locktype;
+ return SQLITE_OK;
+ }
+
+ // grab an exclusive lock
+ int rc = flock(pFile->h, LOCK_EX | LOCK_NB);
+ if (rc) {
+ // didn't get, must be busy
+ return SQLITE_BUSY;
+ } else {
+ // got it, set the type and return ok
+ pFile->locktype = locktype;
+ return SQLITE_OK;
+ }
+}
+
+static int flockUnixUnlock(OsFile *id, int locktype) {
+ unixFile *pFile = (unixFile*)id;
+
+ assert( locktype<=SHARED_LOCK );
+
+ // no-op if possible
+ if( pFile->locktype==locktype ){
+ return SQLITE_OK;
+ }
+
+ // shared can just be set because we always have an exclusive
+ if (locktype==SHARED_LOCK) {
+ pFile->locktype = locktype;
+ return SQLITE_OK;
+ }
+
+ // no, really, unlock.
+ int rc = flock(pFile->h, LOCK_UN);
+ if (rc)
+ return SQLITE_IOERR_UNLOCK;
+ else {
+ pFile->locktype = NO_LOCK;
+ return SQLITE_OK;
+ }
+}
+
+/*
+ ** Close a file.
+ */
+static int flockUnixClose(OsFile **pId) {
+ unixFile *id = (unixFile*)*pId;
+
+ if( !id ) return SQLITE_OK;
+ flockUnixUnlock(*pId, NO_LOCK);
+
+ if( id->dirfd>=0 ) close(id->dirfd);
+ id->dirfd = -1;
+ sqlite3OsEnterMutex();
+
+ close(id->h);
+ sqlite3OsLeaveMutex();
+ id->isOpen = 0;
+ OSTRACE2("CLOSE %-3d\n", id->h);
+ OpenCounter(-1);
+ sqlite3ThreadSafeFree(id);
+ *pId = 0;
+ return SQLITE_OK;
+}
+
+#pragma mark Old-School .lock file based locking
+
+/*
+ ** The dotlockLockingContext structure contains all dotlock (.lock) lock
+ ** specific state
+ */
+typedef struct dotlockLockingContext dotlockLockingContext;
+struct dotlockLockingContext {
+ char *lockPath;
+};
+
+
+static int dotlockUnixCheckReservedLock(OsFile *id) {
+ unixFile *pFile = (unixFile*)id;
+ dotlockLockingContext *context =
+ (dotlockLockingContext *) pFile->lockingContext;
+
+ if (pFile->locktype == RESERVED_LOCK) {
+ return 1; // already have a reserved lock
+ } else {
+ struct stat statBuf;
+ if (lstat(context->lockPath,&statBuf) == 0)
+ // file exists, someone else has the lock
+ return 1;
+ else
+ // file does not exist, we could have it if we want it
+ return 0;
+ }
+}
+
+static int dotlockUnixLock(OsFile *id, int locktype) {
+ unixFile *pFile = (unixFile*)id;
+ dotlockLockingContext *context =
+ (dotlockLockingContext *) pFile->lockingContext;
+
+ // if we already have a lock, it is exclusive.
+ // Just adjust level and punt on outta here.
+ if (pFile->locktype > NO_LOCK) {
+ pFile->locktype = locktype;
+
+ /* Always update the timestamp on the old file */
+ utimes(context->lockPath,NULL);
+ return SQLITE_OK;
+ }
+
+ // check to see if lock file already exists
+ struct stat statBuf;
+ if (lstat(context->lockPath,&statBuf) == 0){
+ return SQLITE_BUSY; // it does, busy
+ }
+
+ // grab an exclusive lock
+ int fd = open(context->lockPath,O_RDONLY|O_CREAT|O_EXCL,0600);
+ if (fd < 0) {
+ // failed to open/create the file, someone else may have stolen the lock
+ return SQLITE_BUSY;
+ }
+ close(fd);
+
+ // got it, set the type and return ok
+ pFile->locktype = locktype;
+ return SQLITE_OK;
+}
+
+static int dotlockUnixUnlock(OsFile *id, int locktype) {
+ unixFile *pFile = (unixFile*)id;
+ dotlockLockingContext *context =
+ (dotlockLockingContext *) pFile->lockingContext;
+
+ assert( locktype<=SHARED_LOCK );
+
+ // no-op if possible
+ if( pFile->locktype==locktype ){
+ return SQLITE_OK;
+ }
+
+ // shared can just be set because we always have an exclusive
+ if (locktype==SHARED_LOCK) {
+ pFile->locktype = locktype;
+ return SQLITE_OK;
+ }
+
+ // no, really, unlock.
+ unlink(context->lockPath);
+ pFile->locktype = NO_LOCK;
+ return SQLITE_OK;
+}
+
+/*
+ ** Close a file.
+ */
+static int dotlockUnixClose(OsFile **pId) {
+ unixFile *id = (unixFile*)*pId;
+
+ if( !id ) return SQLITE_OK;
+ dotlockUnixUnlock(*pId, NO_LOCK);
+ /* free the dotlock locking structure */
+ if (id->lockingContext != NULL) {
+ if (((dotlockLockingContext *)id->lockingContext)->lockPath != NULL)
+ sqlite3ThreadSafeFree( ( (dotlockLockingContext *)
+ id->lockingContext)->lockPath);
+ sqlite3ThreadSafeFree(id->lockingContext);
+ }
+
+ if( id->dirfd>=0 ) close(id->dirfd);
+ id->dirfd = -1;
+ sqlite3OsEnterMutex();
+
+ close(id->h);
+
+ sqlite3OsLeaveMutex();
+ id->isOpen = 0;
+ OSTRACE2("CLOSE %-3d\n", id->h);
+ OpenCounter(-1);
+ sqlite3ThreadSafeFree(id);
+ *pId = 0;
+ return SQLITE_OK;
+}
+
+
+#pragma mark No locking
+
+/*
+ ** The nolockLockingContext is void
+ */
+typedef void nolockLockingContext;
+
+static int nolockUnixCheckReservedLock(OsFile *id) {
+ return 0;
+}
+
+static int nolockUnixLock(OsFile *id, int locktype) {
+ return SQLITE_OK;
+}
+
+static int nolockUnixUnlock(OsFile *id, int locktype) {
+ return SQLITE_OK;
+}
+
+/*
+ ** Close a file.
+ */
+static int nolockUnixClose(OsFile **pId) {
+ unixFile *id = (unixFile*)*pId;
+
+ if( !id ) return SQLITE_OK;
+ if( id->dirfd>=0 ) close(id->dirfd);
+ id->dirfd = -1;
+ sqlite3OsEnterMutex();
+
+ close(id->h);
+
+ sqlite3OsLeaveMutex();
+ id->isOpen = 0;
+ OSTRACE2("CLOSE %-3d\n", id->h);
+ OpenCounter(-1);
+ sqlite3ThreadSafeFree(id);
+ *pId = 0;
+ return SQLITE_OK;
+}
+
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
/*
** Turn a relative pathname into a full pathname. Return a pointer
** to the full pathname stored in space obtained from sqliteMalloc().
@@ -1640,6 +2335,20 @@ static int unixLockState(OsFile *id){
}
/*
+** Return the sector size in bytes of the underlying block device for
+** the specified file. This is almost always 512 bytes, but may be
+** larger for some devices.
+**
+** SQLite code assumes this function cannot fail. It also assumes that
+** if two files are created in the same file-system directory (i.e.
+** a database and it's journal file) that the sector size will be the
+** same for both.
+*/
+static int unixSectorSize(OsFile *id){
+ return SQLITE_DEFAULT_SECTOR_SIZE;
+}
+
+/*
** This vector defines all the methods that can operate on an OsFile
** for unix.
*/
@@ -1658,38 +2367,242 @@ static const IoMethod sqlite3UnixIoMethod = {
unixUnlock,
unixLockState,
unixCheckReservedLock,
+ unixSectorSize,
+};
+
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+/*
+ ** This vector defines all the methods that can operate on an OsFile
+ ** for unix with AFP style file locking.
+ */
+static const IoMethod sqlite3AFPLockingUnixIoMethod = {
+ afpUnixClose,
+ unixOpenDirectory,
+ unixRead,
+ unixWrite,
+ unixSeek,
+ unixTruncate,
+ unixSync,
+ unixSetFullSync,
+ unixFileHandle,
+ unixFileSize,
+ afpUnixLock,
+ afpUnixUnlock,
+ unixLockState,
+ afpUnixCheckReservedLock,
+ unixSectorSize,
+};
+
+/*
+ ** This vector defines all the methods that can operate on an OsFile
+ ** for unix with flock() style file locking.
+ */
+static const IoMethod sqlite3FlockLockingUnixIoMethod = {
+ flockUnixClose,
+ unixOpenDirectory,
+ unixRead,
+ unixWrite,
+ unixSeek,
+ unixTruncate,
+ unixSync,
+ unixSetFullSync,
+ unixFileHandle,
+ unixFileSize,
+ flockUnixLock,
+ flockUnixUnlock,
+ unixLockState,
+ flockUnixCheckReservedLock,
+ unixSectorSize,
+};
+
+/*
+ ** This vector defines all the methods that can operate on an OsFile
+ ** for unix with dotlock style file locking.
+ */
+static const IoMethod sqlite3DotlockLockingUnixIoMethod = {
+ dotlockUnixClose,
+ unixOpenDirectory,
+ unixRead,
+ unixWrite,
+ unixSeek,
+ unixTruncate,
+ unixSync,
+ unixSetFullSync,
+ unixFileHandle,
+ unixFileSize,
+ dotlockUnixLock,
+ dotlockUnixUnlock,
+ unixLockState,
+ dotlockUnixCheckReservedLock,
+ unixSectorSize,
+};
+
+/*
+ ** This vector defines all the methods that can operate on an OsFile
+ ** for unix with dotlock style file locking.
+ */
+static const IoMethod sqlite3NolockLockingUnixIoMethod = {
+ nolockUnixClose,
+ unixOpenDirectory,
+ unixRead,
+ unixWrite,
+ unixSeek,
+ unixTruncate,
+ unixSync,
+ unixSetFullSync,
+ unixFileHandle,
+ unixFileSize,
+ nolockUnixLock,
+ nolockUnixUnlock,
+ unixLockState,
+ nolockUnixCheckReservedLock,
+ unixSectorSize,
};
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
+
/*
-** 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.
+** Allocate memory for a new unixFile and initialize that unixFile.
+** Write a pointer to the new unixFile into *pId.
+** If we run out of memory, close the file and return an error.
*/
-static int allocateUnixFile(unixFile *pInit, OsFile **pId){
+#ifdef SQLITE_ENABLE_LOCKING_STYLE
+/*
+ ** When locking extensions are enabled, the filepath and locking style
+ ** are needed to determine the unixFile pMethod to use for locking operations.
+ ** The locking-style specific lockingContext data structure is created
+ ** and assigned here also.
+ */
+static int allocateUnixFile(
+ int h, /* Open file descriptor of file being opened */
+ OsFile **pId, /* Write completed initialization here */
+ const char *zFilename, /* Name of the file being opened */
+ int delFlag /* Delete-on-or-before-close flag */
+){
+ sqlite3LockingStyle lockingStyle;
unixFile *pNew;
- pInit->dirfd = -1;
- pInit->fullSync = 0;
- pInit->locktype = 0;
- pInit->offset = 0;
- SET_THREADID(pInit);
+ unixFile f;
+ int rc;
+
+ memset(&f, 0, sizeof(f));
+ lockingStyle = sqlite3DetectLockingStyle(zFilename, h);
+ if ( lockingStyle == posixLockingStyle ) {
+ sqlite3OsEnterMutex();
+ rc = findLockInfo(h, &f.pLock, &f.pOpen);
+ sqlite3OsLeaveMutex();
+ if( rc ){
+ close(h);
+ unlink(zFilename);
+ return SQLITE_NOMEM;
+ }
+ } else {
+ // pLock and pOpen are only used for posix advisory locking
+ f.pLock = NULL;
+ f.pOpen = NULL;
+ }
+ if( delFlag ){
+ unlink(zFilename);
+ }
+ f.dirfd = -1;
+ f.h = h;
+ SET_THREADID(&f);
pNew = sqlite3ThreadSafeMalloc( sizeof(unixFile) );
if( pNew==0 ){
- close(pInit->h);
+ close(h);
sqlite3OsEnterMutex();
- releaseLockInfo(pInit->pLock);
- releaseOpenCnt(pInit->pOpen);
+ releaseLockInfo(f.pLock);
+ releaseOpenCnt(f.pOpen);
sqlite3OsLeaveMutex();
*pId = 0;
return SQLITE_NOMEM;
}else{
- *pNew = *pInit;
- pNew->pMethod = &sqlite3UnixIoMethod;
+ *pNew = f;
+ switch(lockingStyle) {
+ case afpLockingStyle:
+ /* afp locking uses the file path so it needs to be included in
+ ** the afpLockingContext */
+ pNew->pMethod = &sqlite3AFPLockingUnixIoMethod;
+ pNew->lockingContext =
+ sqlite3ThreadSafeMalloc(sizeof(afpLockingContext));
+ ((afpLockingContext *)pNew->lockingContext)->filePath =
+ sqlite3ThreadSafeMalloc(strlen(zFilename) + 1);
+ strcpy(((afpLockingContext *)pNew->lockingContext)->filePath,
+ zFilename);
+ srandomdev();
+ break;
+ case flockLockingStyle:
+ /* flock locking doesn't need additional lockingContext information */
+ pNew->pMethod = &sqlite3FlockLockingUnixIoMethod;
+ break;
+ case dotlockLockingStyle:
+ /* dotlock locking uses the file path so it needs to be included in
+ ** the dotlockLockingContext */
+ pNew->pMethod = &sqlite3DotlockLockingUnixIoMethod;
+ pNew->lockingContext = sqlite3ThreadSafeMalloc(
+ sizeof(dotlockLockingContext));
+ ((dotlockLockingContext *)pNew->lockingContext)->lockPath =
+ sqlite3ThreadSafeMalloc(strlen(zFilename) + strlen(".lock") + 1);
+ sprintf(((dotlockLockingContext *)pNew->lockingContext)->lockPath,
+ "%s.lock", zFilename);
+ break;
+ case posixLockingStyle:
+ /* posix locking doesn't need additional lockingContext information */
+ pNew->pMethod = &sqlite3UnixIoMethod;
+ break;
+ case noLockingStyle:
+ case unsupportedLockingStyle:
+ default:
+ pNew->pMethod = &sqlite3NolockLockingUnixIoMethod;
+ }
*pId = (OsFile*)pNew;
OpenCounter(+1);
return SQLITE_OK;
}
}
+#else /* SQLITE_ENABLE_LOCKING_STYLE */
+static int allocateUnixFile(
+ int h, /* Open file descriptor on file being opened */
+ OsFile **pId, /* Write the resul unixFile structure here */
+ const char *zFilename, /* Name of the file being opened */
+ int delFlag /* If true, delete the file on or before closing */
+){
+ unixFile *pNew;
+ unixFile f;
+ int rc;
+ memset(&f, 0, sizeof(f));
+ sqlite3OsEnterMutex();
+ rc = findLockInfo(h, &f.pLock, &f.pOpen);
+ sqlite3OsLeaveMutex();
+ if( delFlag ){
+ unlink(zFilename);
+ }
+ if( rc ){
+ close(h);
+ return SQLITE_NOMEM;
+ }
+ OSTRACE3("OPEN %-3d %s\n", h, zFilename);
+ f.dirfd = -1;
+ f.h = h;
+ SET_THREADID(&f);
+ pNew = sqlite3ThreadSafeMalloc( sizeof(unixFile) );
+ if( pNew==0 ){
+ close(h);
+ sqlite3OsEnterMutex();
+ releaseLockInfo(f.pLock);
+ releaseOpenCnt(f.pOpen);
+ sqlite3OsLeaveMutex();
+ *pId = 0;
+ return SQLITE_NOMEM;
+ }else{
+ *pNew = f;
+ pNew->pMethod = &sqlite3UnixIoMethod;
+ *pId = (OsFile*)pNew;
+ OpenCounter(+1);
+ return SQLITE_OK;
+ }
+}
+#endif /* SQLITE_ENABLE_LOCKING_STYLE */
#endif /* SQLITE_OMIT_DISKIO */
/***************************************************************************
@@ -1698,6 +2611,23 @@ static int allocateUnixFile(unixFile *pInit, OsFile **pId){
****************************************************************************/
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
+/*
+** Interfaces for opening a shared library, finding entry points
+** within the shared library, and closing the shared library.
+*/
+#include <dlfcn.h>
+void *sqlite3UnixDlopen(const char *zFilename){
+ return dlopen(zFilename, RTLD_NOW | RTLD_GLOBAL);
+}
+void *sqlite3UnixDlsym(void *pHandle, const char *zSymbol){
+ return dlsym(pHandle, zSymbol);
+}
+int sqlite3UnixDlclose(void *pHandle){
+ return dlclose(pHandle);
+}
+#endif /* SQLITE_OMIT_LOAD_EXTENSION */
+
/*
** Get information to seed the random number generator. The seed
** is written into the buffer zBuf[256]. The calling function must
@@ -1977,8 +2907,7 @@ int sqlite3UnixCurrentTime(double *prNow){
*prNow = t/86400.0 + 2440587.5;
#else
struct timeval sNow;
- struct timezone sTz; /* Not used */
- gettimeofday(&sNow, &sTz);
+ gettimeofday(&sNow, 0);
*prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0;
#endif
#ifdef SQLITE_TEST
diff --git a/ext/pdo_sqlite/sqlite/src/os_win.c b/ext/pdo_sqlite/sqlite/src/os_win.c
index 6c167ab5b..b15de0334 100644
--- a/ext/pdo_sqlite/sqlite/src/os_win.c
+++ b/ext/pdo_sqlite/sqlite/src/os_win.c
@@ -40,6 +40,7 @@
*/
#if defined(_WIN32_WCE)
# define OS_WINCE 1
+# define AreFileApisANSI() 1
#else
# define OS_WINCE 0
#endif
@@ -124,16 +125,14 @@ int sqlite3_os_type = 0;
#endif /* OS_WINCE */
/*
-** Convert a UTF-8 string to UTF-32. Space to hold the returned string
-** is obtained from sqliteMalloc.
+** Convert a UTF-8 string to microsoft unicode (UTF-16?).
+**
+** Space to hold the returned string is obtained from sqliteMalloc.
*/
static WCHAR *utf8ToUnicode(const char *zFilename){
int nChar;
WCHAR *zWideFilename;
- if( !isNT() ){
- return 0;
- }
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
zWideFilename = sqliteMalloc( nChar*sizeof(zWideFilename[0]) );
if( zWideFilename==0 ){
@@ -148,7 +147,7 @@ static WCHAR *utf8ToUnicode(const char *zFilename){
}
/*
-** Convert UTF-32 to UTF-8. Space to hold the returned string is
+** Convert microsoft unicode to UTF-8. Space to hold the returned string is
** obtained from sqliteMalloc().
*/
static char *unicodeToUtf8(const WCHAR *zWideFilename){
@@ -169,6 +168,91 @@ static char *unicodeToUtf8(const WCHAR *zWideFilename){
return zFilename;
}
+/*
+** Convert an ansi string to microsoft unicode, based on the
+** current codepage settings for file apis.
+**
+** Space to hold the returned string is obtained
+** from sqliteMalloc.
+*/
+static WCHAR *mbcsToUnicode(const char *zFilename){
+ int nByte;
+ WCHAR *zMbcsFilename;
+ int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+
+ nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, NULL,0)*sizeof(WCHAR);
+ zMbcsFilename = sqliteMalloc( nByte*sizeof(zMbcsFilename[0]) );
+ if( zMbcsFilename==0 ){
+ return 0;
+ }
+ nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte);
+ if( nByte==0 ){
+ sqliteFree(zMbcsFilename);
+ zMbcsFilename = 0;
+ }
+ return zMbcsFilename;
+}
+
+/*
+** Convert microsoft unicode to multibyte character string, based on the
+** user's Ansi codepage.
+**
+** Space to hold the returned string is obtained from
+** sqliteMalloc().
+*/
+static char *unicodeToMbcs(const WCHAR *zWideFilename){
+ int nByte;
+ char *zFilename;
+ int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+
+ nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, 0, 0, 0, 0);
+ zFilename = sqliteMalloc( nByte );
+ if( zFilename==0 ){
+ return 0;
+ }
+ nByte = WideCharToMultiByte(codepage, 0, zWideFilename, -1, zFilename, nByte,
+ 0, 0);
+ if( nByte == 0 ){
+ sqliteFree(zFilename);
+ zFilename = 0;
+ }
+ return zFilename;
+}
+
+/*
+** Convert multibyte character string to UTF-8. Space to hold the
+** returned string is obtained from sqliteMalloc().
+*/
+static char *mbcsToUtf8(const char *zFilename){
+ char *zFilenameUtf8;
+ WCHAR *zTmpWide;
+
+ zTmpWide = mbcsToUnicode(zFilename);
+ if( zTmpWide==0 ){
+ return 0;
+ }
+ zFilenameUtf8 = unicodeToUtf8(zTmpWide);
+ sqliteFree(zTmpWide);
+ return zFilenameUtf8;
+}
+
+/*
+** Convert UTF-8 to multibyte character string. Space to hold the
+** returned string is obtained from sqliteMalloc().
+*/
+static char *utf8ToMbcs(const char *zFilename){
+ char *zFilenameMbcs;
+ WCHAR *zTmpWide;
+
+ zTmpWide = utf8ToUnicode(zFilename);
+ if( zTmpWide==0 ){
+ return 0;
+ }
+ zFilenameMbcs = unicodeToMbcs(zTmpWide);
+ sqliteFree(zTmpWide);
+ return zFilenameMbcs;
+}
+
#if OS_WINCE
/*************************************************************************
** This section contains code for WinCE only.
@@ -324,6 +408,12 @@ static void winceDestroyLock(winFile *pFile){
UnmapViewOfFile(pFile->shared);
CloseHandle(pFile->hShared);
+ if( pFile->zDeleteOnClose ){
+ DeleteFileW(pFile->zDeleteOnClose);
+ sqliteFree(pFile->zDeleteOnClose);
+ pFile->zDeleteOnClose = 0;
+ }
+
/* Done with the mutex */
winceMutexRelease(pFile->hMutex);
CloseHandle(pFile->hMutex);
@@ -476,6 +566,23 @@ static BOOL winceLockFileEx(
#endif /* OS_WINCE */
/*
+** Convert a UTF-8 filename into whatever form the underlying
+** operating system wants filenames in. Space to hold the result
+** is obtained from sqliteMalloc and must be freed by the calling
+** function.
+*/
+static void *convertUtf8Filename(const char *zFilename){
+ void *zConverted = 0;
+ if( isNT() ){
+ zConverted = utf8ToUnicode(zFilename);
+ }else{
+ zConverted = utf8ToMbcs(zFilename);
+ }
+ /* caller will handle out of memory */
+ return zConverted;
+}
+
+/*
** Delete the named file.
**
** Note that windows does not allow a file to be deleted if some other
@@ -489,25 +596,31 @@ static BOOL winceLockFileEx(
*/
#define MX_DELETION_ATTEMPTS 3
int sqlite3WinDelete(const char *zFilename){
- WCHAR *zWide = utf8ToUnicode(zFilename);
int cnt = 0;
int rc;
- if( zWide ){
+ void *zConverted = convertUtf8Filename(zFilename);
+ if( zConverted==0 ){
+ return SQLITE_NOMEM;
+ }
+ SimulateIOError(return SQLITE_IOERR_DELETE);
+ if( isNT() ){
do{
- rc = DeleteFileW(zWide);
- }while( rc==0 && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
- sqliteFree(zWide);
+ rc = DeleteFileW(zConverted);
+ }while( rc==0 && GetFileAttributesW(zConverted)!=0xffffffff
+ && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
}else{
#if OS_WINCE
return SQLITE_NOMEM;
#else
do{
- rc = DeleteFileA(zFilename);
- }while( rc==0 && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
+ rc = DeleteFileA(zConverted);
+ }while( rc==0 && GetFileAttributesA(zConverted)!=0xffffffff
+ && cnt++ < MX_DELETION_ATTEMPTS && (Sleep(100), 1) );
#endif
}
- TRACE2("DELETE \"%s\"\n", zFilename);
- return rc==0 ? SQLITE_OK : SQLITE_IOERR;
+ sqliteFree(zConverted);
+ OSTRACE2("DELETE \"%s\"\n", zFilename);
+ return rc!=0 ? SQLITE_OK : SQLITE_IOERR;
}
/*
@@ -515,17 +628,20 @@ int sqlite3WinDelete(const char *zFilename){
*/
int sqlite3WinFileExists(const char *zFilename){
int exists = 0;
- WCHAR *zWide = utf8ToUnicode(zFilename);
- if( zWide ){
- exists = GetFileAttributesW(zWide) != 0xffffffff;
- sqliteFree(zWide);
+ void *zConverted = convertUtf8Filename(zFilename);
+ if( zConverted==0 ){
+ return SQLITE_NOMEM;
+ }
+ if( isNT() ){
+ exists = GetFileAttributesW((WCHAR*)zConverted) != 0xffffffff;
}else{
#if OS_WINCE
return SQLITE_NOMEM;
#else
- exists = GetFileAttributesA(zFilename) != 0xffffffff;
+ exists = GetFileAttributesA((char*)zConverted) != 0xffffffff;
#endif
}
+ sqliteFree(zConverted);
return exists;
}
@@ -552,10 +668,14 @@ int sqlite3WinOpenReadWrite(
){
winFile f;
HANDLE h;
- WCHAR *zWide = utf8ToUnicode(zFilename);
+ void *zConverted = convertUtf8Filename(zFilename);
+ if( zConverted==0 ){
+ return SQLITE_NOMEM;
+ }
assert( *pId==0 );
- if( zWide ){
- h = CreateFileW(zWide,
+
+ if( isNT() ){
+ h = CreateFileW((WCHAR*)zConverted,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
@@ -564,7 +684,7 @@ int sqlite3WinOpenReadWrite(
NULL
);
if( h==INVALID_HANDLE_VALUE ){
- h = CreateFileW(zWide,
+ h = CreateFileW((WCHAR*)zConverted,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
@@ -573,7 +693,7 @@ int sqlite3WinOpenReadWrite(
NULL
);
if( h==INVALID_HANDLE_VALUE ){
- sqliteFree(zWide);
+ sqliteFree(zConverted);
return SQLITE_CANTOPEN;
}
*pReadonly = 1;
@@ -583,16 +703,15 @@ int sqlite3WinOpenReadWrite(
#if OS_WINCE
if (!winceCreateLock(zFilename, &f)){
CloseHandle(h);
- sqliteFree(zWide);
+ sqliteFree(zConverted);
return SQLITE_CANTOPEN;
}
#endif
- sqliteFree(zWide);
}else{
#if OS_WINCE
return SQLITE_NOMEM;
#else
- h = CreateFileA(zFilename,
+ h = CreateFileA((char*)zConverted,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
@@ -601,7 +720,7 @@ int sqlite3WinOpenReadWrite(
NULL
);
if( h==INVALID_HANDLE_VALUE ){
- h = CreateFileA(zFilename,
+ h = CreateFileA((char*)zConverted,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
@@ -610,6 +729,7 @@ int sqlite3WinOpenReadWrite(
NULL
);
if( h==INVALID_HANDLE_VALUE ){
+ sqliteFree(zConverted);
return SQLITE_CANTOPEN;
}
*pReadonly = 1;
@@ -618,11 +738,14 @@ int sqlite3WinOpenReadWrite(
}
#endif /* OS_WINCE */
}
+
+ sqliteFree(zConverted);
+
f.h = h;
#if OS_WINCE
f.zDeleteOnClose = 0;
#endif
- TRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
+ OSTRACE3("OPEN R/W %d \"%s\"\n", h, zFilename);
return allocateWinFile(&f, pId);
}
@@ -650,8 +773,11 @@ int sqlite3WinOpenReadWrite(
int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
winFile f;
HANDLE h;
- int fileflags;
- WCHAR *zWide = utf8ToUnicode(zFilename);
+ DWORD fileflags;
+ void *zConverted = convertUtf8Filename(zFilename);
+ if( zConverted==0 ){
+ return SQLITE_NOMEM;
+ }
assert( *pId == 0 );
fileflags = FILE_FLAG_RANDOM_ACCESS;
#if !OS_WINCE
@@ -659,10 +785,10 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
fileflags |= FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE;
}
#endif
- if( zWide ){
+ if( isNT() ){
int cnt = 0;
do{
- h = CreateFileW(zWide,
+ h = CreateFileW((WCHAR*)zConverted,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
@@ -671,14 +797,13 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
NULL
);
}while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
- sqliteFree(zWide);
}else{
#if OS_WINCE
return SQLITE_NOMEM;
#else
int cnt = 0;
do{
- h = CreateFileA(zFilename,
+ h = CreateFileA((char*)zConverted,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
@@ -689,15 +814,19 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
}while( h==INVALID_HANDLE_VALUE && cnt++ < 2 && (Sleep(100), 1) );
#endif /* OS_WINCE */
}
+#if OS_WINCE
+ if( delFlag && h!=INVALID_HANDLE_VALUE ){
+ f.zDeleteOnClose = zConverted;
+ zConverted = 0;
+ }
+ f.hMutex = NULL;
+#endif
+ sqliteFree(zConverted);
if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN;
}
f.h = h;
-#if OS_WINCE
- f.zDeleteOnClose = delFlag ? utf8ToUnicode(zFilename) : 0;
- f.hMutex = NULL;
-#endif
- TRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
+ OSTRACE3("OPEN EX %d \"%s\"\n", h, zFilename);
return allocateWinFile(&f, pId);
}
@@ -711,10 +840,13 @@ int sqlite3WinOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
winFile f;
HANDLE h;
- WCHAR *zWide = utf8ToUnicode(zFilename);
+ void *zConverted = convertUtf8Filename(zFilename);
+ if( zConverted==0 ){
+ return SQLITE_NOMEM;
+ }
assert( *pId==0 );
- if( zWide ){
- h = CreateFileW(zWide,
+ if( isNT() ){
+ h = CreateFileW((WCHAR*)zConverted,
GENERIC_READ,
0,
NULL,
@@ -722,12 +854,11 @@ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
NULL
);
- sqliteFree(zWide);
}else{
#if OS_WINCE
return SQLITE_NOMEM;
#else
- h = CreateFileA(zFilename,
+ h = CreateFileA((char*)zConverted,
GENERIC_READ,
0,
NULL,
@@ -737,6 +868,7 @@ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
);
#endif
}
+ sqliteFree(zConverted);
if( h==INVALID_HANDLE_VALUE ){
return SQLITE_CANTOPEN;
}
@@ -745,7 +877,7 @@ int sqlite3WinOpenReadOnly(const char *zFilename, OsFile **pId){
f.zDeleteOnClose = 0;
f.hMutex = NULL;
#endif
- TRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
+ OSTRACE3("OPEN RO %d \"%s\"\n", h, zFilename);
return allocateWinFile(&f, pId);
}
@@ -773,13 +905,6 @@ static int winOpenDirectory(
}
/*
-** If the following global variable points to a string which is the
-** name of a directory, then that directory will be used to store
-** temporary files.
-*/
-char *sqlite3_temp_directory = 0;
-
-/*
** Create a temporary file name in zBuf. zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
*/
@@ -802,9 +927,21 @@ int sqlite3WinTempFileName(char *zBuf){
strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30);
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
sqliteFree(zMulti);
+ }else{
+ return SQLITE_NOMEM;
}
}else{
- GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath);
+ char *zUtf8;
+ char zMbcsPath[SQLITE_TEMPNAME_SIZE];
+ GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zMbcsPath);
+ zUtf8 = mbcsToUtf8(zMbcsPath);
+ if( zUtf8 ){
+ strncpy(zTempPath, zUtf8, SQLITE_TEMPNAME_SIZE-30);
+ zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
+ sqliteFree(zUtf8);
+ }else{
+ return SQLITE_NOMEM;
+ }
}
for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
zTempPath[i] = 0;
@@ -818,7 +955,7 @@ int sqlite3WinTempFileName(char *zBuf){
zBuf[j] = 0;
if( !sqlite3OsFileExists(zBuf) ) break;
}
- TRACE2("TEMP FILENAME: %s\n", zBuf);
+ OSTRACE2("TEMP FILENAME: %s\n", zBuf);
return SQLITE_OK;
}
@@ -838,16 +975,12 @@ static int winClose(OsFile **pId){
int rc = 1;
if( pId && (pFile = (winFile*)*pId)!=0 ){
int rc, cnt = 0;
- TRACE2("CLOSE %d\n", pFile->h);
+ OSTRACE2("CLOSE %d\n", pFile->h);
do{
rc = CloseHandle(pFile->h);
}while( rc==0 && cnt++ < MX_CLOSE_ATTEMPT && (Sleep(100), 1) );
#if OS_WINCE
winceDestroyLock(pFile);
- if( pFile->zDeleteOnClose ){
- DeleteFileW(pFile->zDeleteOnClose);
- sqliteFree(pFile->zDeleteOnClose);
- }
#endif
OpenCounter(-1);
sqliteFree(pFile);
@@ -864,15 +997,16 @@ static int winClose(OsFile **pId){
static int winRead(OsFile *id, void *pBuf, int amt){
DWORD got;
assert( id!=0 );
- SimulateIOError(SQLITE_IOERR);
- TRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
+ SimulateIOError(return SQLITE_IOERR_READ);
+ OSTRACE3("READ %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
if( !ReadFile(((winFile*)id)->h, pBuf, amt, &got, 0) ){
- got = 0;
+ return SQLITE_IOERR_READ;
}
if( got==(DWORD)amt ){
return SQLITE_OK;
}else{
- return SQLITE_IOERR;
+ memset(&((char*)pBuf)[got], 0, amt-got);
+ return SQLITE_IOERR_SHORT_READ;
}
}
@@ -884,9 +1018,9 @@ static int winWrite(OsFile *id, const void *pBuf, int amt){
int rc = 0;
DWORD wrote;
assert( id!=0 );
- SimulateIOError(SQLITE_IOERR);
- SimulateDiskfullError;
- TRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
+ SimulateIOError(return SQLITE_IOERR_READ);
+ SimulateDiskfullError(return SQLITE_FULL);
+ OSTRACE3("WRITE %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
assert( amt>0 );
while( amt>0 && (rc = WriteFile(((winFile*)id)->h, pBuf, amt, &wrote, 0))!=0
&& wrote>0 ){
@@ -915,11 +1049,10 @@ static int winSeek(OsFile *id, i64 offset){
DWORD rc;
assert( id!=0 );
#ifdef SQLITE_TEST
- if( offset ) SimulateDiskfullError
+ if( offset ) SimulateDiskfullError(return SQLITE_FULL);
#endif
- SEEK(offset/1024 + 1);
rc = SetFilePointer(((winFile*)id)->h, lowerBits, &upperBits, FILE_BEGIN);
- TRACE3("SEEK %d %lld\n", ((winFile*)id)->h, offset);
+ OSTRACE3("SEEK %d %lld\n", ((winFile*)id)->h, offset);
if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
return SQLITE_FULL;
}
@@ -931,7 +1064,7 @@ static int winSeek(OsFile *id, i64 offset){
*/
static int winSync(OsFile *id, int dataOnly){
assert( id!=0 );
- TRACE3("SYNC %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
+ OSTRACE3("SYNC %d lock=%d\n", ((winFile*)id)->h, ((winFile*)id)->locktype);
if( FlushFileBuffers(((winFile*)id)->h) ){
return SQLITE_OK;
}else{
@@ -944,7 +1077,7 @@ static int winSync(OsFile *id, int dataOnly){
** than UNIX.
*/
int sqlite3WinSyncDirectory(const char *zDirname){
- SimulateIOError(SQLITE_IOERR);
+ SimulateIOError(return SQLITE_IOERR_READ);
return SQLITE_OK;
}
@@ -954,8 +1087,8 @@ int sqlite3WinSyncDirectory(const char *zDirname){
static int winTruncate(OsFile *id, i64 nByte){
LONG upperBits = nByte>>32;
assert( id!=0 );
- TRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte);
- SimulateIOError(SQLITE_IOERR);
+ OSTRACE3("TRUNCATE %d %lld\n", ((winFile*)id)->h, nByte);
+ SimulateIOError(return SQLITE_IOERR_TRUNCATE);
SetFilePointer(((winFile*)id)->h, nByte, &upperBits, FILE_BEGIN);
SetEndOfFile(((winFile*)id)->h);
return SQLITE_OK;
@@ -967,7 +1100,7 @@ static int winTruncate(OsFile *id, i64 nByte){
static int winFileSize(OsFile *id, i64 *pSize){
DWORD upperBits, lowerBits;
assert( id!=0 );
- SimulateIOError(SQLITE_IOERR);
+ SimulateIOError(return SQLITE_IOERR_FSTAT);
lowerBits = GetFileSize(((winFile*)id)->h, &upperBits);
*pSize = (((i64)upperBits)<<32) + lowerBits;
return SQLITE_OK;
@@ -1022,20 +1155,24 @@ static int unlockReadLock(winFile *pFile){
*/
int sqlite3WinIsDirWritable(char *zDirname){
int fileAttr;
- WCHAR *zWide;
+ void *zConverted;
if( zDirname==0 ) return 0;
if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0;
- zWide = utf8ToUnicode(zDirname);
- if( zWide ){
- fileAttr = GetFileAttributesW(zWide);
- sqliteFree(zWide);
+
+ zConverted = convertUtf8Filename(zDirname);
+ if( zConverted==0 ){
+ return SQLITE_NOMEM;
+ }
+ if( isNT() ){
+ fileAttr = GetFileAttributesW((WCHAR*)zConverted);
}else{
#if OS_WINCE
return 0;
#else
- fileAttr = GetFileAttributesA(zDirname);
+ fileAttr = GetFileAttributesA((char*)zConverted);
#endif
}
+ sqliteFree(zConverted);
if( fileAttr == 0xffffffff ) return 0;
if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
return 0;
@@ -1078,7 +1215,7 @@ static int winLock(OsFile *id, int locktype){
winFile *pFile = (winFile*)id;
assert( pFile!=0 );
- TRACE5("LOCK %d %d was %d(%d)\n",
+ OSTRACE5("LOCK %d %d was %d(%d)\n",
pFile->h, locktype, pFile->locktype, pFile->sharedLockByte);
/* If there is already a lock of this type or more restrictive on the
@@ -1108,7 +1245,7 @@ static int winLock(OsFile *id, int locktype){
/* 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);
+ OSTRACE2("could not get a PENDING lock. cnt=%d\n", cnt);
Sleep(1);
}
gotPendingLock = res;
@@ -1146,12 +1283,12 @@ static int winLock(OsFile *id, int locktype){
if( locktype==EXCLUSIVE_LOCK && res ){
assert( pFile->locktype>=SHARED_LOCK );
res = unlockReadLock(pFile);
- TRACE2("unreadlock = %d\n", res);
+ OSTRACE2("unreadlock = %d\n", res);
res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0);
if( res ){
newLocktype = EXCLUSIVE_LOCK;
}else{
- TRACE2("error-code = %d\n", GetLastError());
+ OSTRACE2("error-code = %d\n", GetLastError());
}
}
@@ -1168,7 +1305,7 @@ static int winLock(OsFile *id, int locktype){
if( res ){
rc = SQLITE_OK;
}else{
- TRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
+ OSTRACE4("LOCK FAILED %d trying for %d but got %d\n", pFile->h,
locktype, newLocktype);
rc = SQLITE_BUSY;
}
@@ -1187,14 +1324,14 @@ static int winCheckReservedLock(OsFile *id){
assert( pFile!=0 );
if( pFile->locktype>=RESERVED_LOCK ){
rc = 1;
- TRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
+ OSTRACE3("TEST WR-LOCK %d %d (local)\n", pFile->h, rc);
}else{
rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
if( rc ){
UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0);
}
rc = !rc;
- TRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
+ OSTRACE3("TEST WR-LOCK %d %d (remote)\n", pFile->h, rc);
}
return rc;
}
@@ -1216,7 +1353,7 @@ static int winUnlock(OsFile *id, int locktype){
winFile *pFile = (winFile*)id;
assert( pFile!=0 );
assert( locktype<=SHARED_LOCK );
- TRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
+ OSTRACE5("UNLOCK %d to %d was %d(%d)\n", pFile->h, locktype,
pFile->locktype, pFile->sharedLockByte);
type = pFile->locktype;
if( type>=EXCLUSIVE_LOCK ){
@@ -1224,7 +1361,7 @@ static int winUnlock(OsFile *id, int locktype){
if( locktype==SHARED_LOCK && !getReadLock(pFile) ){
/* This should never happen. We should always be able to
** reacquire the read lock */
- rc = SQLITE_IOERR;
+ rc = SQLITE_IOERR_UNLOCK;
}
}
if( type>=RESERVED_LOCK ){
@@ -1258,24 +1395,33 @@ char *sqlite3WinFullPathname(const char *zRelative){
/* WinCE has no concept of a relative pathname, or so I am told. */
zFull = sqliteStrDup(zRelative);
#else
- char *zNotUsed;
- WCHAR *zWide;
int nByte;
- zWide = utf8ToUnicode(zRelative);
- if( zWide ){
- WCHAR *zTemp, *zNotUsedW;
- nByte = GetFullPathNameW(zWide, 0, 0, &zNotUsedW) + 1;
+ void *zConverted;
+ zConverted = convertUtf8Filename(zRelative);
+ if( isNT() ){
+ WCHAR *zTemp;
+ nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3;
zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
- if( zTemp==0 ) return 0;
- GetFullPathNameW(zWide, nByte, zTemp, &zNotUsedW);
- sqliteFree(zWide);
+ if( zTemp==0 ){
+ sqliteFree(zConverted);
+ return 0;
+ }
+ GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0);
+ sqliteFree(zConverted);
zFull = unicodeToUtf8(zTemp);
sqliteFree(zTemp);
}else{
- nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
- zFull = sqliteMalloc( nByte*sizeof(zFull[0]) );
- if( zFull==0 ) return 0;
- GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
+ char *zTemp;
+ nByte = GetFullPathNameA((char*)zConverted, 0, 0, 0) + 3;
+ zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
+ if( zTemp==0 ){
+ sqliteFree(zConverted);
+ return 0;
+ }
+ GetFullPathNameA((char*)zConverted, nByte, zTemp, 0);
+ sqliteFree(zConverted);
+ zFull = mbcsToUtf8(zTemp);
+ sqliteFree(zTemp);
}
#endif
return zFull;
@@ -1304,6 +1450,20 @@ static int winLockState(OsFile *id){
}
/*
+** Return the sector size in bytes of the underlying block device for
+** the specified file. This is almost always 512 bytes, but may be
+** larger for some devices.
+**
+** SQLite code assumes this function cannot fail. It also assumes that
+** if two files are created in the same file-system directory (i.e.
+** a database and it's journal file) that the sector size will be the
+** same for both.
+*/
+static int winSectorSize(OsFile *id){
+ return SQLITE_DEFAULT_SECTOR_SIZE;
+}
+
+/*
** This vector defines all the methods that can operate on an OsFile
** for win32.
*/
@@ -1322,6 +1482,7 @@ static const IoMethod sqlite3WinIoMethod = {
winUnlock,
winLockState,
winCheckReservedLock,
+ winSectorSize,
};
/*
@@ -1357,6 +1518,45 @@ static int allocateWinFile(winFile *pInit, OsFile **pId){
** with other miscellanous aspects of the operating system interface
****************************************************************************/
+#if !defined(SQLITE_OMIT_LOAD_EXTENSION)
+/*
+** Interfaces for opening a shared library, finding entry points
+** within the shared library, and closing the shared library.
+*/
+void *sqlite3WinDlopen(const char *zFilename){
+ HANDLE h;
+ void *zConverted = convertUtf8Filename(zFilename);
+ if( zConverted==0 ){
+ return 0;
+ }
+ if( isNT() ){
+ h = LoadLibraryW((WCHAR*)zConverted);
+ }else{
+#if OS_WINCE
+ return 0;
+#else
+ h = LoadLibraryA((char*)zConverted);
+#endif
+ }
+ sqliteFree(zConverted);
+ return (void*)h;
+
+}
+void *sqlite3WinDlsym(void *pHandle, const char *zSymbol){
+#if OS_WINCE
+ /* The GetProcAddressA() routine is only available on wince. */
+ return GetProcAddressA((HANDLE)pHandle, zSymbol);
+#else
+ /* All other windows platforms expect GetProcAddress() to take
+ ** an Ansi string regardless of the _UNICODE setting */
+ return GetProcAddress((HANDLE)pHandle, zSymbol);
+#endif
+}
+int sqlite3WinDlclose(void *pHandle){
+ return FreeLibrary((HANDLE)pHandle);
+}
+#endif /* !SQLITE_OMIT_LOAD_EXTENSION */
+
/*
** Get information to seed the random number generator. The seed
** is written into the buffer zBuf[256]. The calling function must
diff --git a/ext/pdo_sqlite/sqlite/src/pager.c b/ext/pdo_sqlite/sqlite/src/pager.c
index 7f4b6f952..6b44448f0 100644
--- a/ext/pdo_sqlite/sqlite/src/pager.c
+++ b/ext/pdo_sqlite/sqlite/src/pager.c
@@ -31,21 +31,22 @@
** Macros for troubleshooting. Normally turned off
*/
#if 0
-#define TRACE1(X) sqlite3DebugPrintf(X)
-#define TRACE2(X,Y) sqlite3DebugPrintf(X,Y)
-#define TRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z)
-#define TRACE4(X,Y,Z,W) sqlite3DebugPrintf(X,Y,Z,W)
-#define TRACE5(X,Y,Z,W,V) sqlite3DebugPrintf(X,Y,Z,W,V)
+#define sqlite3DebugPrintf printf
+#define PAGERTRACE1(X) sqlite3DebugPrintf(X)
+#define PAGERTRACE2(X,Y) sqlite3DebugPrintf(X,Y)
+#define PAGERTRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z)
+#define PAGERTRACE4(X,Y,Z,W) sqlite3DebugPrintf(X,Y,Z,W)
+#define PAGERTRACE5(X,Y,Z,W,V) sqlite3DebugPrintf(X,Y,Z,W,V)
#else
-#define TRACE1(X)
-#define TRACE2(X,Y)
-#define TRACE3(X,Y,Z)
-#define TRACE4(X,Y,Z,W)
-#define TRACE5(X,Y,Z,W,V)
+#define PAGERTRACE1(X)
+#define PAGERTRACE2(X,Y)
+#define PAGERTRACE3(X,Y,Z)
+#define PAGERTRACE4(X,Y,Z,W)
+#define PAGERTRACE5(X,Y,Z,W,V)
#endif
/*
-** The following two macros are used within the TRACEX() macros above
+** The following two macros are used within the PAGERTRACEX() macros above
** to print out file-descriptors.
**
** PAGERID() takes a pointer to a Pager struct as it's argument. The
@@ -84,21 +85,24 @@
** PAGER_SYNCED The pager moves to this state from PAGER_EXCLUSIVE
** after all dirty pages have been written to the
** database file and the file has been synced to
-** disk. All that remains to do is to remove the
-** journal file and the transaction will be
-** committed.
+** disk. All that remains to do is to remove or
+** truncate the journal file and the transaction
+** will be committed.
**
** The page cache comes up in PAGER_UNLOCK. The first time a
-** sqlite3pager_get() occurs, the state transitions to PAGER_SHARED.
+** sqlite3PagerGet() occurs, the state transitions to PAGER_SHARED.
** After all pages have been released using sqlite_page_unref(),
** the state transitions back to PAGER_UNLOCK. The first time
-** that sqlite3pager_write() is called, the state transitions to
-** PAGER_RESERVED. (Note that sqlite_page_write() can only be
+** that sqlite3PagerWrite() is called, the state transitions to
+** PAGER_RESERVED. (Note that sqlite3PagerWrite() can only be
** called on an outstanding page which means that the pager must
** be in PAGER_SHARED before it transitions to PAGER_RESERVED.)
-** The transition to PAGER_EXCLUSIVE occurs when before any changes
-** are made to the database file. After an sqlite3pager_rollback()
-** or sqlite_pager_commit(), the state goes back to PAGER_SHARED.
+** PAGER_RESERVED means that there is an open rollback journal.
+** The transition to PAGER_EXCLUSIVE occurs before any changes
+** are made to the database file, though writes to the rollback
+** journal occurs with just PAGER_RESERVED. After an sqlite3PagerRollback()
+** or sqlite3PagerCommitPhaseTwo(), the state can go back to PAGER_SHARED,
+** or it can stay at PAGER_EXCLUSIVE if we are in exclusive access mode.
*/
#define PAGER_UNLOCK 0
#define PAGER_SHARED 1 /* same as SHARED_LOCK */
@@ -134,8 +138,8 @@
** This header is only visible to this pager module. The client
** code that calls pager sees only the data that follows the header.
**
-** Client code should call sqlite3pager_write() on a page prior to making
-** any modifications to that page. The first time sqlite3pager_write()
+** Client code should call sqlite3PagerWrite() on a page prior to making
+** any modifications to that page. The first time sqlite3PagerWrite()
** is called, the original page contents are written into the rollback
** journal and PgHdr.inJournal and PgHdr.needSync are set. Later, once
** the journal page has made it onto the disk surface, PgHdr.needSync
@@ -143,7 +147,7 @@
** database file until the journal pages has been synced to disk and the
** PgHdr.needSync has been cleared.
**
-** The PgHdr.dirty flag is set when sqlite3pager_write() is called and
+** The PgHdr.dirty flag is set when sqlite3PagerWrite() is called and
** is cleared again when the page content is written back to the original
** database file.
*/
@@ -154,12 +158,11 @@ struct PgHdr {
PgHdr *pNextHash, *pPrevHash; /* Hash collision chain for PgHdr.pgno */
PgHdr *pNextFree, *pPrevFree; /* Freelist of pages where nRef==0 */
PgHdr *pNextAll; /* A list of all pages */
- PgHdr *pNextStmt, *pPrevStmt; /* List of pages in the statement journal */
u8 inJournal; /* TRUE if has been written to journal */
- u8 inStmt; /* TRUE if in the statement subjournal */
u8 dirty; /* TRUE if we need to write back changes */
u8 needSync; /* Sync journal before writing this page */
- u8 alwaysRollback; /* Disable dont_rollback() for this page */
+ u8 alwaysRollback; /* Disable DontRollback() for this page */
+ u8 needRead; /* Read content if PagerWrite() is called */
short int nRef; /* Number of users of this page */
PgHdr *pDirty, *pPrevDirty; /* Dirty pages */
u32 notUsed; /* Buffer space */
@@ -185,6 +188,8 @@ typedef struct PgHistory PgHistory;
struct PgHistory {
u8 *pOrig; /* Original page text. Restore to this on a full rollback */
u8 *pStmt; /* Text as it was at the beginning of the current statement */
+ PgHdr *pNextStmt, *pPrevStmt; /* List of pages in the statement journal */
+ u8 inStmt; /* TRUE if in the statement subjournal */
};
/*
@@ -211,12 +216,12 @@ struct PgHistory {
/*
** A open page cache is an instance of the following structure.
**
-** Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, SQLITE_PROTOCOL
+** Pager.errCode may be set to SQLITE_IOERR, SQLITE_CORRUPT, or
** or SQLITE_FULL. Once one of the first three errors occurs, it persists
** and is returned as the result of every major pager API call. The
** SQLITE_FULL return code is slightly different. It persists only until the
** next successful rollback is performed on the pager cache. Also,
-** SQLITE_FULL does not affect the sqlite3pager_get() and sqlite3pager_lookup()
+** SQLITE_FULL does not affect the sqlite3PagerGet() and sqlite3PagerLookup()
** APIs, they may still be used successfully.
*/
struct Pager {
@@ -231,14 +236,17 @@ struct Pager {
u8 fullSync; /* Do extra syncs of the journal for robustness */
u8 full_fsync; /* Use F_FULLFSYNC when available */
u8 state; /* PAGER_UNLOCK, _SHARED, _RESERVED, etc. */
- u8 errCode; /* One of several kinds of errors */
u8 tempFile; /* zFilename is a temporary file */
u8 readOnly; /* True for a read-only database */
u8 needSync; /* True if an fsync() is needed on the journal */
u8 dirtyCache; /* True if cached pages have changed */
- u8 alwaysRollback; /* Disable dont_rollback() for all pages */
+ u8 alwaysRollback; /* Disable DontRollback() for all pages */
u8 memDb; /* True to inhibit all file I/O */
u8 setMaster; /* True if a m-j name has been written to jrnl */
+ u8 doNotSync; /* Boolean. While true, do not spill the cache */
+ u8 exclusiveMode; /* Boolean. True if locking_mode==EXCLUSIVE */
+ u8 changeCountDone; /* Set after incrementing the change-counter */
+ int errCode; /* One of several kinds of errors */
int dbSize; /* Number of pages in the file */
int origDbSize; /* dbSize before the current change */
int stmtSize; /* Size of database (in pages) at stmt_begin() */
@@ -271,30 +279,41 @@ struct Pager {
i64 stmtJSize; /* Size of journal at stmt_begin() */
int sectorSize; /* Assumed sector size during rollback */
#ifdef SQLITE_TEST
- int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */
- int nRead,nWrite; /* Database pages read/written */
+ int nHit, nMiss; /* Cache hits and missing */
+ int nRead, nWrite; /* Database pages read/written */
#endif
- void (*xDestructor)(void*,int); /* Call this routine when freeing pages */
- void (*xReiniter)(void*,int); /* Call this routine when reloading pages */
+ void (*xDestructor)(DbPage*,int); /* Call this routine when freeing pages */
+ void (*xReiniter)(DbPage*,int); /* Call this routine when reloading pages */
+#ifdef SQLITE_HAS_CODEC
void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
void *pCodecArg; /* First argument to xCodec() */
+#endif
int nHash; /* Size of the pager hash table */
PgHdr **aHash; /* Hash table to map page number to PgHdr */
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
Pager *pNext; /* Linked list of pagers in this thread */
#endif
+ char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */
+ char dbFileVers[16]; /* Changes whenever database file changes */
};
/*
-** If SQLITE_TEST is defined then increment the variable given in
-** the argument
+** The following global variables hold counters used for
+** testing purposes only. These variables do not exist in
+** a non-testing build. These variables are not thread-safe.
*/
#ifdef SQLITE_TEST
-# define TEST_INCR(x) x++
+int sqlite3_pager_readdb_count = 0; /* Number of full pages read from DB */
+int sqlite3_pager_writedb_count = 0; /* Number of full pages written to DB */
+int sqlite3_pager_writej_count = 0; /* Number of pages written to journal */
+int sqlite3_pager_pgfree_count = 0; /* Number of cache pages freed */
+# define PAGER_INCR(v) v++
#else
-# define TEST_INCR(x)
+# define PAGER_INCR(v)
#endif
+
+
/*
** Journal files begin with the following magic string. The data
** was obtained from /dev/random. It is used only as a sanity check.
@@ -348,11 +367,6 @@ static const unsigned char aJournalMagic[] = {
#endif
/*
-** The default size of a disk sector
-*/
-#define PAGER_SECTOR_SIZE 512
-
-/*
** Page number PAGER_MJ_PGNO is never used in an SQLite database (it is
** reserved for working around a windows/posix incompatibility). It is
** used in the journal to signify that the remainder of the journal file
@@ -370,14 +384,14 @@ static const unsigned char aJournalMagic[] = {
/*
** Enable reference count tracking (for debugging) here:
*/
-#ifdef SQLITE_TEST
+#ifdef SQLITE_DEBUG
int pager3_refinfo_enable = 0;
static void pager_refinfo(PgHdr *p){
static int cnt = 0;
if( !pager3_refinfo_enable ) return;
sqlite3DebugPrintf(
- "REFCNT: %4d addr=%p nRef=%d\n",
- p->pgno, PGHDR_TO_DATA(p), p->nRef
+ "REFCNT: %4d addr=%p nRef=%-3d total=%d\n",
+ p->pgno, PGHDR_TO_DATA(p), p->nRef, p->pPager->nRef
);
cnt++; /* Something to set a breakpoint on */
}
@@ -386,6 +400,21 @@ static const unsigned char aJournalMagic[] = {
# define REFINFO(X)
#endif
+/*
+** Return true if page *pPg has already been written to the statement
+** journal (or statement snapshot has been created, if *pPg is part
+** of an in-memory database).
+*/
+static int pageInStatement(PgHdr *pPg){
+ Pager *pPager = pPg->pPager;
+ if( MEMDB ){
+ return PGHDR_TO_HIST(pPg, pPager)->inStmt;
+ }else{
+ Pgno pgno = pPg->pgno;
+ u8 *a = pPager->aInStmt;
+ return (a && (int)pgno<=pPager->stmtSize && (a[pgno/8] & (1<<(pgno&7))));
+ }
+}
/*
** Change the size of the pager hash table to N. N must be a power
@@ -471,17 +500,17 @@ static u32 retrieve32bits(PgHdr *p, int offset){
** second the error-code about to be returned by a pager API function.
** The value returned is a copy of the second argument to this function.
**
-** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT or SQLITE_PROTOCOL,
+** If the second argument is SQLITE_IOERR, SQLITE_CORRUPT, or SQLITE_FULL
** the error becomes persistent. All subsequent API calls on this Pager
** will immediately return the same error code.
*/
static int pager_error(Pager *pPager, int rc){
+ int rc2 = rc & 0xff;
assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK );
- if(
- rc==SQLITE_FULL ||
- rc==SQLITE_IOERR ||
- rc==SQLITE_CORRUPT ||
- rc==SQLITE_PROTOCOL
+ if(
+ rc2==SQLITE_FULL ||
+ rc2==SQLITE_IOERR ||
+ rc2==SQLITE_CORRUPT
){
pPager->errCode = rc;
}
@@ -630,14 +659,16 @@ static int seekJournalHdr(Pager *pPager){
*/
static int writeJournalHdr(Pager *pPager){
char zHeader[sizeof(aJournalMagic)+16];
+ int rc;
+
+ if( pPager->stmtHdrOff==0 ){
+ pPager->stmtHdrOff = pPager->journalOff;
+ }
- int rc = seekJournalHdr(pPager);
+ rc = seekJournalHdr(pPager);
if( rc ) return rc;
pPager->journalHdr = pPager->journalOff;
- if( pPager->stmtHdrOff==0 ){
- pPager->stmtHdrOff = pPager->journalHdr;
- }
pPager->journalOff += JOURNAL_HDR_SZ(pPager);
/* FIX ME:
@@ -658,12 +689,14 @@ static int writeJournalHdr(Pager *pPager){
put32bits(&zHeader[sizeof(aJournalMagic)+8], pPager->dbSize);
/* The assumed sector size for this process */
put32bits(&zHeader[sizeof(aJournalMagic)+12], pPager->sectorSize);
+ IOTRACE(("JHDR %p %lld %d\n", pPager, pPager->journalHdr, sizeof(zHeader)))
rc = sqlite3OsWrite(pPager->jfd, zHeader, sizeof(zHeader));
/* The journal header has been written successfully. Seek the journal
** file descriptor to the end of the journal header sector.
*/
if( rc==SQLITE_OK ){
+ IOTRACE(("JTAIL %p %lld\n", pPager, pPager->journalOff-1))
rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff-1);
if( rc==SQLITE_OK ){
rc = sqlite3OsWrite(pPager->jfd, "\000", 1);
@@ -798,38 +831,23 @@ static int writeMasterJournal(Pager *pPager, const char *zMaster){
** statement journal.
**
** The Pager keeps a separate list of pages that are currently in
-** the statement journal. This helps the sqlite3pager_stmt_commit()
+** the statement journal. This helps the sqlite3PagerStmtCommit()
** routine run MUCH faster for the common case where there are many
** pages in memory but only a few are in the statement journal.
*/
static void page_add_to_stmt_list(PgHdr *pPg){
Pager *pPager = pPg->pPager;
- if( pPg->inStmt ) return;
- assert( pPg->pPrevStmt==0 && pPg->pNextStmt==0 );
- pPg->pPrevStmt = 0;
- if( pPager->pStmt ){
- pPager->pStmt->pPrevStmt = pPg;
- }
- pPg->pNextStmt = pPager->pStmt;
- pPager->pStmt = pPg;
- pPg->inStmt = 1;
-}
-static void page_remove_from_stmt_list(PgHdr *pPg){
- if( !pPg->inStmt ) return;
- if( pPg->pPrevStmt ){
- assert( pPg->pPrevStmt->pNextStmt==pPg );
- pPg->pPrevStmt->pNextStmt = pPg->pNextStmt;
- }else{
- assert( pPg->pPager->pStmt==pPg );
- pPg->pPager->pStmt = pPg->pNextStmt;
- }
- if( pPg->pNextStmt ){
- assert( pPg->pNextStmt->pPrevStmt==pPg );
- pPg->pNextStmt->pPrevStmt = pPg->pPrevStmt;
+ PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
+ assert( MEMDB );
+ if( !pHist->inStmt ){
+ assert( pHist->pPrevStmt==0 && pHist->pNextStmt==0 );
+ if( pPager->pStmt ){
+ PGHDR_TO_HIST(pPager->pStmt, pPager)->pPrevStmt = pPg;
+ }
+ pHist->pNextStmt = pPager->pStmt;
+ pPager->pStmt = pPg;
+ pHist->inStmt = 1;
}
- pPg->pNextStmt = 0;
- pPg->pPrevStmt = 0;
- pPg->inStmt = 0;
}
/*
@@ -847,7 +865,39 @@ static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
}
/*
-** Unlock the database and clear the in-memory cache. This routine
+** Unlock the database file.
+*/
+static void pager_unlock(Pager *pPager){
+ if( !pPager->exclusiveMode ){
+ if( !MEMDB ){
+ sqlite3OsUnlock(pPager->fd, NO_LOCK);
+ pPager->dbSize = -1;
+ IOTRACE(("UNLOCK %p\n", pPager))
+ }
+ pPager->state = PAGER_UNLOCK;
+ pPager->changeCountDone = 0;
+ }
+}
+
+/*
+** Execute a rollback if a transaction is active and unlock the
+** database file. This is a no-op if the pager has already entered
+** the error-state.
+*/
+static void pagerUnlockAndRollback(Pager *p){
+ if( p->errCode ) return;
+ assert( p->state>=PAGER_RESERVED || p->journalOpen==0 );
+ if( p->state>=PAGER_RESERVED ){
+ sqlite3PagerRollback(p);
+ }
+ pager_unlock(p);
+ assert( p->errCode || !p->journalOpen || (p->exclusiveMode&&!p->journalOff) );
+ assert( p->errCode || !p->stmtOpen || p->exclusiveMode );
+}
+
+
+/*
+** Clear the in-memory cache. This routine
** sets the state of the pager back to what it was when it was first
** opened. Any outstanding pages are invalidated and subsequent attempts
** to access those pages will likely result in a coredump.
@@ -856,9 +906,12 @@ static void pager_reset(Pager *pPager){
PgHdr *pPg, *pNext;
if( pPager->errCode ) return;
for(pPg=pPager->pAll; pPg; pPg=pNext){
+ IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno));
+ PAGER_INCR(sqlite3_pager_pgfree_count);
pNext = pPg->pNextAll;
sqliteFree(pPg);
}
+ pPager->pStmt = 0;
pPager->pFirst = 0;
pPager->pFirstSynced = 0;
pPager->pLast = 0;
@@ -867,48 +920,59 @@ static void pager_reset(Pager *pPager){
sqliteFree(pPager->aHash);
pPager->nPage = 0;
pPager->aHash = 0;
- if( pPager->state>=PAGER_RESERVED ){
- sqlite3pager_rollback(pPager);
- }
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
- pPager->dbSize = -1;
pPager->nRef = 0;
- assert( pPager->journalOpen==0 );
}
/*
+** This routine ends a transaction. A transaction is ended by either
+** a COMMIT or a ROLLBACK.
+**
** 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
-** file is deleted and closed.
+** a RESERVED or EXCLUSIVE lock on the database. This routine will release
+** the database lock and acquires a SHARED lock in its place if that is
+** the appropriate thing to do. Release locks usually is appropriate,
+** unless we are in exclusive access mode or unless this is a
+** COMMIT AND BEGIN or ROLLBACK AND BEGIN operation.
+**
+** The journal file is either deleted or truncated.
**
** TODO: Consider keeping the journal file open for temporary databases.
** This might give a performance improvement on windows where opening
** a file is an expensive operation.
*/
-static int pager_unwritelock(Pager *pPager){
+static int pager_end_transaction(Pager *pPager){
PgHdr *pPg;
- int rc;
+ int rc = SQLITE_OK;
+ int rc2 = SQLITE_OK;
assert( !MEMDB );
if( pPager->state<PAGER_RESERVED ){
return SQLITE_OK;
}
- sqlite3pager_stmt_commit(pPager);
- if( pPager->stmtOpen ){
+ sqlite3PagerStmtCommit(pPager);
+ if( pPager->stmtOpen && !pPager->exclusiveMode ){
sqlite3OsClose(&pPager->stfd);
pPager->stmtOpen = 0;
}
if( pPager->journalOpen ){
- sqlite3OsClose(&pPager->jfd);
- pPager->journalOpen = 0;
- sqlite3OsDelete(pPager->zJournal);
+ if( pPager->exclusiveMode
+ && (rc = sqlite3OsTruncate(pPager->jfd, 0))==SQLITE_OK ){;
+ sqlite3OsSeek(pPager->jfd, 0);
+ pPager->journalOff = 0;
+ pPager->journalStarted = 0;
+ }else{
+ sqlite3OsClose(&pPager->jfd);
+ pPager->journalOpen = 0;
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsDelete(pPager->zJournal);
+ }
+ }
sqliteFree( pPager->aInJournal );
pPager->aInJournal = 0;
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
pPg->inJournal = 0;
pPg->dirty = 0;
pPg->needSync = 0;
+ pPg->alwaysRollback = 0;
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
#endif
@@ -920,13 +984,20 @@ static int pager_unwritelock(Pager *pPager){
assert( pPager->aInJournal==0 );
assert( pPager->dirtyCache==0 || pPager->useJournal==0 );
}
- rc = sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
- pPager->state = PAGER_SHARED;
+
+ if( !pPager->exclusiveMode ){
+ rc2 = sqlite3OsUnlock(pPager->fd, SHARED_LOCK);
+ pPager->state = PAGER_SHARED;
+ }else if( pPager->state==PAGER_SYNCED ){
+ pPager->state = PAGER_EXCLUSIVE;
+ }
pPager->origDbSize = 0;
pPager->setMaster = 0;
pPager->needSync = 0;
pPager->pFirstSynced = pPager->pFirst;
- return rc;
+ pPager->dbSize = -1;
+
+ return (rc==SQLITE_OK?rc2:rc);
}
/*
@@ -975,17 +1046,17 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
PgHdr *pPg; /* An existing page in the cache */
Pgno pgno; /* The page number of a page in journal */
u32 cksum; /* Checksum used for sanity checking */
- u8 aData[SQLITE_MAX_PAGE_SIZE]; /* Temp storage for a page */
+ u8 *aData = (u8 *)pPager->pTmpSpace; /* 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( aData );
rc = read32bits(jfd, &pgno);
if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3OsRead(jfd, &aData, pPager->pageSize);
+ rc = sqlite3OsRead(jfd, aData, pPager->pageSize);
if( rc!=SQLITE_OK ) return rc;
pPager->journalOff += pPager->pageSize + 4;
@@ -1033,7 +1104,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
*/
pPg = pager_lookup(pPager, pgno);
assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
- TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
+ PAGERTRACE3("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);
if( rc==SQLITE_OK ){
@@ -1048,18 +1119,25 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
** for page 1 which is held in use in order to keep the lock on the
** database active. However such a page may be rolled back as a result
** of an internal error resulting in an automatic call to
- ** sqlite3pager_rollback().
+ ** sqlite3PagerRollback().
*/
void *pData;
/* assert( pPg->nRef==0 || pPg->pgno==1 ); */
pData = PGHDR_TO_DATA(pPg);
memcpy(pData, aData, pPager->pageSize);
- if( pPager->xDestructor ){ /*** FIX ME: Should this be xReinit? ***/
- pPager->xDestructor(pData, pPager->pageSize);
+ if( pPager->xReiniter ){
+ pPager->xReiniter(pPg, pPager->pageSize);
}
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
#endif
+ /* If this was page 1, then restore the value of Pager.dbFileVers.
+ ** Do this before any decoding. */
+ if( pgno==1 ){
+ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
+ }
+
+ /* Decode the page just read from disk */
CODEC1(pPager, pData, pPg->pgno, 3);
}
return rc;
@@ -1087,6 +1165,7 @@ static int pager_delmaster(const char *zMaster){
** is running this routine also. Not that it makes too much difference.
*/
rc = sqlite3OsOpenReadOnly(zMaster, &master);
+ assert( rc!=SQLITE_OK || master );
if( rc!=SQLITE_OK ) goto delmaster_out;
master_open = 1;
rc = sqlite3OsFileSize(master, &nMasterJournal);
@@ -1118,6 +1197,7 @@ static int pager_delmaster(const char *zMaster){
int c;
rc = sqlite3OsOpenReadOnly(zJournal, &journal);
+ assert( rc!=SQLITE_OK || journal );
if( rc!=SQLITE_OK ){
goto delmaster_out;
}
@@ -1139,7 +1219,7 @@ static int pager_delmaster(const char *zMaster){
}
}
- sqlite3OsDelete(zMaster);
+ rc = sqlite3OsDelete(zMaster);
delmaster_out:
if( zMasterJournal ){
@@ -1151,57 +1231,23 @@ delmaster_out:
return rc;
}
-/*
-** Make every page in the cache agree with what is on disk. In other words,
-** reread the disk to reset the state of the cache.
-**
-** This routine is called after a rollback in which some of the dirty cache
-** pages had never been written out to disk. We need to roll back the
-** cache content and the easiest way to do that is to reread the old content
-** back from the disk.
-*/
-static int pager_reload_cache(Pager *pPager){
- PgHdr *pPg;
- int rc = SQLITE_OK;
- for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
- char zBuf[SQLITE_MAX_PAGE_SIZE];
- if( !pPg->dirty ) continue;
- if( (int)pPg->pgno <= pPager->origDbSize ){
- rc = sqlite3OsSeek(pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
- if( rc==SQLITE_OK ){
- rc = sqlite3OsRead(pPager->fd, zBuf, pPager->pageSize);
- }
- TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
- if( rc ) break;
- CODEC1(pPager, zBuf, pPg->pgno, 2);
- }else{
- memset(zBuf, 0, pPager->pageSize);
- }
- if( pPg->nRef==0 || memcmp(zBuf, PGHDR_TO_DATA(pPg), pPager->pageSize) ){
- memcpy(PGHDR_TO_DATA(pPg), zBuf, pPager->pageSize);
- if( pPager->xReiniter ){
- pPager->xReiniter(PGHDR_TO_DATA(pPg), pPager->pageSize);
- }else{
- memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
- }
- }
- pPg->needSync = 0;
- pPg->dirty = 0;
-#ifdef SQLITE_CHECK_PAGES
- pPg->pageHash = pager_pagehash(pPg);
-#endif
- }
- pPager->pDirty = 0;
- return rc;
-}
+
+static void pager_truncate_cache(Pager *pPager);
/*
** Truncate the main file of the given pager to the number of pages
-** indicated.
+** indicated. Also truncate the cached representation of the file.
*/
static int pager_truncate(Pager *pPager, int nPage){
- assert( pPager->state>=PAGER_EXCLUSIVE );
- return sqlite3OsTruncate(pPager->fd, pPager->pageSize*(i64)nPage);
+ int rc = SQLITE_OK;
+ if( pPager->state>=PAGER_EXCLUSIVE ){
+ rc = sqlite3OsTruncate(pPager->fd, pPager->pageSize*(i64)nPage);
+ }
+ if( rc==SQLITE_OK ){
+ pPager->dbSize = nPage;
+ pager_truncate_cache(pPager);
+ }
+ return rc;
}
/*
@@ -1257,7 +1303,7 @@ static int pager_truncate(Pager *pPager, int nPage){
** If an I/O or malloc() error occurs, the journal-file is not deleted
** and an error code is returned.
*/
-static int pager_playback(Pager *pPager){
+static int pager_playback(Pager *pPager, int isHot){
i64 szJ; /* Size of the journal file in bytes */
u32 nRec; /* Number of Records in the journal */
int i; /* Loop counter */
@@ -1270,7 +1316,7 @@ static int pager_playback(Pager *pPager){
*/
assert( pPager->journalOpen );
rc = sqlite3OsFileSize(pPager->jfd, &szJ);
- if( rc!=SQLITE_OK ){
+ if( rc!=SQLITE_OK || szJ==0 ){
goto end_playback;
}
@@ -1317,17 +1363,22 @@ static int pager_playback(Pager *pPager){
nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager);
}
+ /* If nRec is 0 and this rollback is of a transaction created by this
+ ** process. In this case the rest of the journal file consists of
+ ** journalled copies of pages that need to be read back into the cache.
+ */
+ if( nRec==0 && !isHot ){
+ nRec = (szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager);
+ }
+
/* If this is the first header read from the journal, truncate the
** database file back to it's original size.
*/
- if( pPager->state>=PAGER_EXCLUSIVE &&
- pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
- assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg );
+ if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){
rc = pager_truncate(pPager, mxPg);
if( rc!=SQLITE_OK ){
goto end_playback;
}
- pPager->dbSize = mxPg;
}
/* Copy original pages out of the journal and back into the database file.
@@ -1350,10 +1401,10 @@ static int pager_playback(Pager *pPager){
end_playback:
if( rc==SQLITE_OK ){
- rc = pager_unwritelock(pPager);
+ rc = pager_end_transaction(pPager);
}
if( zMaster ){
- /* If there was a master journal and this routine will return true,
+ /* If there was a master journal and this routine will return success,
** see if it is possible to delete the master journal.
*/
if( rc==SQLITE_OK ){
@@ -1363,10 +1414,10 @@ end_playback:
}
/* The Pager.sectorSize variable may have been updated while rolling
- ** back a journal created by a process with a different PAGER_SECTOR_SIZE
+ ** back a journal created by a process with a different sector size
** value. Reset it to the correct value for this process.
*/
- pPager->sectorSize = PAGER_SECTOR_SIZE;
+ pPager->sectorSize = sqlite3OsSectorSize(pPager->fd);
return rc;
}
@@ -1401,8 +1452,9 @@ static int pager_stmt_playback(Pager *pPager){
}
#endif
- /* Set hdrOff to be the offset to the first journal header written
- ** this statement transaction, or the end of the file if no journal
+ /* Set hdrOff to be the offset just after the end of the last journal
+ ** page written before the first journal-header for this statement
+ ** transaction was written, or the end of the file if no journal
** header was written.
*/
hdrOff = pPager->stmtHdrOff;
@@ -1413,10 +1465,8 @@ static int pager_stmt_playback(Pager *pPager){
/* Truncate the database back to its original size.
*/
- if( pPager->state>=PAGER_EXCLUSIVE ){
- rc = pager_truncate(pPager, pPager->stmtSize);
- }
- pPager->dbSize = pPager->stmtSize;
+ rc = pager_truncate(pPager, pPager->stmtSize);
+ assert( pPager->state>=PAGER_SHARED );
/* Figure out how many records are in the statement journal.
*/
@@ -1449,8 +1499,7 @@ static int pager_stmt_playback(Pager *pPager){
}
pPager->journalOff = pPager->stmtJSize;
pPager->cksumInit = pPager->stmtCksum;
- assert( JOURNAL_HDR_SZ(pPager)<(pPager->pageSize+8) );
- while( pPager->journalOff <= (hdrOff-(pPager->pageSize+8)) ){
+ while( pPager->journalOff < hdrOff ){
rc = pager_playback_one_page(pPager, pPager->jfd, 1);
assert( rc!=SQLITE_DONE );
if( rc!=SQLITE_OK ) goto end_stmt_playback;
@@ -1487,7 +1536,7 @@ end_stmt_playback:
/*
** Change the maximum number of in-memory pages that are allowed.
*/
-void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
+void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
if( mxPage>10 ){
pPager->mxPage = mxPage;
}else{
@@ -1522,7 +1571,7 @@ void sqlite3pager_set_cachesize(Pager *pPager, int mxPage){
** and FULL=3.
*/
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
-void sqlite3pager_set_safety_level(Pager *pPager, int level, int full_fsync){
+void sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int full_fsync){
pPager->noSync = level==1 || pPager->tempFile;
pPager->fullSync = level==3 && !pPager->tempFile;
pPager->full_fsync = full_fsync;
@@ -1540,17 +1589,19 @@ int sqlite3_opentemp_count = 0;
#endif
/*
-** Open a temporary file. Write the name of the file into zFile
-** (zFile must be at least SQLITE_TEMPNAME_SIZE bytes long.) Write
-** the file descriptor into *fd. Return SQLITE_OK on success or some
+** Open a temporary file.
+**
+** Write the file descriptor into *fd. Return SQLITE_OK on success or some
** other error code if we fail.
**
** The OS will automatically delete the temporary file when it is
** closed.
*/
-static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){
+static int sqlite3PagerOpentemp(OsFile **pFd){
int cnt = 8;
int rc;
+ char zFile[SQLITE_TEMPNAME_SIZE];
+
#ifdef SQLITE_TEST
sqlite3_opentemp_count++; /* Used for testing and analysis only */
#endif
@@ -1558,6 +1609,7 @@ static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){
cnt--;
sqlite3OsTempFileName(zFile);
rc = sqlite3OsOpenExclusive(zFile, pFd, 1);
+ assert( rc!=SQLITE_OK || *pFd );
}while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM );
return rc;
}
@@ -1565,8 +1617,8 @@ static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){
/*
** Create a new page cache and put a pointer to the page cache in *ppPager.
** The file to be cached need not exist. The file is not locked until
-** the first call to sqlite3pager_get() and is only held open until the
-** last page is released using sqlite3pager_unref().
+** the first call to sqlite3PagerGet() and is only held open until the
+** last page is released using sqlite3PagerUnref().
**
** If zFilename is NULL then a randomly-named temporary file is created
** and used as the file to be cached. The file will be deleted
@@ -1576,7 +1628,7 @@ static int sqlite3pager_opentemp(char *zFile, OsFile **pFd){
** It is never written to disk. This can be used to implement an
** in-memory database.
*/
-int sqlite3pager_open(
+int sqlite3PagerOpen(
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 */
@@ -1585,7 +1637,7 @@ int sqlite3pager_open(
Pager *pPager = 0;
char *zFullPathname = 0;
int nameLen; /* Compiler is wrong. This is always initialized before use */
- OsFile *fd;
+ OsFile *fd = 0;
int rc = SQLITE_OK;
int i;
int tempFile = 0;
@@ -1606,15 +1658,13 @@ int sqlite3pager_open(
assert( pTsd );
#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.
+ /* We used to test if malloc() had already failed before proceeding.
+ ** But the way this function is used in SQLite means that can never
+ ** happen. Furthermore, if the malloc-failed flag is already set,
+ ** either the call to sqliteStrDup() or sqliteMalloc() below will
+ ** fail shortly and SQLITE_NOMEM returned anyway.
*/
*ppPager = 0;
- if( sqlite3MallocFailed() ){
- 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).
@@ -1630,10 +1680,12 @@ int sqlite3pager_open(
zFullPathname = sqlite3OsFullPathname(zFilename);
if( zFullPathname ){
rc = sqlite3OsOpenReadWrite(zFullPathname, &fd, &readOnly);
+ assert( rc!=SQLITE_OK || fd );
}
}
}else{
- rc = sqlite3pager_opentemp(zTemp, &fd);
+ rc = sqlite3PagerOpentemp(&fd);
+ sqlite3OsTempFileName(zTemp);
zFilename = zTemp;
zFullPathname = sqlite3OsFullPathname(zFilename);
if( rc==SQLITE_OK ){
@@ -1648,21 +1700,26 @@ int sqlite3pager_open(
if( zFullPathname ){
nameLen = strlen(zFullPathname);
pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 );
+ if( pPager && rc==SQLITE_OK ){
+ pPager->pTmpSpace = (char *)sqliteMallocRaw(SQLITE_DEFAULT_PAGE_SIZE);
+ }
}
+
/* 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 ){
+ if( !pPager || !zFullPathname || !pPager->pTmpSpace || rc!=SQLITE_OK ){
sqlite3OsClose(&fd);
sqliteFree(zFullPathname);
sqliteFree(pPager);
return ((rc==SQLITE_OK)?SQLITE_NOMEM:rc);
}
- TRACE3("OPEN %d %s\n", FILEHANDLEID(fd), zFullPathname);
+ PAGERTRACE3("OPEN %d %s\n", FILEHANDLEID(fd), zFullPathname);
+ IOTRACE(("OPEN %p %s\n", pPager, zFullPathname))
pPager->zFilename = (char*)&pPager[1];
pPager->zDirectory = &pPager->zFilename[nameLen+1];
pPager->zJournal = &pPager->zDirectory[nameLen+1];
@@ -1692,6 +1749,10 @@ int sqlite3pager_open(
/* pPager->state = PAGER_UNLOCK; */
/* pPager->errMask = 0; */
pPager->tempFile = tempFile;
+ assert( tempFile==PAGER_LOCKINGMODE_NORMAL
+ || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE );
+ assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 );
+ pPager->exclusiveMode = tempFile;
pPager->memDb = memDb;
pPager->readOnly = readOnly;
/* pPager->needSync = 0; */
@@ -1701,7 +1762,10 @@ int sqlite3pager_open(
/* pPager->pFirstSynced = 0; */
/* pPager->pLast = 0; */
pPager->nExtra = FORCE_ALIGNMENT(nExtra);
- pPager->sectorSize = PAGER_SECTOR_SIZE;
+ assert(fd||memDb);
+ if( !memDb ){
+ pPager->sectorSize = sqlite3OsSectorSize(fd);
+ }
/* pPager->pBusyHandler = 0; */
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
*ppPager = pPager;
@@ -1715,7 +1779,7 @@ int sqlite3pager_open(
/*
** Set the busy handler function.
*/
-void sqlite3pager_set_busyhandler(Pager *pPager, BusyHandler *pBusyHandler){
+void sqlite3PagerSetBusyhandler(Pager *pPager, BusyHandler *pBusyHandler){
pPager->pBusyHandler = pBusyHandler;
}
@@ -1724,10 +1788,10 @@ void sqlite3pager_set_busyhandler(Pager *pPager, BusyHandler *pBusyHandler){
** when the reference count on each page reaches zero. The destructor can
** be used to clean up information in the extra segment appended to each page.
**
-** The destructor is not called as a result sqlite3pager_close().
-** Destructors are only called by sqlite3pager_unref().
+** The destructor is not called as a result sqlite3PagerClose().
+** Destructors are only called by sqlite3PagerUnref().
*/
-void sqlite3pager_set_destructor(Pager *pPager, void (*xDesc)(void*,int)){
+void sqlite3PagerSetDestructor(Pager *pPager, void (*xDesc)(DbPage*,int)){
pPager->xDestructor = xDesc;
}
@@ -1738,7 +1802,7 @@ void sqlite3pager_set_destructor(Pager *pPager, void (*xDesc)(void*,int)){
** an opportunity to restore the EXTRA section to agree with the restored
** page data.
*/
-void sqlite3pager_set_reiniter(Pager *pPager, void (*xReinit)(void*,int)){
+void sqlite3PagerSetReiniter(Pager *pPager, void (*xReinit)(DbPage*,int)){
pPager->xReiniter = xReinit;
}
@@ -1747,10 +1811,12 @@ void sqlite3pager_set_reiniter(Pager *pPager, void (*xReinit)(void*,int)){
** size is inappropriate, then an alternative page size is selected
** and returned.
*/
-int sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
+int sqlite3PagerSetPagesize(Pager *pPager, int pageSize){
assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE );
- if( !pPager->memDb ){
+ if( !pPager->memDb && pPager->nRef==0 ){
+ pager_reset(pPager);
pPager->pageSize = pageSize;
+ pPager->pTmpSpace = sqlite3ReallocOrFree(pPager->pTmpSpace, pageSize);
}
return pPager->pageSize;
}
@@ -1767,9 +1833,6 @@ int sqlite3pager_set_pagesize(Pager *pPager, int pageSize){
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;
@@ -1778,7 +1841,6 @@ 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
@@ -1793,14 +1855,20 @@ void enable_simulated_io_errors(void){
** 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){
+int sqlite3PagerReadFileheader(Pager *pPager, int N, unsigned char *pDest){
+ int rc = SQLITE_OK;
memset(pDest, 0, N);
if( MEMDB==0 ){
disable_simulated_io_errors();
sqlite3OsSeek(pPager->fd, 0);
- sqlite3OsRead(pPager->fd, pDest, N);
enable_simulated_io_errors();
+ IOTRACE(("DBHDR %p 0 %d\n", pPager, N))
+ rc = sqlite3OsRead(pPager->fd, pDest, N);
+ if( rc==SQLITE_IOERR_SHORT_READ ){
+ rc = SQLITE_OK;
+ }
}
+ return rc;
}
/*
@@ -1812,14 +1880,18 @@ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
** PENDING_BYTE is byte 4096 (the first byte of page 5) and the size of the
** file is 4096 bytes, 5 is returned instead of 4.
*/
-int sqlite3pager_pagecount(Pager *pPager){
+int sqlite3PagerPagecount(Pager *pPager){
i64 n;
+ int rc;
assert( pPager!=0 );
+ if( pPager->errCode ){
+ return 0;
+ }
if( pPager->dbSize>=0 ){
n = pPager->dbSize;
} else {
- if( sqlite3OsFileSize(pPager->fd, &n)!=SQLITE_OK ){
- pager_error(pPager, SQLITE_IOERR);
+ if( (rc = sqlite3OsFileSize(pPager->fd, &n))!=SQLITE_OK ){
+ pager_error(pPager, rc);
return 0;
}
if( n>0 && n<pPager->pageSize ){
@@ -1860,7 +1932,7 @@ static int syncJournal(Pager*);
/*
** Unlink pPg from it's hash chain. Also set the page number to 0 to indicate
** that the page is not part of any hash chain. This is required because the
-** sqlite3pager_movepage() routine can leave a page in the
+** sqlite3PagerMovepage() routine can leave a page in the
** pNextFree/pPrevFree list that is not a part of any hash-chain.
*/
static void unlinkHashChain(Pager *pPager, PgHdr *pPg){
@@ -1918,13 +1990,19 @@ static void unlinkPage(PgHdr *pPg){
unlinkHashChain(pPager, pPg);
}
-#ifndef SQLITE_OMIT_MEMORYDB
/*
-** This routine is used to truncate an in-memory database. Delete
-** all pages whose pgno is larger than pPager->dbSize and is unreferenced.
+** This routine is used to truncate the cache when a database
+** is truncated. Drop from the cache all pages whose pgno is
+** larger than pPager->dbSize and is unreferenced.
+**
** Referenced pages larger than pPager->dbSize are zeroed.
+**
+** Actually, at the point this routine is called, it would be
+** an error to have a referenced page. But rather than delete
+** that page and guarantee a subsequent segfault, it seems better
+** to zero it and hope that we error out sanely.
*/
-static void memoryTruncate(Pager *pPager){
+static void pager_truncate_cache(Pager *pPager){
PgHdr *pPg;
PgHdr **ppPg;
int dbSize = pPager->dbSize;
@@ -1938,6 +2016,8 @@ static void memoryTruncate(Pager *pPager){
ppPg = &pPg->pNextAll;
}else{
*ppPg = pPg->pNextAll;
+ IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno));
+ PAGER_INCR(sqlite3_pager_pgfree_count);
unlinkPage(pPg);
makeClean(pPg);
sqliteFree(pPg);
@@ -1945,9 +2025,6 @@ static void memoryTruncate(Pager *pPager){
}
}
}
-#else
-#define memoryTruncate(p)
-#endif
/*
** Try to obtain a lock on a file. Invoke the busy callback if the lock
@@ -1959,9 +2036,15 @@ static void memoryTruncate(Pager *pPager){
*/
static int pager_wait_on_lock(Pager *pPager, int locktype){
int rc;
+
+ /* The OS lock values must be the same as the Pager lock values */
assert( PAGER_SHARED==SHARED_LOCK );
assert( PAGER_RESERVED==RESERVED_LOCK );
assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK );
+
+ /* If the file is currently unlocked then the size must be unknown */
+ assert( pPager->state>=PAGER_SHARED || pPager->dbSize<0 || MEMDB );
+
if( pPager->state>=locktype ){
rc = SQLITE_OK;
}else{
@@ -1970,6 +2053,7 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
}while( rc==SQLITE_BUSY && sqlite3InvokeBusyHandler(pPager->pBusyHandler) );
if( rc==SQLITE_OK ){
pPager->state = locktype;
+ IOTRACE(("LOCK %p %d\n", pPager, locktype))
}
}
return rc;
@@ -1978,9 +2062,10 @@ static int pager_wait_on_lock(Pager *pPager, int locktype){
/*
** Truncate the file to the number of pages specified.
*/
-int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
+int sqlite3PagerTruncate(Pager *pPager, Pgno nPage){
int rc;
- sqlite3pager_pagecount(pPager);
+ assert( pPager->state>=PAGER_SHARED || MEMDB );
+ sqlite3PagerPagecount(pPager);
if( pPager->errCode ){
rc = pPager->errCode;
return rc;
@@ -1990,7 +2075,7 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
}
if( MEMDB ){
pPager->dbSize = nPage;
- memoryTruncate(pPager);
+ pager_truncate_cache(pPager);
return SQLITE_OK;
}
rc = syncJournal(pPager);
@@ -2005,9 +2090,6 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
}
rc = pager_truncate(pPager, nPage);
- if( rc==SQLITE_OK ){
- pPager->dbSize = nPage;
- }
return rc;
}
@@ -2025,8 +2107,7 @@ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){
** 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;
+int sqlite3PagerClose(Pager *pPager){
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
/* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to
** malloc() must have already been made by this thread before it gets
@@ -2038,47 +2119,14 @@ int sqlite3pager_close(Pager *pPager){
assert( pTsd && pTsd->nAlloc );
#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.
- */
- disable_simulated_io_errors();
- sqlite3pager_rollback(pPager);
- enable_simulated_io_errors();
- if( !MEMDB ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- }
- assert( pPager->errCode || pPager->journalOpen==0 );
- break;
- }
- case PAGER_SHARED: {
- if( !MEMDB ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- }
- break;
- }
- default: {
- /* Do nothing */
- break;
- }
- }
- for(pPg=pPager->pAll; pPg; pPg=pNext){
-#ifndef NDEBUG
- if( MEMDB ){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- assert( !pPg->alwaysRollback );
- assert( !pHist->pOrig );
- assert( !pHist->pStmt );
- }
-#endif
- pNext = pPg->pNextAll;
- sqliteFree(pPg);
- }
- TRACE2("CLOSE %d\n", PAGERID(pPager));
+ disable_simulated_io_errors();
+ pPager->errCode = 0;
+ pPager->exclusiveMode = 0;
+ pager_reset(pPager);
+ pagerUnlockAndRollback(pPager);
+ enable_simulated_io_errors();
+ PAGERTRACE2("CLOSE %d\n", PAGERID(pPager));
+ IOTRACE(("CLOSE %p\n", pPager))
assert( pPager->errCode || (pPager->journalOpen==0 && pPager->stmtOpen==0) );
if( pPager->journalOpen ){
sqlite3OsClose(&pPager->jfd);
@@ -2107,6 +2155,7 @@ int sqlite3pager_close(Pager *pPager){
}
#endif
sqliteFree(pPager->aHash);
+ sqliteFree(pPager->pTmpSpace);
sqliteFree(pPager);
return SQLITE_OK;
}
@@ -2114,8 +2163,7 @@ int sqlite3pager_close(Pager *pPager){
/*
** Return the page number for the given page data.
*/
-Pgno sqlite3pager_pagenumber(void *pData){
- PgHdr *p = DATA_TO_PGHDR(pData);
+Pgno sqlite3PagerPagenumber(DbPage *p){
return p->pgno;
}
@@ -2168,8 +2216,7 @@ static void _page_ref(PgHdr *pPg){
** Increment the reference count for a page. The input pointer is
** a reference to the page data.
*/
-int sqlite3pager_ref(void *pData){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
+int sqlite3PagerRef(DbPage *pPg){
page_ref(pPg);
return SQLITE_OK;
}
@@ -2224,20 +2271,24 @@ static int syncJournal(Pager *pPager){
** it as a candidate for rollback.
*/
if( pPager->fullSync ){
- TRACE2("SYNC journal of %d\n", PAGERID(pPager));
+ PAGERTRACE2("SYNC journal of %d\n", PAGERID(pPager));
+ IOTRACE(("JSYNC %p\n", pPager))
rc = sqlite3OsSync(pPager->jfd, 0);
if( rc!=0 ) return rc;
}
rc = sqlite3OsSeek(pPager->jfd,
pPager->journalHdr + sizeof(aJournalMagic));
if( rc ) return rc;
+ IOTRACE(("JHDR %p %lld %d\n", pPager,
+ pPager->journalHdr + sizeof(aJournalMagic), 4))
rc = write32bits(pPager->jfd, pPager->nRec);
if( rc ) return rc;
rc = sqlite3OsSeek(pPager->jfd, pPager->journalOff);
if( rc ) return rc;
}
- TRACE2("SYNC journal of %d\n", PAGERID(pPager));
+ PAGERTRACE2("SYNC journal of %d\n", PAGERID(pPager));
+ IOTRACE(("JSYNC %d\n", pPager))
rc = sqlite3OsSync(pPager->jfd, pPager->full_fsync);
if( rc!=0 ) return rc;
pPager->journalStarted = 1;
@@ -2301,9 +2352,16 @@ static PgHdr *merge_pagelist(PgHdr *pA, PgHdr *pB){
** connected by pDirty pointers. The pPrevDirty pointers are
** corrupted by this sort.
*/
-#define N_SORT_BUCKET 25
+#define N_SORT_BUCKET_ALLOC 25
+#define N_SORT_BUCKET 25
+#ifdef SQLITE_TEST
+ int sqlite3_pager_n_sort_bucket = 0;
+ #undef N_SORT_BUCKET
+ #define N_SORT_BUCKET \
+ (sqlite3_pager_n_sort_bucket?sqlite3_pager_n_sort_bucket:N_SORT_BUCKET_ALLOC)
+#endif
static PgHdr *sort_pagelist(PgHdr *pIn){
- PgHdr *a[N_SORT_BUCKET], *p;
+ PgHdr *a[N_SORT_BUCKET_ALLOC], *p;
int i;
memset(a, 0, sizeof(a));
while( pIn ){
@@ -2320,6 +2378,11 @@ static PgHdr *sort_pagelist(PgHdr *pIn){
}
}
if( i==N_SORT_BUCKET-1 ){
+ /* Coverage: To get here, there need to be 2^(N_SORT_BUCKET)
+ ** elements in the input list. This is possible, but impractical.
+ ** Testing this line is the point of global variable
+ ** sqlite3_pager_n_sort_bucket.
+ */
a[i] = merge_pagelist(a[i], p);
}
}
@@ -2369,19 +2432,24 @@ static int pager_write_pagelist(PgHdr *pList){
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
+ ** than Pager.dbSize, this means sqlite3PagerTruncate() 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 ){
char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
- TRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno);
+ PAGERTRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno);
+ IOTRACE(("PGOUT %p %d\n", pPager, pList->pgno));
rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize);
- TEST_INCR(pPager->nWrite);
+ PAGER_INCR(sqlite3_pager_writedb_count);
+ PAGER_INCR(pPager->nWrite);
+ if( pList->pgno==1 ){
+ memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
+ }
}
#ifndef NDEBUG
else{
- TRACE3("NOSTORE %d page %d\n", PAGERID(pPager), pList->pgno);
+ PAGERTRACE3("NOSTORE %d page %d\n", PAGERID(pPager), pList->pgno);
}
#endif
if( rc ) return rc;
@@ -2413,9 +2481,13 @@ static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
*/
static int hasHotJournal(Pager *pPager){
if( !pPager->useJournal ) return 0;
- if( !sqlite3OsFileExists(pPager->zJournal) ) return 0;
- if( sqlite3OsCheckReservedLock(pPager->fd) ) return 0;
- if( sqlite3pager_pagecount(pPager)==0 ){
+ if( !sqlite3OsFileExists(pPager->zJournal) ){
+ return 0;
+ }
+ if( sqlite3OsCheckReservedLock(pPager->fd) ){
+ return 0;
+ }
+ if( sqlite3PagerPagecount(pPager)==0 ){
sqlite3OsDelete(pPager->zJournal);
return 0;
}else{
@@ -2433,6 +2505,8 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
PgHdr *pPg;
*ppPg = 0;
+ assert(!MEMDB);
+
/* Find a page to recycle. Try to locate a page that does not
** require us to do an fsync() on the journal.
*/
@@ -2457,6 +2531,7 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
*/
pPager->nRec = 0;
assert( pPager->journalOff > 0 );
+ assert( pPager->doNotSync==0 );
rc = writeJournalHdr(pPager);
if( rc!=0 ){
return rc;
@@ -2487,20 +2562,21 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
/* 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.
+ ** sqlite3PagerDontRollback() 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 ){
+ IOTRACE(("ALWAYS_ROLLBACK %p\n", pPager))
pPager->alwaysRollback = 1;
}
/* Unlink the old page from the free list and the hash table
*/
unlinkPage(pPg);
- TEST_INCR(pPager->nOvfl);
+ assert( pPg->pgno==0 );
*ppPg = pPg;
return SQLITE_OK;
@@ -2517,9 +2593,8 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
** of bytes of memory released.
*/
#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT
-int sqlite3pager_release_memory(int nReq){
+int sqlite3PagerReleaseMemory(int nReq){
const ThreadData *pTsdro = sqlite3ThreadDataReadOnly();
- Pager *p;
int nReleased = 0;
int i;
@@ -2541,15 +2616,20 @@ int sqlite3pager_release_memory(int nReq){
for(i=0; i<=1; i++){
/* Loop through all the SQLite pagers opened by the current thread. */
- for(p=pTsdro->pPager; p && (nReq<0 || nReleased<nReq); p=p->pNext){
+ Pager *pPager = pTsdro->pPager;
+ for( ; pPager && (nReq<0 || nReleased<nReq); pPager=pPager->pNext){
PgHdr *pPg;
int rc;
+ if( MEMDB ){
+ continue;
+ }
+
/* 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) {
+ while( SQLITE_OK==(rc = pager_recycle(pPager, 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.
@@ -2560,14 +2640,15 @@ int sqlite3pager_release_memory(int nReq){
*/
PgHdr *pTmp;
assert( pPg );
- page_remove_from_stmt_list(pPg);
- if( pPg==p->pAll ){
- p->pAll = pPg->pNextAll;
+ if( pPg==pPager->pAll ){
+ pPager->pAll = pPg->pNextAll;
}else{
- for( pTmp=p->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ){}
+ for( pTmp=pPager->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ){}
pTmp->pNextAll = pPg->pNextAll;
}
nReleased += sqliteAllocSize(pPg);
+ IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno));
+ PAGER_INCR(sqlite3_pager_pgfree_count);
sqliteFree(pPg);
}
@@ -2578,9 +2659,9 @@ int sqlite3pager_release_memory(int nReq){
** 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);
+ assert( (rc&0xff)==SQLITE_IOERR || rc==SQLITE_FULL );
+ assert( pPager->state>=PAGER_RESERVED );
+ pager_error(pPager, rc);
}
}
}
@@ -2590,6 +2671,258 @@ int sqlite3pager_release_memory(int nReq){
#endif /* SQLITE_ENABLE_MEMORY_MANAGEMENT */
/*
+** Read the content of page pPg out of the database file.
+*/
+static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){
+ int rc;
+ assert( MEMDB==0 );
+ rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg),
+ pPager->pageSize);
+ }
+ PAGER_INCR(sqlite3_pager_readdb_count);
+ PAGER_INCR(pPager->nRead);
+ IOTRACE(("PGIN %p %d\n", pPager, pgno));
+ PAGERTRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
+ if( pgno==1 ){
+ memcpy(&pPager->dbFileVers, &((u8*)PGHDR_TO_DATA(pPg))[24],
+ sizeof(pPager->dbFileVers));
+ }
+ CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
+ return rc;
+}
+
+
+/*
+** This function is called to obtain the shared lock required before
+** data may be read from the pager cache. If the shared lock has already
+** been obtained, this function is a no-op.
+**
+** Immediately after obtaining the shared lock (if required), this function
+** checks for a hot-journal file. If one is found, an emergency rollback
+** is performed immediately.
+*/
+static int pagerSharedLock(Pager *pPager){
+ int rc = SQLITE_OK;
+
+ if( pPager->state==PAGER_UNLOCK ){
+ if( !MEMDB ){
+ assert( pPager->nRef==0 );
+ if( !pPager->noReadlock ){
+ rc = pager_wait_on_lock(pPager, SHARED_LOCK);
+ if( rc!=SQLITE_OK ){
+ return pager_error(pPager, rc);
+ }
+ assert( pPager->state>=SHARED_LOCK );
+ }
+
+ /* 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.
+ */
+ if( hasHotJournal(pPager) ){
+ /* Get an EXCLUSIVE lock on the database file. At this point it is
+ ** important that a RESERVED lock is not obtained on the way to the
+ ** EXCLUSIVE lock. If it were, another process might open the
+ ** database file, detect the RESERVED lock, and conclude that the
+ ** database is safe to read while this process is still rolling it
+ ** back.
+ **
+ ** Because the intermediate RESERVED lock is not requested, the
+ ** second process will get to this point in the code and fail to
+ ** obtain it's own EXCLUSIVE lock on the database file.
+ */
+ rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
+ if( rc!=SQLITE_OK ){
+ pager_unlock(pPager);
+ 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.
+ **
+ ** The journal file does not need to be locked itself. The
+ ** journal file is never open unless the main database file holds
+ ** a write lock, so there is never any chance of two or more
+ ** processes opening the journal at the same time.
+ **
+ ** Open the journal for read/write access. This is because in
+ ** exclusive-access mode the file descriptor will be kept open and
+ ** possibly used for a transaction later on. On some systems, the
+ ** OsTruncate() call used in exclusive-access mode also requires
+ ** a read/write file handle.
+ */
+ rc = SQLITE_BUSY;
+ if( sqlite3OsFileExists(pPager->zJournal) ){
+ int ro;
+ assert( !pPager->tempFile );
+ rc = sqlite3OsOpenReadWrite(pPager->zJournal, &pPager->jfd, &ro);
+ assert( rc!=SQLITE_OK || pPager->jfd );
+ if( ro ){
+ rc = SQLITE_BUSY;
+ sqlite3OsClose(&pPager->jfd);
+ }
+ }
+ if( rc!=SQLITE_OK ){
+ pager_unlock(pPager);
+ return SQLITE_BUSY;
+ }
+ pPager->journalOpen = 1;
+ pPager->journalStarted = 0;
+ pPager->journalOff = 0;
+ pPager->setMaster = 0;
+ pPager->journalHdr = 0;
+
+ /* Playback and delete the journal. Drop the database write
+ ** lock and reacquire the read lock.
+ */
+ rc = pager_playback(pPager, 1);
+ if( rc!=SQLITE_OK ){
+ return pager_error(pPager, rc);
+ }
+ assert(pPager->state==PAGER_SHARED ||
+ (pPager->exclusiveMode && pPager->state>PAGER_SHARED)
+ );
+ }
+
+ if( pPager->pAll ){
+ /* The shared-lock has just been acquired on the database file
+ ** and there are already pages in the cache (from a previous
+ ** read or write transaction). Check to see if the database
+ ** has been modified. If the database has changed, flush the
+ ** cache.
+ **
+ ** Database changes is detected by looking at 15 bytes beginning
+ ** at offset 24 into the file. The first 4 of these 16 bytes are
+ ** a 32-bit counter that is incremented with each change. The
+ ** other bytes change randomly with each file change when
+ ** a codec is in use.
+ **
+ ** There is a vanishingly small chance that a change will not be
+ ** deteched. The chance of an undetected change is so small that
+ ** it can be neglected.
+ */
+ char dbFileVers[sizeof(pPager->dbFileVers)];
+ sqlite3PagerPagecount(pPager);
+
+ if( pPager->errCode ){
+ return pPager->errCode;
+ }
+
+ if( pPager->dbSize>0 ){
+ rc = sqlite3OsSeek(pPager->fd, 24);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers));
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ }else{
+ memset(dbFileVers, 0, sizeof(dbFileVers));
+ }
+
+ if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
+ pager_reset(pPager);
+ }
+ }
+ }
+ assert( pPager->exclusiveMode || pPager->state<=PAGER_SHARED );
+ if( pPager->state==PAGER_UNLOCK ){
+ pPager->state = PAGER_SHARED;
+ }
+ }
+
+ return rc;
+}
+
+/*
+** Allocate a PgHdr object. Either create a new one or reuse
+** an existing one that is not otherwise in use.
+**
+** A new PgHdr structure is created if any of the following are
+** true:
+**
+** (1) We have not exceeded our maximum allocated cache size
+** as set by the "PRAGMA cache_size" command.
+**
+** (2) There are no unused PgHdr objects available at this time.
+**
+** (3) This is an in-memory database.
+**
+** (4) There are no PgHdr objects that do not require a journal
+** file sync and a sync of the journal file is currently
+** prohibited.
+**
+** Otherwise, reuse an existing PgHdr. In other words, reuse an
+** existing PgHdr if all of the following are true:
+**
+** (1) We have reached or exceeded the maximum cache size
+** allowed by "PRAGMA cache_size".
+**
+** (2) There is a PgHdr available with PgHdr->nRef==0
+**
+** (3) We are not in an in-memory database
+**
+** (4) Either there is an available PgHdr that does not need
+** to be synced to disk or else disk syncing is currently
+** allowed.
+*/
+static int pagerAllocatePage(Pager *pPager, PgHdr **ppPg){
+ int rc = SQLITE_OK;
+ PgHdr *pPg;
+
+ /* Create a new PgHdr if any of the four conditions defined
+ ** above is met: */
+ if( pPager->nPage<pPager->mxPage
+ || pPager->pFirst==0
+ || MEMDB
+ || (pPager->pFirstSynced==0 && pPager->doNotSync)
+ ){
+ if( pPager->nPage>=pPager->nHash ){
+ pager_resize_hash_table(pPager,
+ pPager->nHash<256 ? 256 : pPager->nHash*2);
+ if( pPager->nHash==0 ){
+ rc = SQLITE_NOMEM;
+ goto pager_allocate_out;
+ }
+ }
+ pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize
+ + sizeof(u32) + pPager->nExtra
+ + MEMDB*sizeof(PgHistory) );
+ if( pPg==0 ){
+ rc = SQLITE_NOMEM;
+ goto pager_allocate_out;
+ }
+ memset(pPg, 0, sizeof(*pPg));
+ if( MEMDB ){
+ memset(PGHDR_TO_HIST(pPg, pPager), 0, sizeof(PgHistory));
+ }
+ pPg->pPager = pPager;
+ pPg->pNextAll = pPager->pAll;
+ pPager->pAll = pPg;
+ pPager->nPage++;
+ if( pPager->nPage>pPager->nMaxPage ){
+ assert( pPager->nMaxPage==(pPager->nPage-1) );
+ pPager->nMaxPage++;
+ }
+ }else{
+ /* Recycle an existing page with a zero ref-count. */
+ rc = pager_recycle(pPager, 1, &pPg);
+ if( rc!=SQLITE_OK ){
+ goto pager_allocate_out;
+ }
+ assert( pPager->state>=SHARED_LOCK );
+ assert(pPg);
+ }
+ *ppPg = pPg;
+
+pager_allocate_out:
+ return rc;
+}
+
+/*
** Acquire a page.
**
** A read lock on the disk file is obtained when the first page is acquired.
@@ -2604,18 +2937,33 @@ int sqlite3pager_release_memory(int nReq){
** The acquisition might fail for several reasons. In all cases,
** an appropriate error code is returned and *ppPage is set to NULL.
**
-** See also sqlite3pager_lookup(). Both this routine and _lookup() attempt
+** See also sqlite3PagerLookup(). Both this routine and _lookup() attempt
** to find a page in the in-memory cache first. If the page is not already
** in memory, this routine goes to disk to read it in whereas _lookup()
** just returns 0. This routine acquires a read-lock the first time it
** has to go to disk, and could also playback an old journal if necessary.
** Since _lookup() never goes to disk, it never has to deal with locks
** or journal files.
+**
+** If noContent is false, the page contents are actually read from disk.
+** If noContent is true, it means that we do not care about the contents
+** of the page at this time, so do not do a disk read. Just fill in the
+** page content with zeros. But mark the fact that we have not read the
+** content by setting the PgHdr.needRead flag. Later on, if
+** sqlite3PagerWrite() is called on this page, that means that the
+** content is needed and the disk read should occur at that point.
*/
-int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
+int sqlite3PagerAcquire(
+ Pager *pPager, /* The pager open on the database file */
+ Pgno pgno, /* Page number to fetch */
+ DbPage **ppPage, /* Write a pointer to the page here */
+ int noContent /* Do not bother reading content from disk if true */
+){
PgHdr *pPg;
int rc;
+ assert( pPager->state==PAGER_UNLOCK || pPager->nRef>0 || pgno==1 );
+
/* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
** number greater than this, or zero, is requested.
*/
@@ -2632,114 +2980,28 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
}
/* If this is the first page accessed, then get a SHARED lock
- ** on the database file.
+ ** on the database file. pagerSharedLock() is a no-op if
+ ** a database lock is already held.
*/
- if( pPager->nRef==0 && !MEMDB ){
- if( !pPager->noReadlock ){
- rc = pager_wait_on_lock(pPager, SHARED_LOCK);
- if( rc!=SQLITE_OK ){
- 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.
- */
- if( hasHotJournal(pPager) ){
- /* Get an EXCLUSIVE lock on the database file. At this point it is
- ** important that a RESERVED lock is not obtained on the way to the
- ** EXCLUSIVE lock. If it were, another process might open the
- ** database file, detect the RESERVED lock, and conclude that the
- ** database is safe to read while this process is still rolling it
- ** back.
- **
- ** Because the intermediate RESERVED lock is not requested, the
- ** second process will get to this point in the code and fail to
- ** obtain it's own EXCLUSIVE lock on the database file.
- */
- rc = sqlite3OsLock(pPager->fd, EXCLUSIVE_LOCK);
- if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
- 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.
- **
- ** The journal file does not need to be locked itself. The
- ** journal file is never open unless the main database file holds
- ** a write lock, so there is never any chance of two or more
- ** processes opening the journal at the same time.
- */
- rc = sqlite3OsOpenReadOnly(pPager->zJournal, &pPager->jfd);
- if( rc!=SQLITE_OK ){
- sqlite3OsUnlock(pPager->fd, NO_LOCK);
- pPager->state = PAGER_UNLOCK;
- return SQLITE_BUSY;
- }
- pPager->journalOpen = 1;
- pPager->journalStarted = 0;
- pPager->journalOff = 0;
- pPager->setMaster = 0;
- pPager->journalHdr = 0;
-
- /* Playback and delete the journal. Drop the database write
- ** lock and reacquire the read lock.
- */
- rc = pager_playback(pPager);
- if( rc!=SQLITE_OK ){
- return pager_error(pPager, rc);
- }
- }
- pPg = 0;
- }else{
- /* Search for page in cache */
- pPg = pager_lookup(pPager, pgno);
- if( MEMDB && pPager->state==PAGER_UNLOCK ){
- pPager->state = PAGER_SHARED;
- }
+ rc = pagerSharedLock(pPager);
+ if( rc!=SQLITE_OK ){
+ return rc;
}
+ assert( pPager->state!=PAGER_UNLOCK );
+
+ pPg = pager_lookup(pPager, pgno);
if( pPg==0 ){
/* The requested page is not in the page cache. */
+ int nMax;
int h;
- TEST_INCR(pPager->nMiss);
- if( pPager->nPage<pPager->mxPage || pPager->pFirst==0 || MEMDB ){
- /* Create a new page */
- if( pPager->nPage>=pPager->nHash ){
- pager_resize_hash_table(pPager,
- pPager->nHash<256 ? 256 : pPager->nHash*2);
- if( pPager->nHash==0 ){
- return SQLITE_NOMEM;
- }
- }
- pPg = sqliteMallocRaw( sizeof(*pPg) + pPager->pageSize
- + sizeof(u32) + pPager->nExtra
- + MEMDB*sizeof(PgHistory) );
- if( pPg==0 ){
- return SQLITE_NOMEM;
- }
- memset(pPg, 0, sizeof(*pPg));
- if( MEMDB ){
- memset(PGHDR_TO_HIST(pPg, pPager), 0, sizeof(PgHistory));
- }
- pPg->pPager = pPager;
- pPg->pNextAll = pPager->pAll;
- pPager->pAll = pPg;
- pPager->nPage++;
- if( pPager->nPage>pPager->nMaxPage ){
- assert( pPager->nMaxPage==(pPager->nPage-1) );
- pPager->nMaxPage++;
- }
- }else{
- rc = pager_recycle(pPager, 1, &pPg);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- assert(pPg) ;
+ PAGER_INCR(pPager->nMiss);
+ rc = pagerAllocatePage(pPager, &pPg);
+ if( rc!=SQLITE_OK ){
+ return rc;
}
+
pPg->pgno = pgno;
+ assert( !MEMDB || pgno>pPager->stmtSize );
if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){
sqlite3CheckMemory(pPager->aInJournal, pgno/8);
assert( pPager->journalOpen );
@@ -2749,12 +3011,7 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
pPg->inJournal = 0;
pPg->needSync = 0;
}
- if( pPager->aInStmt && (int)pgno<=pPager->stmtSize
- && (pPager->aInStmt[pgno/8] & (1<<(pgno&7)))!=0 ){
- page_add_to_stmt_list(pPg);
- }else{
- page_remove_from_stmt_list(pPg);
- }
+
makeClean(pPg);
pPg->nRef = 1;
REFINFO(pPg);
@@ -2763,8 +3020,9 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
if( pPager->nExtra>0 ){
memset(PGHDR_TO_EXTRA(pPg, pPager), 0, pPager->nExtra);
}
+ nMax = sqlite3PagerPagecount(pPager);
if( pPager->errCode ){
- sqlite3pager_unref(PGHDR_TO_DATA(pPg));
+ sqlite3PagerUnref(pPg);
rc = pPager->errCode;
return rc;
}
@@ -2772,32 +3030,16 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
/* Populate the page with data, either by reading from the database
** file, or by setting the entire page to zero.
*/
- if( sqlite3pager_pagecount(pPager)<(int)pgno || MEMDB ){
+ if( nMax<(int)pgno || MEMDB || (noContent && !pPager->alwaysRollback) ){
memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
+ pPg->needRead = noContent && !pPager->alwaysRollback;
+ IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{
- assert( MEMDB==0 );
- rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsRead(pPager->fd, PGHDR_TO_DATA(pPg),
- pPager->pageSize);
- }
- TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
- CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
- if( rc!=SQLITE_OK ){
- i64 fileSize;
- int rc2 = sqlite3OsFileSize(pPager->fd, &fileSize);
- if( rc2!=SQLITE_OK || fileSize>=pgno*pPager->pageSize ){
- /* An IO error occured in one of the the sqlite3OsSeek() or
- ** sqlite3OsRead() calls above. */
- pPg->pgno = 0;
- sqlite3pager_unref(PGHDR_TO_DATA(pPg));
- return rc;
- }else{
- clear_simulated_io_error();
- memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize);
- }
- }else{
- TEST_INCR(pPager->nRead);
+ rc = readDbPage(pPager, pPg, pgno);
+ if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
+ pPg->pgno = 0;
+ sqlite3PagerUnref(pPg);
+ return rc;
}
}
@@ -2816,10 +3058,11 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
#endif
}else{
/* The requested page is in the page cache. */
- TEST_INCR(pPager->nHit);
+ assert(pPager->nRef>0 || pgno==1);
+ PAGER_INCR(pPager->nHit);
page_ref(pPg);
}
- *ppPage = PGHDR_TO_DATA(pPg);
+ *ppPage = pPg;
return SQLITE_OK;
}
@@ -2828,24 +3071,29 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
** not read the page from disk. Return a pointer to the page,
** or 0 if the page is not in cache.
**
-** See also sqlite3pager_get(). The difference between this routine
-** and sqlite3pager_get() is that _get() will go to the disk and read
+** See also sqlite3PagerGet(). The difference between this routine
+** and sqlite3PagerGet() is that _get() will go to the disk and read
** in the page if the page is not already in cache. This routine
** returns NULL if the page is not in cache or if a disk I/O error
** has ever happened.
*/
-void *sqlite3pager_lookup(Pager *pPager, Pgno pgno){
+DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
PgHdr *pPg;
assert( pPager!=0 );
assert( pgno!=0 );
+
+ if( pPager->state==PAGER_UNLOCK ){
+ assert( !pPager->pAll || pPager->exclusiveMode );
+ return 0;
+ }
if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
return 0;
}
pPg = pager_lookup(pPager, pgno);
if( pPg==0 ) return 0;
page_ref(pPg);
- return PGHDR_TO_DATA(pPg);
+ return pPg;
}
/*
@@ -2856,12 +3104,10 @@ void *sqlite3pager_lookup(Pager *pPager, Pgno pgno){
** are released, a rollback occurs and the lock on the database is
** removed.
*/
-int sqlite3pager_unref(void *pData){
- PgHdr *pPg;
+int sqlite3PagerUnref(DbPage *pPg){
/* Decrement the reference count for this page
*/
- pPg = DATA_TO_PGHDR(pData);
assert( pPg->nRef>0 );
pPg->nRef--;
REFINFO(pPg);
@@ -2886,7 +3132,7 @@ int sqlite3pager_unref(void *pData){
pPager->pFirstSynced = pPg;
}
if( pPager->xDestructor ){
- pPager->xDestructor(pData, pPager->pageSize);
+ pPager->xDestructor(pPg, pPager->pageSize);
}
/* When all pages reach the freelist, drop the read lock from
@@ -2894,8 +3140,8 @@ int sqlite3pager_unref(void *pData){
*/
pPager->nRef--;
assert( pPager->nRef>=0 );
- if( pPager->nRef==0 && !MEMDB ){
- pager_reset(pPager);
+ if( pPager->nRef==0 && (!pPager->exclusiveMode || pPager->journalOff>0) ){
+ pagerUnlockAndRollback(pPager);
}
}
return SQLITE_OK;
@@ -2915,7 +3161,7 @@ static int pager_open_journal(Pager *pPager){
assert( pPager->journalOpen==0 );
assert( pPager->useJournal );
assert( pPager->aInJournal==0 );
- sqlite3pager_pagecount(pPager);
+ sqlite3PagerPagecount(pPager);
pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
if( pPager->aInJournal==0 ){
rc = SQLITE_NOMEM;
@@ -2923,10 +3169,14 @@ static int pager_open_journal(Pager *pPager){
}
rc = sqlite3OsOpenExclusive(pPager->zJournal, &pPager->jfd,
pPager->tempFile);
+ assert( rc!=SQLITE_OK || pPager->jfd );
pPager->journalOff = 0;
pPager->setMaster = 0;
pPager->journalHdr = 0;
if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_NOMEM ){
+ sqlite3OsDelete(pPager->zJournal);
+ }
goto failed_to_open_journal;
}
sqlite3OsSetFullSync(pPager->jfd, pPager->full_fsync);
@@ -2946,10 +3196,10 @@ static int pager_open_journal(Pager *pPager){
rc = writeJournalHdr(pPager);
if( pPager->stmtAutoopen && rc==SQLITE_OK ){
- rc = sqlite3pager_stmt_begin(pPager);
+ rc = sqlite3PagerStmtBegin(pPager);
}
if( rc!=SQLITE_OK && rc!=SQLITE_NOMEM ){
- rc = pager_unwritelock(pPager);
+ rc = pager_end_transaction(pPager);
if( rc==SQLITE_OK ){
rc = SQLITE_FULL;
}
@@ -2959,17 +3209,6 @@ static int pager_open_journal(Pager *pPager){
failed_to_open_journal:
sqliteFree(pPager->aInJournal);
pPager->aInJournal = 0;
- 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;
}
@@ -2977,10 +3216,10 @@ failed_to_open_journal:
** Acquire a write-lock on the database. The lock is removed when
** the any of the following happen:
**
-** * sqlite3pager_commit() is called.
-** * sqlite3pager_rollback() is called.
-** * sqlite3pager_close() is called.
-** * sqlite3pager_unref() is called to on every outstanding page.
+** * sqlite3PagerCommitPhaseTwo() is called.
+** * sqlite3PagerRollback() is called.
+** * sqlite3PagerClose() is called.
+** * sqlite3PagerUnref() is called to on every outstanding page.
**
** The first parameter to this routine is a pointer to any open page of the
** database file. Nothing changes about the page - it is used merely to
@@ -3000,8 +3239,7 @@ failed_to_open_journal:
** immediately instead of waiting until we try to flush the cache. The
** exFlag is ignored if a transaction is already active.
*/
-int sqlite3pager_begin(void *pData, int exFlag){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
+int sqlite3PagerBegin(DbPage *pPg, int exFlag){
Pager *pPager = pPg->pPager;
int rc = SQLITE_OK;
assert( pPg->nRef>0 );
@@ -3023,12 +3261,30 @@ int sqlite3pager_begin(void *pData, int exFlag){
return rc;
}
pPager->dirtyCache = 0;
- TRACE2("TRANSACTION %d\n", PAGERID(pPager));
+ PAGERTRACE2("TRANSACTION %d\n", PAGERID(pPager));
if( pPager->useJournal && !pPager->tempFile ){
rc = pager_open_journal(pPager);
}
}
+ }else if( pPager->journalOpen && pPager->journalOff==0 ){
+ /* This happens when the pager was in exclusive-access mode last
+ ** time a (read or write) transaction was successfully concluded
+ ** by this connection. Instead of deleting the journal file it was
+ ** kept open and truncated to 0 bytes.
+ */
+ assert( pPager->nRec==0 );
+ assert( pPager->origDbSize==0 );
+ assert( pPager->aInJournal==0 );
+ sqlite3PagerPagecount(pPager);
+ pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
+ if( !pPager->aInJournal ){
+ rc = SQLITE_NOMEM;
+ }else{
+ pPager->origDbSize = pPager->dbSize;
+ rc = writeJournalHdr(pPager);
+ }
}
+ assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK );
return rc;
}
@@ -3082,11 +3338,11 @@ static void makeClean(PgHdr *pPg){
** If the journal file could not be written because the disk is full,
** then this routine returns SQLITE_FULL and does an immediate rollback.
** All subsequent write attempts also return SQLITE_FULL until there
-** is a call to sqlite3pager_commit() or sqlite3pager_rollback() to
+** is a call to sqlite3PagerCommit() or sqlite3PagerRollback() to
** reset.
*/
-int sqlite3pager_write(void *pData){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
+static int pager_write(PgHdr *pPg){
+ void *pData = PGHDR_TO_DATA(pPg);
Pager *pPager = pPg->pPager;
int rc = SQLITE_OK;
@@ -3103,11 +3359,28 @@ int sqlite3pager_write(void *pData){
CHECK_PAGE(pPg);
+ /* If this page was previously acquired with noContent==1, that means
+ ** we didn't really read in the content of the page. This can happen
+ ** (for example) when the page is being moved to the freelist. But
+ ** now we are (perhaps) moving the page off of the freelist for
+ ** reuse and we need to know its original content so that content
+ ** can be stored in the rollback journal. So do the read at this
+ ** time.
+ */
+ if( pPg->needRead ){
+ rc = readDbPage(pPager, pPg, pPg->pgno);
+ if( rc==SQLITE_OK ){
+ pPg->needRead = 0;
+ }else{
+ return rc;
+ }
+ }
+
/* Mark the page as dirty. If the page has already been written
** to the journal then we can return right away.
*/
makeDirty(pPg);
- if( pPg->inJournal && (pPg->inStmt || pPager->stmtInUse==0) ){
+ if( pPg->inJournal && (pageInStatement(pPg) || pPager->stmtInUse==0) ){
pPager->dirtyCache = 1;
}else{
@@ -3119,7 +3392,7 @@ int sqlite3pager_write(void *pData){
** create it if it does not.
*/
assert( pPager->state!=PAGER_UNLOCK );
- rc = sqlite3pager_begin(pData, 0);
+ rc = sqlite3PagerBegin(pPg, 0);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -3140,7 +3413,7 @@ int sqlite3pager_write(void *pData){
int szPg;
if( MEMDB ){
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
- TRACE3("JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
+ PAGERTRACE3("JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
assert( pHist->pOrig==0 );
pHist->pOrig = sqliteMallocRaw( pPager->pageSize );
if( pHist->pOrig ){
@@ -3162,8 +3435,11 @@ int sqlite3pager_write(void *pData){
szPg = pPager->pageSize+8;
put32bits(pData2, pPg->pgno);
rc = sqlite3OsWrite(pPager->jfd, pData2, szPg);
+ IOTRACE(("JOUT %p %d %lld %d\n", pPager, pPg->pgno,
+ pPager->journalOff, szPg));
+ PAGER_INCR(sqlite3_pager_writej_count);
pPager->journalOff += szPg;
- TRACE4("JOURNAL %d page %d needSync=%d\n",
+ PAGERTRACE4("JOURNAL %d page %d needSync=%d\n",
PAGERID(pPager), pPg->pgno, pPg->needSync);
*(u32*)pEnd = saved;
@@ -3180,12 +3456,11 @@ int sqlite3pager_write(void *pData){
pPg->needSync = !pPager->noSync;
if( pPager->stmtInUse ){
pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- page_add_to_stmt_list(pPg);
}
}
}else{
pPg->needSync = !pPager->journalStarted && !pPager->noSync;
- TRACE4("APPEND %d page %d needSync=%d\n",
+ PAGERTRACE4("APPEND %d page %d needSync=%d\n",
PAGERID(pPager), pPg->pgno, pPg->needSync);
}
if( pPg->needSync ){
@@ -3199,7 +3474,10 @@ int sqlite3pager_write(void *pData){
** the statement journal format differs from the standard journal format
** in that it omits the checksums and the header.
*/
- if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
+ if( pPager->stmtInUse
+ && !pageInStatement(pPg)
+ && (int)pPg->pgno<=pPager->stmtSize
+ ){
assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
if( MEMDB ){
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
@@ -3208,12 +3486,13 @@ int sqlite3pager_write(void *pData){
if( pHist->pStmt ){
memcpy(pHist->pStmt, PGHDR_TO_DATA(pPg), pPager->pageSize);
}
- TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
+ PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
+ page_add_to_stmt_list(pPg);
}else{
char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7)-4;
put32bits(pData2, pPg->pgno);
rc = sqlite3OsWrite(pPager->stfd, pData2, pPager->pageSize+4);
- TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
+ PAGERTRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
if( rc!=SQLITE_OK ){
return rc;
}
@@ -3221,12 +3500,12 @@ int sqlite3pager_write(void *pData){
assert( pPager->aInStmt!=0 );
pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
}
- page_add_to_stmt_list(pPg);
}
}
/* Update the database size and return.
*/
+ assert( pPager->state>=PAGER_SHARED );
if( pPager->dbSize<(int)pPg->pgno ){
pPager->dbSize = pPg->pgno;
if( !MEMDB && pPager->dbSize==PENDING_BYTE/pPager->pageSize ){
@@ -3237,13 +3516,83 @@ int sqlite3pager_write(void *pData){
}
/*
+** This function is used to mark a data-page as writable. It uses
+** pager_write() to open a journal file (if it is not already open)
+** and write the page *pData to the journal.
+**
+** The difference between this function and pager_write() is that this
+** function also deals with the special case where 2 or more pages
+** fit on a single disk sector. In this case all co-resident pages
+** must have been written to the journal file before returning.
+*/
+int sqlite3PagerWrite(DbPage *pDbPage){
+ int rc = SQLITE_OK;
+
+ PgHdr *pPg = pDbPage;
+ Pager *pPager = pPg->pPager;
+ Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
+
+ if( !MEMDB && nPagePerSector>1 ){
+ Pgno nPageCount; /* Total number of pages in database file */
+ Pgno pg1; /* First page of the sector pPg is located on. */
+ int nPage; /* Number of pages starting at pg1 to journal */
+ int ii;
+
+ /* Set the doNotSync flag to 1. This is because we cannot allow a journal
+ ** header to be written between the pages journaled by this function.
+ */
+ assert( pPager->doNotSync==0 );
+ pPager->doNotSync = 1;
+
+ /* This trick assumes that both the page-size and sector-size are
+ ** an integer power of 2. It sets variable pg1 to the identifier
+ ** of the first page of the sector pPg is located on.
+ */
+ pg1 = ((pPg->pgno-1) & ~(nPagePerSector-1)) + 1;
+
+ nPageCount = sqlite3PagerPagecount(pPager);
+ if( pPg->pgno>nPageCount ){
+ nPage = (pPg->pgno - pg1)+1;
+ }else if( (pg1+nPagePerSector-1)>nPageCount ){
+ nPage = nPageCount+1-pg1;
+ }else{
+ nPage = nPagePerSector;
+ }
+ assert(nPage>0);
+ assert(pg1<=pPg->pgno);
+ assert((pg1+nPage)>pPg->pgno);
+
+ for(ii=0; ii<nPage && rc==SQLITE_OK; ii++){
+ Pgno pg = pg1+ii;
+ if( !pPager->aInJournal || pg==pPg->pgno ||
+ pg>pPager->origDbSize || !(pPager->aInJournal[pg/8]&(1<<(pg&7)))
+ ) {
+ if( pg!=PAGER_MJ_PGNO(pPager) ){
+ PgHdr *pPage;
+ rc = sqlite3PagerGet(pPager, pg, &pPage);
+ if( rc==SQLITE_OK ){
+ rc = pager_write(pPage);
+ sqlite3PagerUnref(pPage);
+ }
+ }
+ }
+ }
+
+ assert( pPager->doNotSync==1 );
+ pPager->doNotSync = 0;
+ }else{
+ rc = pager_write(pDbPage);
+ }
+ return rc;
+}
+
+/*
** Return TRUE if the page given in the argument was previously passed
-** to sqlite3pager_write(). In other words, return TRUE if it is ok
+** to sqlite3PagerWrite(). In other words, return TRUE if it is ok
** to change the content of the page.
*/
#ifndef NDEBUG
-int sqlite3pager_iswriteable(void *pData){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
+int sqlite3PagerIswriteable(DbPage *pPg){
return pPg->dirty;
}
#endif
@@ -3253,17 +3602,17 @@ int sqlite3pager_iswriteable(void *pData){
** Replace the content of a single page with the information in the third
** argument.
*/
-int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void *pData){
- void *pPage;
+int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void *pData){
+ PgHdr *pPg;
int rc;
- rc = sqlite3pager_get(pPager, pgno, &pPage);
+ rc = sqlite3PagerGet(pPager, pgno, &pPg);
if( rc==SQLITE_OK ){
- rc = sqlite3pager_write(pPage);
+ rc = sqlite3PagerWrite(pPg);
if( rc==SQLITE_OK ){
- memcpy(pPage, pData, pPager->pageSize);
+ memcpy(sqlite3PagerGetData(pPg), pData, pPager->pageSize);
}
- sqlite3pager_unref(pPage);
+ sqlite3PagerUnref(pPg);
}
return rc;
}
@@ -3271,7 +3620,7 @@ int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void *pData){
/*
** A call to this routine tells the pager that it is not necessary to
-** write the information on page "pgno" back to the disk, even though
+** write the information on page pPg back to the disk, even though
** that page might be marked as dirty.
**
** The overlying software layer calls this routine when all of the data
@@ -3279,29 +3628,28 @@ int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void *pData){
** that it does not get written to disk.
**
** Tests show that this optimization, together with the
-** sqlite3pager_dont_rollback() below, more than double the speed
+** sqlite3PagerDontRollback() below, more than double the speed
** of large INSERT operations and quadruple the speed of large DELETEs.
**
** When this routine is called, set the alwaysRollback flag to true.
-** Subsequent calls to sqlite3pager_dont_rollback() for the same page
+** Subsequent calls to sqlite3PagerDontRollback() for the same page
** will thereafter be ignored. This is necessary to avoid a problem
** where a page with data is added to the freelist during one part of
** a transaction then removed from the freelist during a later part
** of the same transaction and reused for some other purpose. When it
** is first added to the freelist, this routine is called. When reused,
-** the dont_rollback() routine is called. But because the page contains
-** critical data, we still need to be sure it gets rolled back in spite
-** of the dont_rollback() call.
+** the sqlite3PagerDontRollback() routine is called. But because the
+** page contains critical data, we still need to be sure it gets
+** rolled back in spite of the sqlite3PagerDontRollback() call.
*/
-void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
- PgHdr *pPg;
+void sqlite3PagerDontWrite(DbPage *pDbPage){
+ PgHdr *pPg = pDbPage;
+ Pager *pPager = pPg->pPager;
if( MEMDB ) return;
-
- pPg = pager_lookup(pPager, pgno);
- assert( pPg!=0 ); /* We never call _dont_write unless the page is in mem */
pPg->alwaysRollback = 1;
if( pPg->dirty && !pPager->stmtInUse ){
+ assert( pPager->state>=PAGER_SHARED );
if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){
/* If this pages is the last page in the file and the file has grown
** during the current transaction, then do NOT mark the page as clean.
@@ -3312,7 +3660,8 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
** corruption during the next transaction.
*/
}else{
- TRACE3("DONT_WRITE page %d of %d\n", pgno, PAGERID(pPager));
+ PAGERTRACE3("DONT_WRITE page %d of %d\n", pPg->pgno, PAGERID(pPager));
+ IOTRACE(("CLEAN %p %d\n", pPager, pPg->pgno))
makeClean(pPg);
#ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg);
@@ -3326,40 +3675,171 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
** it is not necessary to restore the data on the given page. This
** means that the pager does not have to record the given page in the
** rollback journal.
+**
+** If we have not yet actually read the content of this page (if
+** the PgHdr.needRead flag is set) then this routine acts as a promise
+** that we will never need to read the page content in the future.
+** so the needRead flag can be cleared at this point.
*/
-void sqlite3pager_dont_rollback(void *pData){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
+void sqlite3PagerDontRollback(DbPage *pPg){
Pager *pPager = pPg->pPager;
- if( pPager->state!=PAGER_EXCLUSIVE || pPager->journalOpen==0 ) return;
+ assert( pPager->state>=PAGER_RESERVED );
+ if( pPager->journalOpen==0 ) return;
if( pPg->alwaysRollback || pPager->alwaysRollback || MEMDB ) return;
if( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ){
assert( pPager->aInJournal!=0 );
pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
pPg->inJournal = 1;
+ pPg->needRead = 0;
if( pPager->stmtInUse ){
pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- page_add_to_stmt_list(pPg);
}
- TRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, PAGERID(pPager));
+ PAGERTRACE3("DONT_ROLLBACK page %d of %d\n", pPg->pgno, PAGERID(pPager));
+ IOTRACE(("GARBAGE %p %d\n", pPager, pPg->pgno))
}
- if( pPager->stmtInUse && !pPg->inStmt && (int)pPg->pgno<=pPager->stmtSize ){
+ if( pPager->stmtInUse
+ && !pageInStatement(pPg)
+ && (int)pPg->pgno<=pPager->stmtSize
+ ){
assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
assert( pPager->aInStmt!=0 );
pPager->aInStmt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
- page_add_to_stmt_list(pPg);
}
}
/*
+** This routine is called to increment the database file change-counter,
+** stored at byte 24 of the pager file.
+*/
+static int pager_incr_changecounter(Pager *pPager){
+ PgHdr *pPgHdr;
+ u32 change_counter;
+ int rc;
+
+ if( !pPager->changeCountDone ){
+ /* Open page 1 of the file for writing. */
+ rc = sqlite3PagerGet(pPager, 1, &pPgHdr);
+ if( rc!=SQLITE_OK ) return rc;
+ rc = sqlite3PagerWrite(pPgHdr);
+ if( rc!=SQLITE_OK ) return rc;
+
+ /* Read the current value at byte 24. */
+ change_counter = retrieve32bits(pPgHdr, 24);
+
+ /* Increment the value just read and write it back to byte 24. */
+ change_counter++;
+ put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
+
+ /* Release the page reference. */
+ sqlite3PagerUnref(pPgHdr);
+ pPager->changeCountDone = 1;
+ }
+ return SQLITE_OK;
+}
+
+/*
+** Sync the database file for the pager pPager. zMaster points to the name
+** of a master journal file that should be written into the individual
+** journal file. zMaster may be NULL, which is interpreted as no master
+** journal (a single database transaction).
+**
+** This routine ensures that the journal is synced, all dirty pages written
+** to the database file and the database file synced. The only thing that
+** remains to commit the transaction is to delete the journal file (or
+** master journal file if specified).
+**
+** Note that if zMaster==NULL, this does not overwrite a previous value
+** passed to an sqlite3PagerCommitPhaseOne() call.
+**
+** If parameter nTrunc is non-zero, then the pager file is truncated to
+** nTrunc pages (this is used by auto-vacuum databases).
+*/
+int sqlite3PagerCommitPhaseOne(Pager *pPager, const char *zMaster, Pgno nTrunc){
+ int rc = SQLITE_OK;
+
+ PAGERTRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%d\n",
+ pPager->zFilename, zMaster, nTrunc);
+
+ /* If this is an in-memory db, or no pages have been written to, or this
+ ** function has already been called, it is a no-op.
+ */
+ if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){
+ PgHdr *pPg;
+ assert( pPager->journalOpen );
+
+ /* If a master journal file name has already been written to the
+ ** journal file, then no sync is required. This happens when it is
+ ** written, then the process fails to upgrade from a RESERVED to an
+ ** EXCLUSIVE lock. The next time the process tries to commit the
+ ** transaction the m-j name will have already been written.
+ */
+ if( !pPager->setMaster ){
+ rc = pager_incr_changecounter(pPager);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( nTrunc!=0 ){
+ /* If this transaction has made the database smaller, then all pages
+ ** being discarded by the truncation must be written to the journal
+ ** file.
+ */
+ Pgno i;
+ int iSkip = PAGER_MJ_PGNO(pPager);
+ for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
+ if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){
+ rc = sqlite3PagerGet(pPager, i, &pPg);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+ rc = sqlite3PagerWrite(pPg);
+ sqlite3PagerUnref(pPg);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+ }
+ }
+ }
+#endif
+ rc = writeMasterJournal(pPager, zMaster);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+ rc = syncJournal(pPager);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+ }
+
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( nTrunc!=0 ){
+ rc = sqlite3PagerTruncate(pPager, nTrunc);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+ }
+#endif
+
+ /* Write all dirty pages to the database file */
+ pPg = pager_get_all_dirty_pages(pPager);
+ rc = pager_write_pagelist(pPg);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+ pPager->pDirty = 0;
+
+ /* Sync the database file. */
+ if( !pPager->noSync ){
+ rc = sqlite3OsSync(pPager->fd, 0);
+ }
+ IOTRACE(("DBSYNC %p\n", pPager))
+
+ pPager->state = PAGER_SYNCED;
+ }else if( MEMDB && nTrunc!=0 ){
+ rc = sqlite3PagerTruncate(pPager, nTrunc);
+ }
+
+sync_exit:
+ return rc;
+}
+
+
+/*
** Commit all changes to the database and release the write lock.
**
** If the commit fails for any reason, a rollback attempt is made
** and an error code is returned. If the commit worked, SQLITE_OK
** is returned.
*/
-int sqlite3pager_commit(Pager *pPager){
+int sqlite3PagerCommitPhaseTwo(Pager *pPager){
int rc;
PgHdr *pPg;
@@ -3369,16 +3849,17 @@ int sqlite3pager_commit(Pager *pPager){
if( pPager->state<PAGER_RESERVED ){
return SQLITE_ERROR;
}
- TRACE2("COMMIT %d\n", PAGERID(pPager));
+ PAGERTRACE2("COMMIT %d\n", PAGERID(pPager));
if( MEMDB ){
pPg = pager_get_all_dirty_pages(pPager);
while( pPg ){
- clearHistory(PGHDR_TO_HIST(pPg, pPager));
+ PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
+ clearHistory(pHist);
pPg->dirty = 0;
pPg->inJournal = 0;
- pPg->inStmt = 0;
+ pHist->inStmt = 0;
pPg->needSync = 0;
- pPg->pPrevStmt = pPg->pNextStmt = 0;
+ pHist->pPrevStmt = pHist->pNextStmt = 0;
pPg = pPg->pDirty;
}
pPager->pDirty = 0;
@@ -3394,21 +3875,10 @@ int sqlite3pager_commit(Pager *pPager){
pPager->state = PAGER_SHARED;
return SQLITE_OK;
}
- if( pPager->dirtyCache==0 ){
- /* Exit early (without doing the time-consuming sqlite3OsSync() calls)
- ** if there have been no changes to the database file. */
- assert( pPager->needSync==0 );
- rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
- return rc;
- }
- assert( pPager->journalOpen );
- rc = sqlite3pager_sync(pPager, 0, 0);
- if( rc==SQLITE_OK ){
- rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
- }
- return rc;
+ assert( pPager->journalOpen || !pPager->dirtyCache );
+ assert( pPager->state==PAGER_SYNCED || !pPager->dirtyCache );
+ rc = pager_end_transaction(pPager);
+ return pager_error(pPager, rc);
}
/*
@@ -3417,15 +3887,15 @@ int sqlite3pager_commit(Pager *pPager){
** The journal is deleted.
**
** This routine cannot fail unless some other process is not following
-** the correct locking protocol (SQLITE_PROTOCOL) or unless some other
+** the correct locking protocol or unless some other
** process is writing trash into the journal file (SQLITE_CORRUPT) or
** unless a prior malloc() failed (SQLITE_NOMEM). Appropriate error
** codes are returned for all these occasions. Otherwise,
** SQLITE_OK is returned.
*/
-int sqlite3pager_rollback(Pager *pPager){
+int sqlite3PagerRollback(Pager *pPager){
int rc;
- TRACE2("ROLLBACK %d\n", PAGERID(pPager));
+ PAGERTRACE2("ROLLBACK %d\n", PAGERID(pPager));
if( MEMDB ){
PgHdr *p;
for(p=pPager->pAll; p; p=p->pNextAll){
@@ -3440,50 +3910,50 @@ int sqlite3pager_rollback(Pager *pPager){
pHist = PGHDR_TO_HIST(p, pPager);
if( pHist->pOrig ){
memcpy(PGHDR_TO_DATA(p), pHist->pOrig, pPager->pageSize);
- TRACE3("ROLLBACK-PAGE %d of %d\n", p->pgno, PAGERID(pPager));
+ PAGERTRACE3("ROLLBACK-PAGE %d of %d\n", p->pgno, PAGERID(pPager));
}else{
- TRACE3("PAGE %d is clean on %d\n", p->pgno, PAGERID(pPager));
+ PAGERTRACE3("PAGE %d is clean on %d\n", p->pgno, PAGERID(pPager));
}
clearHistory(pHist);
p->dirty = 0;
p->inJournal = 0;
- p->inStmt = 0;
- p->pPrevStmt = p->pNextStmt = 0;
+ pHist->inStmt = 0;
+ pHist->pPrevStmt = pHist->pNextStmt = 0;
if( pPager->xReiniter ){
- pPager->xReiniter(PGHDR_TO_DATA(p), pPager->pageSize);
+ pPager->xReiniter(p, pPager->pageSize);
}
}
pPager->pDirty = 0;
pPager->pStmt = 0;
pPager->dbSize = pPager->origDbSize;
- memoryTruncate(pPager);
+ pager_truncate_cache(pPager);
pPager->stmtInUse = 0;
pPager->state = PAGER_SHARED;
return SQLITE_OK;
}
if( !pPager->dirtyCache || !pPager->journalOpen ){
- rc = pager_unwritelock(pPager);
- pPager->dbSize = -1;
+ rc = pager_end_transaction(pPager);
return rc;
}
if( pPager->errCode && pPager->errCode!=SQLITE_FULL ){
if( pPager->state>=PAGER_EXCLUSIVE ){
- pager_playback(pPager);
+ pager_playback(pPager, 0);
}
return pPager->errCode;
}
if( pPager->state==PAGER_RESERVED ){
int rc2;
- rc = pager_reload_cache(pPager);
- rc2 = pager_unwritelock(pPager);
+ rc = pager_playback(pPager, 0);
+ rc2 = pager_end_transaction(pPager);
if( rc==SQLITE_OK ){
rc = rc2;
}
}else{
- rc = pager_playback(pPager);
+ rc = pager_playback(pPager, 0);
}
+ /* pager_reset(pPager); */
pPager->dbSize = -1;
/* If an error occurs during a ROLLBACK, we can no longer trust the pager
@@ -3497,14 +3967,14 @@ int sqlite3pager_rollback(Pager *pPager){
** Return TRUE if the database file is opened read-only. Return FALSE
** if the database is (in theory) writable.
*/
-int sqlite3pager_isreadonly(Pager *pPager){
+int sqlite3PagerIsreadonly(Pager *pPager){
return pPager->readOnly;
}
/*
** Return the number of references to the pager.
*/
-int sqlite3pager_refcount(Pager *pPager){
+int sqlite3PagerRefcount(Pager *pPager){
return pPager->nRef;
}
@@ -3512,7 +3982,7 @@ int sqlite3pager_refcount(Pager *pPager){
/*
** This routine is used for testing and analysis only.
*/
-int *sqlite3pager_stats(Pager *pPager){
+int *sqlite3PagerStats(Pager *pPager){
static int a[11];
a[0] = pPager->nRef;
a[1] = pPager->nPage;
@@ -3522,7 +3992,7 @@ int *sqlite3pager_stats(Pager *pPager){
a[5] = pPager->errCode;
a[6] = pPager->nHit;
a[7] = pPager->nMiss;
- a[8] = pPager->nOvfl;
+ a[8] = 0; /* Used to be pPager->nOvfl */
a[9] = pPager->nRead;
a[10] = pPager->nWrite;
return a;
@@ -3536,12 +4006,12 @@ int *sqlite3pager_stats(Pager *pPager){
** open. A new statement journal is created that can be used to rollback
** changes of a single SQL command within a larger transaction.
*/
-int sqlite3pager_stmt_begin(Pager *pPager){
+int sqlite3PagerStmtBegin(Pager *pPager){
int rc;
- char zTemp[SQLITE_TEMPNAME_SIZE];
assert( !pPager->stmtInUse );
+ assert( pPager->state>=PAGER_SHARED );
assert( pPager->dbSize>=0 );
- TRACE2("STMT-BEGIN %d\n", PAGERID(pPager));
+ PAGERTRACE2("STMT-BEGIN %d\n", PAGERID(pPager));
if( MEMDB ){
pPager->stmtInUse = 1;
pPager->stmtSize = pPager->dbSize;
@@ -3567,7 +4037,7 @@ int sqlite3pager_stmt_begin(Pager *pPager){
pPager->stmtHdrOff = 0;
pPager->stmtCksum = pPager->cksumInit;
if( !pPager->stmtOpen ){
- rc = sqlite3pager_opentemp(zTemp, &pPager->stfd);
+ rc = sqlite3PagerOpentemp(&pPager->stfd);
if( rc ) goto stmt_begin_failed;
pPager->stmtOpen = 1;
pPager->stmtNRec = 0;
@@ -3586,23 +4056,22 @@ stmt_begin_failed:
/*
** Commit a statement.
*/
-int sqlite3pager_stmt_commit(Pager *pPager){
+int sqlite3PagerStmtCommit(Pager *pPager){
if( pPager->stmtInUse ){
PgHdr *pPg, *pNext;
- TRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
+ PAGERTRACE2("STMT-COMMIT %d\n", PAGERID(pPager));
if( !MEMDB ){
sqlite3OsSeek(pPager->stfd, 0);
/* sqlite3OsTruncate(pPager->stfd, 0); */
sqliteFree( pPager->aInStmt );
pPager->aInStmt = 0;
- }
- for(pPg=pPager->pStmt; pPg; pPg=pNext){
- pNext = pPg->pNextStmt;
- assert( pPg->inStmt );
- pPg->inStmt = 0;
- pPg->pPrevStmt = pPg->pNextStmt = 0;
- if( MEMDB ){
+ }else{
+ for(pPg=pPager->pStmt; pPg; pPg=pNext){
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
+ pNext = pHist->pNextStmt;
+ assert( pHist->inStmt );
+ pHist->inStmt = 0;
+ pHist->pPrevStmt = pHist->pNextStmt = 0;
sqliteFree(pHist->pStmt);
pHist->pStmt = 0;
}
@@ -3618,14 +4087,15 @@ int sqlite3pager_stmt_commit(Pager *pPager){
/*
** Rollback a statement.
*/
-int sqlite3pager_stmt_rollback(Pager *pPager){
+int sqlite3PagerStmtRollback(Pager *pPager){
int rc;
if( pPager->stmtInUse ){
- TRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager));
+ PAGERTRACE2("STMT-ROLLBACK %d\n", PAGERID(pPager));
if( MEMDB ){
PgHdr *pPg;
- for(pPg=pPager->pStmt; pPg; pPg=pPg->pNextStmt){
- PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
+ PgHistory *pHist;
+ for(pPg=pPager->pStmt; pPg; pPg=pHist->pNextStmt){
+ pHist = PGHDR_TO_HIST(pPg, pPager);
if( pHist->pStmt ){
memcpy(PGHDR_TO_DATA(pPg), pHist->pStmt, pPager->pageSize);
sqliteFree(pHist->pStmt);
@@ -3633,12 +4103,12 @@ int sqlite3pager_stmt_rollback(Pager *pPager){
}
}
pPager->dbSize = pPager->stmtSize;
- memoryTruncate(pPager);
+ pager_truncate_cache(pPager);
rc = SQLITE_OK;
}else{
rc = pager_stmt_playback(pPager);
}
- sqlite3pager_stmt_commit(pPager);
+ sqlite3PagerStmtCommit(pPager);
}else{
rc = SQLITE_OK;
}
@@ -3649,21 +4119,21 @@ int sqlite3pager_stmt_rollback(Pager *pPager){
/*
** Return the full pathname of the database file.
*/
-const char *sqlite3pager_filename(Pager *pPager){
+const char *sqlite3PagerFilename(Pager *pPager){
return pPager->zFilename;
}
/*
** Return the directory of the database file.
*/
-const char *sqlite3pager_dirname(Pager *pPager){
+const char *sqlite3PagerDirname(Pager *pPager){
return pPager->zDirectory;
}
/*
** Return the full pathname of the journal file.
*/
-const char *sqlite3pager_journalname(Pager *pPager){
+const char *sqlite3PagerJournalname(Pager *pPager){
return pPager->zJournal;
}
@@ -3671,14 +4141,15 @@ const char *sqlite3pager_journalname(Pager *pPager){
** Return true if fsync() calls are disabled for this pager. Return FALSE
** if fsync()s are executed normally.
*/
-int sqlite3pager_nosync(Pager *pPager){
+int sqlite3PagerNosync(Pager *pPager){
return pPager->noSync;
}
+#ifdef SQLITE_HAS_CODEC
/*
** Set the codec for this pager
*/
-void sqlite3pager_set_codec(
+void sqlite3PagerSetCodec(
Pager *pPager,
void *(*xCodec)(void*,void*,Pgno,int),
void *pCodecArg
@@ -3686,127 +4157,8 @@ void sqlite3pager_set_codec(
pPager->xCodec = xCodec;
pPager->pCodecArg = pCodecArg;
}
-
-/*
-** This routine is called to increment the database file change-counter,
-** stored at byte 24 of the pager file.
-*/
-static int pager_incr_changecounter(Pager *pPager){
- void *pPage;
- PgHdr *pPgHdr;
- u32 change_counter;
- int rc;
-
- /* Open page 1 of the file for writing. */
- rc = sqlite3pager_get(pPager, 1, &pPage);
- if( rc!=SQLITE_OK ) return rc;
- rc = sqlite3pager_write(pPage);
- if( rc!=SQLITE_OK ) return rc;
-
- /* Read the current value at byte 24. */
- pPgHdr = DATA_TO_PGHDR(pPage);
- change_counter = retrieve32bits(pPgHdr, 24);
-
- /* Increment the value just read and write it back to byte 24. */
- change_counter++;
- put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
-
- /* Release the page reference. */
- sqlite3pager_unref(pPage);
- return SQLITE_OK;
-}
-
-/*
-** Sync the database file for the pager pPager. zMaster points to the name
-** of a master journal file that should be written into the individual
-** journal file. zMaster may be NULL, which is interpreted as no master
-** journal (a single database transaction).
-**
-** This routine ensures that the journal is synced, all dirty pages written
-** to the database file and the database file synced. The only thing that
-** remains to commit the transaction is to delete the journal file (or
-** master journal file if specified).
-**
-** Note that if zMaster==NULL, this does not overwrite a previous value
-** passed to an sqlite3pager_sync() call.
-**
-** If parameter nTrunc is non-zero, then the pager file is truncated to
-** nTrunc pages (this is used by auto-vacuum databases).
-*/
-int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
- int rc = SQLITE_OK;
-
- TRACE4("DATABASE SYNC: File=%s zMaster=%s nTrunc=%d\n",
- pPager->zFilename, zMaster, nTrunc);
-
- /* If this is an in-memory db, or no pages have been written to, or this
- ** function has already been called, it is a no-op.
- */
- if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){
- PgHdr *pPg;
- assert( pPager->journalOpen );
-
- /* If a master journal file name has already been written to the
- ** journal file, then no sync is required. This happens when it is
- ** written, then the process fails to upgrade from a RESERVED to an
- ** EXCLUSIVE lock. The next time the process tries to commit the
- ** transaction the m-j name will have already been written.
- */
- if( !pPager->setMaster ){
- rc = pager_incr_changecounter(pPager);
- if( rc!=SQLITE_OK ) goto sync_exit;
-#ifndef SQLITE_OMIT_AUTOVACUUM
- if( nTrunc!=0 ){
- /* If this transaction has made the database smaller, then all pages
- ** being discarded by the truncation must be written to the journal
- ** file.
- */
- Pgno i;
- void *pPage;
- int iSkip = PAGER_MJ_PGNO(pPager);
- for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
- if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){
- rc = sqlite3pager_get(pPager, i, &pPage);
- if( rc!=SQLITE_OK ) goto sync_exit;
- rc = sqlite3pager_write(pPage);
- sqlite3pager_unref(pPage);
- if( rc!=SQLITE_OK ) goto sync_exit;
- }
- }
- }
-#endif
- rc = writeMasterJournal(pPager, zMaster);
- if( rc!=SQLITE_OK ) goto sync_exit;
- rc = syncJournal(pPager);
- if( rc!=SQLITE_OK ) goto sync_exit;
- }
-
-#ifndef SQLITE_OMIT_AUTOVACUUM
- if( nTrunc!=0 ){
- rc = sqlite3pager_truncate(pPager, nTrunc);
- if( rc!=SQLITE_OK ) goto sync_exit;
- }
#endif
- /* Write all dirty pages to the database file */
- pPg = pager_get_all_dirty_pages(pPager);
- rc = pager_write_pagelist(pPg);
- if( rc!=SQLITE_OK ) goto sync_exit;
-
- /* Sync the database file. */
- if( !pPager->noSync ){
- rc = sqlite3OsSync(pPager->fd, 0);
- }
-
- pPager->state = PAGER_SYNCED;
- }else if( MEMDB && nTrunc!=0 ){
- rc = sqlite3pager_truncate(pPager, nTrunc);
- }
-
-sync_exit:
- return rc;
-}
-
#ifndef SQLITE_OMIT_AUTOVACUUM
/*
** Move the page identified by pData to location pgno in the file.
@@ -3825,16 +4177,16 @@ sync_exit:
** has been removed (CREATE INDEX needs to move a page when a statement
** transaction is active).
*/
-int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
- PgHdr *pPg = DATA_TO_PGHDR(pData);
+int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){
PgHdr *pPgOld;
int h;
Pgno needSyncPgno = 0;
assert( pPg->nRef>0 );
- TRACE5("MOVE %d page %d (needSync=%d) moves to %d\n",
+ PAGERTRACE5("MOVE %d page %d (needSync=%d) moves to %d\n",
PAGERID(pPager), pPg->pgno, pPg->needSync, pgno);
+ IOTRACE(("MOVE %p %d %d\n", pPager, pPg->pgno, pgno))
if( pPg->needSync ){
needSyncPgno = pPg->pgno;
@@ -3886,32 +4238,70 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
** Pager.aInJournal bit has been set. This needs to be remedied by loading
** the page into the pager-cache and setting the PgHdr.needSync flag.
**
- ** The sqlite3pager_get() call may cause the journal to sync. So make
+ ** The sqlite3PagerGet() call may cause the journal to sync. So make
** sure the Pager.needSync flag is set too.
*/
int rc;
- void *pNeedSync;
+ PgHdr *pPgHdr;
assert( pPager->needSync );
- rc = sqlite3pager_get(pPager, needSyncPgno, &pNeedSync);
+ rc = sqlite3PagerGet(pPager, needSyncPgno, &pPgHdr);
if( rc!=SQLITE_OK ) return rc;
pPager->needSync = 1;
- DATA_TO_PGHDR(pNeedSync)->needSync = 1;
- DATA_TO_PGHDR(pNeedSync)->inJournal = 1;
- makeDirty(DATA_TO_PGHDR(pNeedSync));
- sqlite3pager_unref(pNeedSync);
+ pPgHdr->needSync = 1;
+ pPgHdr->inJournal = 1;
+ makeDirty(pPgHdr);
+ sqlite3PagerUnref(pPgHdr);
}
return SQLITE_OK;
}
#endif
+/*
+** Return a pointer to the data for the specified page.
+*/
+void *sqlite3PagerGetData(DbPage *pPg){
+ return PGHDR_TO_DATA(pPg);
+}
+
+/*
+** Return a pointer to the Pager.nExtra bytes of "extra" space
+** allocated along with the specified page.
+*/
+void *sqlite3PagerGetExtra(DbPage *pPg){
+ Pager *pPager = pPg->pPager;
+ return (pPager?PGHDR_TO_EXTRA(pPg, pPager):0);
+}
+
+/*
+** Get/set the locking-mode for this pager. Parameter eMode must be one
+** of PAGER_LOCKINGMODE_QUERY, PAGER_LOCKINGMODE_NORMAL or
+** PAGER_LOCKINGMODE_EXCLUSIVE. If the parameter is not _QUERY, then
+** the locking-mode is set to the value specified.
+**
+** The returned value is either PAGER_LOCKINGMODE_NORMAL or
+** PAGER_LOCKINGMODE_EXCLUSIVE, indicating the current (possibly updated)
+** locking-mode.
+*/
+int sqlite3PagerLockingMode(Pager *pPager, int eMode){
+ assert( eMode==PAGER_LOCKINGMODE_QUERY
+ || eMode==PAGER_LOCKINGMODE_NORMAL
+ || eMode==PAGER_LOCKINGMODE_EXCLUSIVE );
+ assert( PAGER_LOCKINGMODE_QUERY<0 );
+ assert( PAGER_LOCKINGMODE_NORMAL>=0 && PAGER_LOCKINGMODE_EXCLUSIVE>=0 );
+ if( eMode>=0 && !pPager->tempFile ){
+ pPager->exclusiveMode = eMode;
+ }
+ return (int)pPager->exclusiveMode;
+}
+
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
/*
** Return the current state of the file lock for the given pager.
** The return value is one of NO_LOCK, SHARED_LOCK, RESERVED_LOCK,
** PENDING_LOCK, or EXCLUSIVE_LOCK.
*/
-int sqlite3pager_lockstate(Pager *pPager){
+int sqlite3PagerLockstate(Pager *pPager){
return sqlite3OsLockState(pPager->fd);
}
#endif
@@ -3920,7 +4310,7 @@ int sqlite3pager_lockstate(Pager *pPager){
/*
** Print a listing of all referenced pages and their ref count.
*/
-void sqlite3pager_refdump(Pager *pPager){
+void sqlite3PagerRefdump(Pager *pPager){
PgHdr *pPg;
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
if( pPg->nRef<=0 ) continue;
diff --git a/ext/pdo_sqlite/sqlite/src/pager.h b/ext/pdo_sqlite/sqlite/src/pager.h
index 555e52a03..5e011d118 100644
--- a/ext/pdo_sqlite/sqlite/src/pager.h
+++ b/ext/pdo_sqlite/sqlite/src/pager.h
@@ -57,67 +57,91 @@ typedef unsigned int Pgno;
typedef struct Pager Pager;
/*
-** Allowed values for the flags parameter to sqlite3pager_open().
+** Handle type for pages.
+*/
+typedef struct PgHdr DbPage;
+
+/*
+** Allowed values for the flags parameter to sqlite3PagerOpen().
**
** NOTE: This values must match the corresponding BTREE_ values in btree.h.
*/
#define PAGER_OMIT_JOURNAL 0x0001 /* Do not use a rollback journal */
#define PAGER_NO_READLOCK 0x0002 /* Omit readlocks on readonly files */
+/*
+** Valid values for the second argument to sqlite3PagerLockingMode().
+*/
+#define PAGER_LOCKINGMODE_QUERY -1
+#define PAGER_LOCKINGMODE_NORMAL 0
+#define PAGER_LOCKINGMODE_EXCLUSIVE 1
/*
** See source code comments for a detailed description of the following
** routines:
*/
-int sqlite3pager_open(Pager **ppPager, const char *zFilename,
+int sqlite3PagerOpen(Pager **ppPager, const char *zFilename,
int nExtra, int flags);
-void sqlite3pager_set_busyhandler(Pager*, BusyHandler *pBusyHandler);
-void sqlite3pager_set_destructor(Pager*, void(*)(void*,int));
-void sqlite3pager_set_reiniter(Pager*, void(*)(void*,int));
-int sqlite3pager_set_pagesize(Pager*, int);
-void sqlite3pager_read_fileheader(Pager*, int, unsigned char*);
-void sqlite3pager_set_cachesize(Pager*, int);
-int sqlite3pager_close(Pager *pPager);
-int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage);
-void *sqlite3pager_lookup(Pager *pPager, Pgno pgno);
-int sqlite3pager_ref(void*);
-int sqlite3pager_unref(void*);
-Pgno sqlite3pager_pagenumber(void*);
-int sqlite3pager_write(void*);
-int sqlite3pager_iswriteable(void*);
-int sqlite3pager_overwrite(Pager *pPager, Pgno pgno, void*);
-int sqlite3pager_pagecount(Pager*);
-int sqlite3pager_truncate(Pager*,Pgno);
-int sqlite3pager_begin(void*, int exFlag);
-int sqlite3pager_commit(Pager*);
-int sqlite3pager_sync(Pager*,const char *zMaster, Pgno);
-int sqlite3pager_rollback(Pager*);
-int sqlite3pager_isreadonly(Pager*);
-int sqlite3pager_stmt_begin(Pager*);
-int sqlite3pager_stmt_commit(Pager*);
-int sqlite3pager_stmt_rollback(Pager*);
-void sqlite3pager_dont_rollback(void*);
-void sqlite3pager_dont_write(Pager*, Pgno);
-int sqlite3pager_refcount(Pager*);
-int *sqlite3pager_stats(Pager*);
-void sqlite3pager_set_safety_level(Pager*,int,int);
-const char *sqlite3pager_filename(Pager*);
-const char *sqlite3pager_dirname(Pager*);
-const char *sqlite3pager_journalname(Pager*);
-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);
+void sqlite3PagerSetBusyhandler(Pager*, BusyHandler *pBusyHandler);
+void sqlite3PagerSetDestructor(Pager*, void(*)(DbPage*,int));
+void sqlite3PagerSetReiniter(Pager*, void(*)(DbPage*,int));
+int sqlite3PagerSetPagesize(Pager*, int);
+int sqlite3PagerReadFileheader(Pager*, int, unsigned char*);
+void sqlite3PagerSetCachesize(Pager*, int);
+int sqlite3PagerClose(Pager *pPager);
+int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag);
+#define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0)
+DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno);
+int sqlite3PagerRef(DbPage*);
+int sqlite3PagerUnref(DbPage*);
+Pgno sqlite3PagerPagenumber(DbPage*);
+int sqlite3PagerWrite(DbPage*);
+int sqlite3PagerIswriteable(DbPage*);
+int sqlite3PagerOverwrite(Pager *pPager, Pgno pgno, void*);
+int sqlite3PagerPagecount(Pager*);
+int sqlite3PagerTruncate(Pager*,Pgno);
+int sqlite3PagerBegin(DbPage*, int exFlag);
+int sqlite3PagerCommitPhaseOne(Pager*,const char *zMaster, Pgno);
+int sqlite3PagerCommitPhaseTwo(Pager*);
+int sqlite3PagerRollback(Pager*);
+int sqlite3PagerIsreadonly(Pager*);
+int sqlite3PagerStmtBegin(Pager*);
+int sqlite3PagerStmtCommit(Pager*);
+int sqlite3PagerStmtRollback(Pager*);
+void sqlite3PagerDontRollback(DbPage*);
+void sqlite3PagerDontWrite(DbPage*);
+int sqlite3PagerRefcount(Pager*);
+int *sqlite3PagerStats(Pager*);
+void sqlite3PagerSetSafetyLevel(Pager*,int,int);
+const char *sqlite3PagerFilename(Pager*);
+const char *sqlite3PagerDirname(Pager*);
+const char *sqlite3PagerJournalname(Pager*);
+int sqlite3PagerNosync(Pager*);
+int sqlite3PagerRename(Pager*, const char *zNewName);
+void sqlite3PagerSetCodec(Pager*,void*(*)(void*,void*,Pgno,int),void*);
+int sqlite3PagerMovepage(Pager*,DbPage*,Pgno);
+int sqlite3PagerReset(Pager*);
+int sqlite3PagerReleaseMemory(int);
+
+void *sqlite3PagerGetData(DbPage *);
+void *sqlite3PagerGetExtra(DbPage *);
+int sqlite3PagerLockingMode(Pager *, int);
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
-int sqlite3pager_lockstate(Pager*);
+int sqlite3PagerLockstate(Pager*);
#endif
#ifdef SQLITE_TEST
-void sqlite3pager_refdump(Pager*);
+void sqlite3PagerRefdump(Pager*);
int pager3_refinfo_enable;
#endif
+#ifdef SQLITE_TEST
+void disable_simulated_io_errors(void);
+void enable_simulated_io_errors(void);
+#else
+# define disable_simulated_io_errors()
+# define enable_simulated_io_errors()
+#endif
+
#endif /* _PAGER_H_ */
diff --git a/ext/pdo_sqlite/sqlite/src/parse.c b/ext/pdo_sqlite/sqlite/src/parse.c
index 801bb7ca1..b560230f5 100644
--- a/ext/pdo_sqlite/sqlite/src/parse.c
+++ b/ext/pdo_sqlite/sqlite/src/parse.c
@@ -82,7 +82,8 @@ struct AttachKey { int type; Token key; };
** This is typically a union of many types, one of
** which is sqlite3ParserTOKENTYPE. The entry in the union
** for base tokens is called "yy0".
-** YYSTACKDEPTH is the maximum depth of the parser's stack.
+** YYSTACKDEPTH is the maximum depth of the parser's stack. If
+** zero the stack is dynamically sized using realloc()
** sqlite3ParserARG_SDECL A static variable declaration for the %extra_argument
** sqlite3ParserARG_PDECL A parameter declaration for the %extra_argument
** sqlite3ParserARG_STORE Code to store %extra_argument into yypParser
@@ -95,7 +96,7 @@ struct AttachKey { int type; Token key; };
#define YYCODETYPE unsigned char
#define YYNOCODE 248
#define YYACTIONTYPE unsigned short int
-#define YYWILDCARD 60
+#define YYWILDCARD 59
#define sqlite3ParserTOKENTYPE Token
typedef union {
sqlite3ParserTOKENTYPE yy0;
@@ -114,14 +115,16 @@ typedef union {
IdList* yy432;
int yy495;
} YYMINORTYPE;
+#ifndef YYSTACKDEPTH
#define YYSTACKDEPTH 100
+#endif
#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 309
-#define YYERRORSYMBOL 139
+#define YYNSTATE 586
+#define YYNRULE 311
+#define YYERRORSYMBOL 138
#define YYERRSYMDT yy495
#define YYFALLBACK 1
#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
@@ -176,409 +179,415 @@ typedef union {
** yy_default[] Default action for each state.
*/
static const YYACTIONTYPE yy_action[] = {
- /* 0 */ 287, 67, 291, 69, 150, 168, 206, 431, 61, 61,
- /* 10 */ 61, 61, 66, 63, 63, 63, 63, 64, 64, 65,
- /* 20 */ 65, 65, 66, 441, 322, 164, 444, 450, 68, 63,
- /* 30 */ 63, 63, 63, 64, 64, 65, 65, 65, 66, 64,
- /* 40 */ 64, 65, 65, 65, 66, 60, 58, 295, 454, 455,
- /* 50 */ 451, 451, 62, 62, 61, 61, 61, 61, 513, 63,
- /* 60 */ 63, 63, 63, 64, 64, 65, 65, 65, 66, 287,
- /* 70 */ 318, 67, 431, 69, 150, 79, 160, 114, 224, 314,
- /* 80 */ 229, 315, 172, 249, 891, 120, 580, 515, 518, 2,
- /* 90 */ 250, 566, 422, 35, 223, 444, 450, 528, 20, 57,
- /* 100 */ 384, 381, 63, 63, 63, 63, 64, 64, 65, 65,
- /* 110 */ 65, 66, 287, 473, 60, 58, 295, 454, 455, 451,
- /* 120 */ 451, 62, 62, 61, 61, 61, 61, 389, 63, 63,
- /* 130 */ 63, 63, 64, 64, 65, 65, 65, 66, 444, 450,
- /* 140 */ 91, 311, 385, 480, 236, 383, 269, 204, 2, 83,
- /* 150 */ 581, 384, 381, 470, 196, 439, 209, 60, 58, 295,
- /* 160 */ 454, 455, 451, 451, 62, 62, 61, 61, 61, 61,
- /* 170 */ 170, 63, 63, 63, 63, 64, 64, 65, 65, 65,
- /* 180 */ 66, 287, 486, 439, 209, 132, 109, 270, 423, 443,
- /* 190 */ 402, 281, 390, 391, 441, 517, 164, 318, 507, 67,
- /* 200 */ 526, 69, 150, 562, 423, 143, 516, 444, 450, 145,
- /* 210 */ 146, 578, 882, 373, 882, 511, 171, 156, 514, 422,
- /* 220 */ 40, 337, 426, 19, 287, 140, 60, 58, 295, 454,
- /* 230 */ 455, 451, 451, 62, 62, 61, 61, 61, 61, 380,
- /* 240 */ 63, 63, 63, 63, 64, 64, 65, 65, 65, 66,
- /* 250 */ 444, 450, 575, 404, 405, 428, 428, 428, 329, 332,
- /* 260 */ 240, 545, 67, 468, 69, 150, 271, 287, 291, 60,
- /* 270 */ 58, 295, 454, 455, 451, 451, 62, 62, 61, 61,
- /* 280 */ 61, 61, 124, 63, 63, 63, 63, 64, 64, 65,
- /* 290 */ 65, 65, 66, 444, 450, 401, 510, 389, 290, 544,
- /* 300 */ 65, 65, 65, 66, 507, 389, 542, 405, 443, 294,
- /* 310 */ 434, 435, 60, 58, 295, 454, 455, 451, 451, 62,
- /* 320 */ 62, 61, 61, 61, 61, 206, 63, 63, 63, 63,
- /* 330 */ 64, 64, 65, 65, 65, 66, 519, 514, 366, 287,
- /* 340 */ 75, 426, 148, 490, 224, 314, 229, 315, 172, 249,
- /* 350 */ 367, 265, 264, 1, 574, 286, 250, 389, 416, 445,
- /* 360 */ 446, 206, 390, 391, 177, 444, 450, 340, 343, 344,
- /* 370 */ 390, 391, 208, 357, 428, 428, 428, 360, 168, 345,
- /* 380 */ 431, 448, 449, 78, 60, 58, 295, 454, 455, 451,
- /* 390 */ 451, 62, 62, 61, 61, 61, 61, 476, 63, 63,
- /* 400 */ 63, 63, 64, 64, 65, 65, 65, 66, 287, 447,
- /* 410 */ 177, 561, 493, 340, 343, 344, 21, 318, 518, 318,
- /* 420 */ 431, 318, 390, 391, 318, 345, 475, 400, 20, 563,
- /* 430 */ 564, 489, 151, 177, 444, 450, 340, 343, 344, 422,
- /* 440 */ 34, 422, 34, 422, 34, 431, 422, 34, 345, 192,
- /* 450 */ 237, 147, 527, 60, 58, 295, 454, 455, 451, 451,
- /* 460 */ 62, 62, 61, 61, 61, 61, 423, 63, 63, 63,
- /* 470 */ 63, 64, 64, 65, 65, 65, 66, 287, 230, 348,
- /* 480 */ 408, 512, 298, 423, 334, 431, 318, 206, 318, 296,
- /* 490 */ 318, 208, 409, 154, 465, 9, 465, 458, 464, 389,
- /* 500 */ 374, 465, 173, 444, 450, 410, 173, 406, 422, 40,
- /* 510 */ 422, 48, 422, 48, 321, 434, 435, 407, 324, 475,
- /* 520 */ 457, 457, 60, 58, 295, 454, 455, 451, 451, 62,
- /* 530 */ 62, 61, 61, 61, 61, 459, 63, 63, 63, 63,
- /* 540 */ 64, 64, 65, 65, 65, 66, 287, 318, 499, 238,
- /* 550 */ 253, 480, 389, 338, 408, 149, 421, 306, 289, 307,
- /* 560 */ 420, 389, 289, 389, 390, 391, 409, 250, 500, 422,
- /* 570 */ 27, 155, 444, 450, 431, 422, 3, 208, 539, 410,
- /* 580 */ 335, 328, 578, 881, 324, 881, 457, 457, 484, 423,
- /* 590 */ 242, 60, 58, 295, 454, 455, 451, 451, 62, 62,
- /* 600 */ 61, 61, 61, 61, 255, 63, 63, 63, 63, 64,
- /* 610 */ 64, 65, 65, 65, 66, 287, 368, 390, 391, 488,
- /* 620 */ 90, 299, 324, 575, 457, 457, 390, 391, 390, 391,
- /* 630 */ 318, 525, 494, 318, 392, 393, 394, 518, 524, 431,
- /* 640 */ 241, 444, 450, 183, 477, 181, 571, 20, 324, 297,
- /* 650 */ 457, 457, 422, 28, 541, 422, 23, 505, 287, 339,
- /* 660 */ 60, 58, 295, 454, 455, 451, 451, 62, 62, 61,
- /* 670 */ 61, 61, 61, 318, 63, 63, 63, 63, 64, 64,
- /* 680 */ 65, 65, 65, 66, 444, 450, 421, 535, 354, 535,
- /* 690 */ 420, 259, 300, 505, 816, 422, 32, 74, 505, 76,
- /* 700 */ 188, 287, 505, 60, 58, 295, 454, 455, 451, 451,
- /* 710 */ 62, 62, 61, 61, 61, 61, 318, 63, 63, 63,
- /* 720 */ 63, 64, 64, 65, 65, 65, 66, 444, 450, 174,
- /* 730 */ 175, 176, 377, 216, 423, 480, 248, 301, 422, 53,
- /* 740 */ 505, 505, 259, 259, 287, 259, 60, 70, 295, 454,
- /* 750 */ 455, 451, 451, 62, 62, 61, 61, 61, 61, 365,
+ /* 0 */ 289, 898, 121, 585, 405, 169, 2, 435, 61, 61,
+ /* 10 */ 61, 61, 517, 63, 63, 63, 63, 64, 64, 65,
+ /* 20 */ 65, 65, 66, 230, 387, 384, 420, 426, 68, 63,
+ /* 30 */ 63, 63, 63, 64, 64, 65, 65, 65, 66, 230,
+ /* 40 */ 443, 208, 392, 447, 60, 59, 294, 430, 431, 427,
+ /* 50 */ 427, 62, 62, 61, 61, 61, 61, 205, 63, 63,
+ /* 60 */ 63, 63, 64, 64, 65, 65, 65, 66, 230, 289,
+ /* 70 */ 368, 316, 435, 487, 205, 80, 67, 415, 69, 151,
+ /* 80 */ 63, 63, 63, 63, 64, 64, 65, 65, 65, 66,
+ /* 90 */ 230, 515, 162, 410, 35, 420, 426, 443, 571, 58,
+ /* 100 */ 64, 64, 65, 65, 65, 66, 230, 393, 394, 417,
+ /* 110 */ 417, 417, 289, 60, 59, 294, 430, 431, 427, 427,
+ /* 120 */ 62, 62, 61, 61, 61, 61, 302, 63, 63, 63,
+ /* 130 */ 63, 64, 64, 65, 65, 65, 66, 230, 420, 426,
+ /* 140 */ 92, 65, 65, 65, 66, 230, 392, 456, 472, 67,
+ /* 150 */ 56, 69, 151, 169, 406, 435, 60, 59, 294, 430,
+ /* 160 */ 431, 427, 427, 62, 62, 61, 61, 61, 61, 247,
+ /* 170 */ 63, 63, 63, 63, 64, 64, 65, 65, 65, 66,
+ /* 180 */ 230, 289, 569, 522, 292, 620, 111, 478, 515, 447,
+ /* 190 */ 230, 316, 403, 21, 67, 460, 69, 151, 66, 230,
+ /* 200 */ 568, 443, 208, 67, 224, 69, 151, 420, 426, 146,
+ /* 210 */ 147, 393, 394, 410, 41, 386, 148, 531, 2, 487,
+ /* 220 */ 435, 566, 232, 415, 289, 60, 59, 294, 430, 431,
+ /* 230 */ 427, 427, 62, 62, 61, 61, 61, 61, 316, 63,
+ /* 240 */ 63, 63, 63, 64, 64, 65, 65, 65, 66, 230,
+ /* 250 */ 420, 426, 486, 330, 211, 417, 417, 417, 359, 270,
+ /* 260 */ 410, 41, 378, 207, 362, 542, 245, 289, 60, 59,
+ /* 270 */ 294, 430, 431, 427, 427, 62, 62, 61, 61, 61,
+ /* 280 */ 61, 392, 63, 63, 63, 63, 64, 64, 65, 65,
+ /* 290 */ 65, 66, 230, 420, 426, 260, 299, 273, 522, 271,
+ /* 300 */ 522, 210, 370, 319, 223, 433, 433, 532, 21, 576,
+ /* 310 */ 21, 60, 59, 294, 430, 431, 427, 427, 62, 62,
+ /* 320 */ 61, 61, 61, 61, 191, 63, 63, 63, 63, 64,
+ /* 330 */ 64, 65, 65, 65, 66, 230, 261, 316, 239, 76,
+ /* 340 */ 289, 544, 299, 149, 482, 150, 393, 394, 178, 240,
+ /* 350 */ 569, 341, 344, 345, 404, 520, 445, 322, 165, 410,
+ /* 360 */ 28, 540, 346, 517, 248, 539, 420, 426, 568, 567,
+ /* 370 */ 161, 115, 238, 339, 243, 340, 173, 358, 272, 411,
+ /* 380 */ 821, 488, 79, 249, 60, 59, 294, 430, 431, 427,
+ /* 390 */ 427, 62, 62, 61, 61, 61, 61, 530, 63, 63,
+ /* 400 */ 63, 63, 64, 64, 65, 65, 65, 66, 230, 289,
+ /* 410 */ 248, 178, 465, 485, 341, 344, 345, 115, 238, 339,
+ /* 420 */ 243, 340, 173, 82, 316, 346, 316, 491, 492, 249,
+ /* 430 */ 565, 207, 152, 523, 489, 420, 426, 178, 529, 503,
+ /* 440 */ 341, 344, 345, 407, 472, 528, 410, 35, 410, 35,
+ /* 450 */ 171, 346, 198, 60, 59, 294, 430, 431, 427, 427,
+ /* 460 */ 62, 62, 61, 61, 61, 61, 411, 63, 63, 63,
+ /* 470 */ 63, 64, 64, 65, 65, 65, 66, 230, 289, 548,
+ /* 480 */ 579, 288, 502, 234, 411, 316, 411, 316, 296, 283,
+ /* 490 */ 298, 316, 445, 521, 165, 476, 172, 157, 421, 422,
+ /* 500 */ 457, 335, 457, 144, 420, 426, 366, 410, 35, 410,
+ /* 510 */ 36, 435, 1, 410, 49, 327, 392, 547, 193, 424,
+ /* 520 */ 425, 156, 60, 59, 294, 430, 431, 427, 427, 62,
+ /* 530 */ 62, 61, 61, 61, 61, 333, 63, 63, 63, 63,
+ /* 540 */ 64, 64, 65, 65, 65, 66, 230, 289, 423, 332,
+ /* 550 */ 452, 252, 411, 295, 438, 439, 297, 316, 349, 307,
+ /* 560 */ 231, 457, 453, 321, 438, 439, 392, 369, 266, 265,
+ /* 570 */ 189, 217, 392, 420, 426, 454, 435, 493, 205, 410,
+ /* 580 */ 49, 393, 394, 583, 889, 174, 889, 494, 545, 492,
+ /* 590 */ 392, 60, 59, 294, 430, 431, 427, 427, 62, 62,
+ /* 600 */ 61, 61, 61, 61, 411, 63, 63, 63, 63, 64,
+ /* 610 */ 64, 65, 65, 65, 66, 230, 289, 207, 586, 387,
+ /* 620 */ 384, 91, 10, 580, 336, 308, 392, 207, 367, 480,
+ /* 630 */ 316, 393, 394, 583, 888, 219, 888, 393, 394, 476,
+ /* 640 */ 291, 233, 420, 426, 481, 249, 410, 3, 434, 260,
+ /* 650 */ 317, 363, 410, 29, 448, 393, 394, 468, 260, 289,
+ /* 660 */ 60, 59, 294, 430, 431, 427, 427, 62, 62, 61,
+ /* 670 */ 61, 61, 61, 580, 63, 63, 63, 63, 64, 64,
+ /* 680 */ 65, 65, 65, 66, 230, 420, 426, 391, 312, 388,
+ /* 690 */ 555, 393, 394, 75, 204, 77, 395, 396, 397, 557,
+ /* 700 */ 357, 197, 289, 60, 59, 294, 430, 431, 427, 427,
+ /* 710 */ 62, 62, 61, 61, 61, 61, 316, 63, 63, 63,
+ /* 720 */ 63, 64, 64, 65, 65, 65, 66, 230, 420, 426,
+ /* 730 */ 319, 116, 433, 433, 319, 411, 433, 433, 410, 24,
+ /* 740 */ 319, 515, 433, 433, 515, 289, 60, 70, 294, 430,
+ /* 750 */ 431, 427, 427, 62, 62, 61, 61, 61, 61, 375,
/* 760 */ 63, 63, 63, 63, 64, 64, 65, 65, 65, 66,
- /* 770 */ 444, 450, 247, 319, 244, 302, 304, 248, 167, 156,
- /* 780 */ 361, 248, 379, 260, 552, 259, 554, 287, 259, 219,
- /* 790 */ 58, 295, 454, 455, 451, 451, 62, 62, 61, 61,
- /* 800 */ 61, 61, 318, 63, 63, 63, 63, 64, 64, 65,
- /* 810 */ 65, 65, 66, 444, 450, 484, 432, 484, 22, 248,
- /* 820 */ 248, 207, 388, 364, 422, 24, 555, 364, 54, 556,
- /* 830 */ 309, 119, 437, 437, 295, 454, 455, 451, 451, 62,
- /* 840 */ 62, 61, 61, 61, 61, 318, 63, 63, 63, 63,
- /* 850 */ 64, 64, 65, 65, 65, 66, 71, 325, 318, 4,
- /* 860 */ 318, 537, 318, 293, 259, 536, 259, 422, 51, 318,
- /* 870 */ 161, 320, 71, 325, 318, 4, 355, 356, 305, 293,
- /* 880 */ 422, 96, 422, 93, 422, 98, 225, 320, 327, 217,
- /* 890 */ 115, 422, 99, 218, 190, 318, 422, 110, 226, 443,
- /* 900 */ 318, 259, 318, 417, 327, 272, 427, 372, 318, 5,
- /* 910 */ 418, 318, 413, 414, 330, 443, 318, 422, 111, 73,
- /* 920 */ 72, 197, 422, 16, 422, 97, 152, 71, 316, 317,
- /* 930 */ 422, 33, 426, 422, 94, 73, 72, 487, 422, 52,
- /* 940 */ 318, 200, 274, 71, 316, 317, 71, 325, 426, 4,
- /* 950 */ 318, 206, 318, 293, 318, 423, 463, 318, 12, 179,
- /* 960 */ 423, 320, 422, 112, 615, 428, 428, 428, 429, 430,
- /* 970 */ 11, 323, 422, 113, 422, 25, 422, 36, 327, 422,
- /* 980 */ 37, 428, 428, 428, 429, 430, 11, 498, 497, 443,
- /* 990 */ 158, 18, 318, 423, 81, 220, 221, 222, 101, 182,
- /* 1000 */ 482, 318, 169, 318, 491, 318, 12, 318, 440, 73,
- /* 1010 */ 72, 202, 466, 276, 422, 26, 474, 71, 316, 317,
- /* 1020 */ 277, 318, 426, 422, 38, 422, 39, 422, 41, 422,
- /* 1030 */ 42, 318, 199, 423, 544, 503, 252, 124, 124, 198,
- /* 1040 */ 318, 479, 201, 422, 43, 318, 483, 452, 318, 246,
- /* 1050 */ 347, 318, 124, 422, 29, 428, 428, 428, 429, 430,
- /* 1060 */ 11, 495, 422, 30, 496, 576, 318, 422, 44, 501,
- /* 1070 */ 422, 45, 318, 422, 46, 520, 318, 533, 534, 318,
- /* 1080 */ 540, 318, 124, 502, 185, 371, 273, 264, 422, 47,
- /* 1090 */ 254, 288, 256, 257, 422, 31, 206, 258, 422, 10,
- /* 1100 */ 352, 422, 49, 422, 50, 577, 548, 549, 169, 88,
- /* 1110 */ 559, 263, 88, 359, 362, 573, 363, 285, 266, 267,
- /* 1120 */ 376, 268, 551, 560, 275, 375, 278, 279, 231, 570,
- /* 1130 */ 227, 142, 398, 326, 469, 436, 438, 472, 494, 159,
- /* 1140 */ 504, 547, 506, 558, 387, 395, 342, 396, 397, 8,
- /* 1150 */ 312, 313, 292, 416, 81, 403, 333, 232, 411, 80,
- /* 1160 */ 228, 331, 419, 415, 56, 77, 210, 412, 239, 166,
- /* 1170 */ 467, 211, 470, 471, 121, 82, 102, 336, 349, 282,
- /* 1180 */ 508, 424, 521, 522, 529, 523, 351, 180, 233, 509,
- /* 1190 */ 234, 184, 235, 283, 531, 425, 353, 85, 186, 117,
- /* 1200 */ 358, 128, 369, 370, 308, 567, 568, 243, 543, 481,
- /* 1210 */ 245, 212, 485, 189, 386, 569, 572, 129, 95, 214,
- /* 1220 */ 215, 399, 550, 116, 130, 205, 55, 616, 131, 617,
- /* 1230 */ 162, 163, 433, 134, 59, 213, 442, 557, 137, 100,
- /* 1240 */ 138, 139, 453, 456, 460, 153, 165, 461, 261, 462,
- /* 1250 */ 6, 122, 13, 12, 7, 532, 478, 123, 157, 492,
- /* 1260 */ 103, 341, 89, 251, 104, 84, 105, 346, 226, 178,
- /* 1270 */ 350, 141, 530, 125, 303, 169, 262, 187, 106, 126,
- /* 1280 */ 538, 284, 546, 127, 191, 14, 194, 92, 17, 86,
- /* 1290 */ 87, 193, 195, 133, 108, 553, 135, 565, 136, 15,
- /* 1300 */ 107, 203, 378, 280, 144, 382, 558, 118, 579, 558,
- /* 1310 */ 558, 310,
+ /* 770 */ 230, 420, 426, 538, 356, 538, 216, 260, 472, 303,
+ /* 780 */ 175, 176, 177, 254, 476, 515, 260, 383, 289, 5,
+ /* 790 */ 59, 294, 430, 431, 427, 427, 62, 62, 61, 61,
+ /* 800 */ 61, 61, 316, 63, 63, 63, 63, 64, 64, 65,
+ /* 810 */ 65, 65, 66, 230, 420, 426, 392, 236, 380, 247,
+ /* 820 */ 304, 258, 247, 256, 410, 33, 260, 558, 125, 467,
+ /* 830 */ 515, 416, 168, 157, 294, 430, 431, 427, 427, 62,
+ /* 840 */ 62, 61, 61, 61, 61, 306, 63, 63, 63, 63,
+ /* 850 */ 64, 64, 65, 65, 65, 66, 230, 72, 323, 452,
+ /* 860 */ 4, 153, 22, 247, 293, 305, 435, 559, 316, 382,
+ /* 870 */ 316, 453, 320, 72, 323, 316, 4, 366, 316, 180,
+ /* 880 */ 293, 393, 394, 20, 454, 141, 326, 316, 320, 325,
+ /* 890 */ 410, 53, 410, 52, 316, 411, 155, 410, 96, 447,
+ /* 900 */ 410, 94, 316, 500, 316, 325, 328, 469, 247, 410,
+ /* 910 */ 99, 444, 260, 411, 318, 447, 410, 100, 316, 74,
+ /* 920 */ 73, 467, 183, 260, 410, 110, 410, 112, 72, 314,
+ /* 930 */ 315, 435, 337, 415, 458, 74, 73, 479, 316, 377,
+ /* 940 */ 410, 17, 218, 19, 72, 314, 315, 72, 323, 415,
+ /* 950 */ 4, 205, 316, 274, 293, 316, 411, 466, 205, 409,
+ /* 960 */ 410, 97, 320, 408, 374, 417, 417, 417, 418, 419,
+ /* 970 */ 12, 376, 316, 206, 410, 34, 174, 410, 95, 325,
+ /* 980 */ 55, 417, 417, 417, 418, 419, 12, 310, 120, 447,
+ /* 990 */ 428, 159, 9, 260, 410, 25, 220, 221, 222, 102,
+ /* 1000 */ 441, 441, 316, 471, 409, 316, 475, 316, 408, 74,
+ /* 1010 */ 73, 436, 202, 23, 278, 455, 244, 13, 72, 314,
+ /* 1020 */ 315, 279, 316, 415, 410, 54, 316, 410, 113, 410,
+ /* 1030 */ 114, 291, 581, 200, 276, 547, 462, 497, 498, 199,
+ /* 1040 */ 316, 504, 201, 463, 410, 26, 316, 524, 410, 37,
+ /* 1050 */ 316, 474, 316, 170, 253, 417, 417, 417, 418, 419,
+ /* 1060 */ 12, 505, 410, 38, 510, 483, 316, 13, 410, 27,
+ /* 1070 */ 508, 582, 410, 39, 410, 40, 316, 255, 507, 506,
+ /* 1080 */ 512, 316, 125, 316, 511, 373, 275, 265, 410, 42,
+ /* 1090 */ 509, 290, 316, 251, 316, 125, 205, 257, 410, 43,
+ /* 1100 */ 316, 259, 316, 410, 44, 410, 30, 348, 316, 125,
+ /* 1110 */ 316, 353, 186, 316, 410, 31, 410, 45, 316, 543,
+ /* 1120 */ 379, 125, 410, 46, 410, 47, 316, 551, 264, 170,
+ /* 1130 */ 410, 48, 410, 32, 401, 410, 11, 552, 440, 89,
+ /* 1140 */ 410, 50, 301, 562, 578, 89, 287, 361, 410, 51,
+ /* 1150 */ 364, 365, 267, 268, 269, 554, 143, 564, 277, 324,
+ /* 1160 */ 280, 281, 575, 225, 442, 461, 464, 503, 241, 513,
+ /* 1170 */ 516, 550, 343, 160, 561, 390, 8, 313, 398, 399,
+ /* 1180 */ 400, 412, 82, 226, 331, 329, 81, 406, 57, 78,
+ /* 1190 */ 209, 167, 83, 459, 122, 414, 227, 334, 228, 338,
+ /* 1200 */ 300, 500, 103, 496, 246, 519, 514, 490, 495, 242,
+ /* 1210 */ 214, 518, 499, 229, 501, 413, 350, 533, 284, 525,
+ /* 1220 */ 526, 527, 235, 181, 473, 237, 285, 477, 182, 354,
+ /* 1230 */ 352, 184, 86, 185, 118, 535, 187, 546, 360, 190,
+ /* 1240 */ 129, 553, 139, 371, 372, 130, 215, 309, 560, 131,
+ /* 1250 */ 132, 133, 572, 577, 135, 573, 98, 574, 389, 262,
+ /* 1260 */ 402, 621, 536, 213, 101, 622, 432, 163, 164, 429,
+ /* 1270 */ 138, 71, 449, 437, 446, 140, 470, 154, 6, 450,
+ /* 1280 */ 7, 158, 166, 451, 14, 123, 13, 124, 484, 212,
+ /* 1290 */ 84, 342, 104, 105, 90, 250, 85, 117, 106, 347,
+ /* 1300 */ 179, 240, 351, 142, 534, 126, 18, 170, 93, 263,
+ /* 1310 */ 188, 107, 355, 286, 109, 127, 549, 541, 128, 119,
+ /* 1320 */ 537, 192, 15, 194, 195, 136, 196, 134, 556, 563,
+ /* 1330 */ 311, 137, 16, 108, 570, 203, 145, 385, 381, 282,
+ /* 1340 */ 584, 899, 899, 899, 899, 899, 87, 899, 88,
};
static const YYCODETYPE yy_lookahead[] = {
- /* 0 */ 16, 218, 16, 220, 221, 21, 111, 23, 70, 71,
- /* 10 */ 72, 73, 84, 75, 76, 77, 78, 79, 80, 81,
- /* 20 */ 82, 83, 84, 162, 163, 164, 42, 43, 74, 75,
- /* 30 */ 76, 77, 78, 79, 80, 81, 82, 83, 84, 79,
- /* 40 */ 80, 81, 82, 83, 84, 61, 62, 63, 64, 65,
- /* 50 */ 66, 67, 68, 69, 70, 71, 72, 73, 170, 75,
+ /* 0 */ 16, 139, 140, 141, 168, 21, 144, 23, 69, 70,
+ /* 10 */ 71, 72, 176, 74, 75, 76, 77, 78, 79, 80,
+ /* 20 */ 81, 82, 83, 84, 1, 2, 42, 43, 73, 74,
+ /* 30 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ /* 40 */ 78, 79, 23, 58, 60, 61, 62, 63, 64, 65,
+ /* 50 */ 66, 67, 68, 69, 70, 71, 72, 110, 74, 75,
/* 60 */ 76, 77, 78, 79, 80, 81, 82, 83, 84, 16,
- /* 70 */ 148, 218, 88, 220, 221, 22, 90, 91, 92, 93,
- /* 80 */ 94, 95, 96, 97, 140, 141, 142, 170, 148, 145,
- /* 90 */ 104, 238, 170, 171, 154, 42, 43, 157, 158, 46,
- /* 100 */ 1, 2, 75, 76, 77, 78, 79, 80, 81, 82,
- /* 110 */ 83, 84, 16, 22, 61, 62, 63, 64, 65, 66,
- /* 120 */ 67, 68, 69, 70, 71, 72, 73, 23, 75, 76,
+ /* 70 */ 123, 147, 88, 88, 110, 22, 216, 92, 218, 219,
+ /* 80 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ /* 90 */ 84, 147, 19, 169, 170, 42, 43, 78, 238, 46,
+ /* 100 */ 78, 79, 80, 81, 82, 83, 84, 88, 89, 124,
+ /* 110 */ 125, 126, 16, 60, 61, 62, 63, 64, 65, 66,
+ /* 120 */ 67, 68, 69, 70, 71, 72, 182, 74, 75, 76,
/* 130 */ 77, 78, 79, 80, 81, 82, 83, 84, 42, 43,
- /* 140 */ 44, 143, 144, 162, 222, 142, 14, 149, 145, 19,
- /* 150 */ 0, 1, 2, 23, 156, 79, 80, 61, 62, 63,
- /* 160 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
- /* 170 */ 156, 75, 76, 77, 78, 79, 80, 81, 82, 83,
- /* 180 */ 84, 16, 201, 79, 80, 53, 21, 55, 190, 59,
- /* 190 */ 169, 159, 88, 89, 162, 163, 164, 148, 177, 218,
- /* 200 */ 182, 220, 221, 99, 190, 114, 161, 42, 43, 79,
- /* 210 */ 80, 19, 20, 215, 22, 170, 202, 203, 88, 170,
- /* 220 */ 171, 207, 92, 19, 16, 21, 61, 62, 63, 64,
- /* 230 */ 65, 66, 67, 68, 69, 70, 71, 72, 73, 241,
+ /* 140 */ 44, 80, 81, 82, 83, 84, 23, 223, 161, 216,
+ /* 150 */ 19, 218, 219, 21, 23, 23, 60, 61, 62, 63,
+ /* 160 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 225,
+ /* 170 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ /* 180 */ 84, 16, 147, 147, 150, 112, 21, 200, 147, 58,
+ /* 190 */ 84, 147, 156, 157, 216, 217, 218, 219, 83, 84,
+ /* 200 */ 165, 78, 79, 216, 190, 218, 219, 42, 43, 78,
+ /* 210 */ 79, 88, 89, 169, 170, 141, 180, 181, 144, 88,
+ /* 220 */ 88, 98, 147, 92, 16, 60, 61, 62, 63, 64,
+ /* 230 */ 65, 66, 67, 68, 69, 70, 71, 72, 147, 74,
/* 240 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
- /* 250 */ 42, 43, 60, 186, 187, 125, 126, 127, 187, 210,
- /* 260 */ 211, 11, 218, 219, 220, 221, 134, 16, 16, 61,
+ /* 250 */ 42, 43, 169, 209, 210, 124, 125, 126, 224, 14,
+ /* 260 */ 169, 170, 227, 228, 230, 18, 225, 16, 60, 61,
/* 270 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
- /* 280 */ 72, 73, 22, 75, 76, 77, 78, 79, 80, 81,
- /* 290 */ 82, 83, 84, 42, 43, 168, 169, 23, 151, 49,
- /* 300 */ 81, 82, 83, 84, 177, 23, 186, 187, 59, 165,
- /* 310 */ 166, 167, 61, 62, 63, 64, 65, 66, 67, 68,
- /* 320 */ 69, 70, 71, 72, 73, 111, 75, 76, 77, 78,
- /* 330 */ 79, 80, 81, 82, 83, 84, 182, 88, 124, 16,
- /* 340 */ 132, 92, 22, 20, 92, 93, 94, 95, 96, 97,
- /* 350 */ 100, 101, 102, 19, 244, 245, 104, 23, 98, 42,
- /* 360 */ 43, 111, 88, 89, 90, 42, 43, 93, 94, 95,
- /* 370 */ 88, 89, 228, 226, 125, 126, 127, 230, 21, 105,
- /* 380 */ 23, 64, 65, 132, 61, 62, 63, 64, 65, 66,
- /* 390 */ 67, 68, 69, 70, 71, 72, 73, 115, 75, 76,
- /* 400 */ 77, 78, 79, 80, 81, 82, 83, 84, 16, 92,
- /* 410 */ 90, 148, 20, 93, 94, 95, 19, 148, 148, 148,
- /* 420 */ 23, 148, 88, 89, 148, 105, 22, 157, 158, 166,
- /* 430 */ 167, 20, 156, 90, 42, 43, 93, 94, 95, 170,
- /* 440 */ 171, 170, 171, 170, 171, 88, 170, 171, 105, 156,
- /* 450 */ 148, 181, 182, 61, 62, 63, 64, 65, 66, 67,
- /* 460 */ 68, 69, 70, 71, 72, 73, 190, 75, 76, 77,
- /* 470 */ 78, 79, 80, 81, 82, 83, 84, 16, 191, 16,
- /* 480 */ 12, 20, 213, 190, 213, 88, 148, 111, 148, 213,
- /* 490 */ 148, 228, 24, 89, 225, 19, 225, 20, 225, 23,
- /* 500 */ 124, 225, 43, 42, 43, 37, 43, 39, 170, 171,
- /* 510 */ 170, 171, 170, 171, 165, 166, 167, 49, 107, 115,
- /* 520 */ 109, 110, 61, 62, 63, 64, 65, 66, 67, 68,
- /* 530 */ 69, 70, 71, 72, 73, 20, 75, 76, 77, 78,
- /* 540 */ 79, 80, 81, 82, 83, 84, 16, 148, 30, 211,
- /* 550 */ 20, 162, 23, 148, 12, 156, 108, 217, 99, 217,
- /* 560 */ 112, 23, 99, 23, 88, 89, 24, 104, 50, 170,
- /* 570 */ 171, 148, 42, 43, 23, 170, 171, 228, 18, 37,
- /* 580 */ 148, 39, 19, 20, 107, 22, 109, 110, 148, 190,
- /* 590 */ 201, 61, 62, 63, 64, 65, 66, 67, 68, 69,
- /* 600 */ 70, 71, 72, 73, 14, 75, 76, 77, 78, 79,
- /* 610 */ 80, 81, 82, 83, 84, 16, 56, 88, 89, 81,
- /* 620 */ 21, 103, 107, 60, 109, 110, 88, 89, 88, 89,
- /* 630 */ 148, 177, 178, 148, 7, 8, 9, 148, 184, 88,
- /* 640 */ 148, 42, 43, 53, 115, 55, 157, 158, 107, 209,
- /* 650 */ 109, 110, 170, 171, 94, 170, 171, 148, 16, 81,
- /* 660 */ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
- /* 670 */ 71, 72, 73, 148, 75, 76, 77, 78, 79, 80,
- /* 680 */ 81, 82, 83, 84, 42, 43, 108, 100, 101, 102,
- /* 690 */ 112, 148, 183, 148, 134, 170, 171, 131, 148, 133,
- /* 700 */ 156, 16, 148, 61, 62, 63, 64, 65, 66, 67,
- /* 710 */ 68, 69, 70, 71, 72, 73, 148, 75, 76, 77,
- /* 720 */ 78, 79, 80, 81, 82, 83, 84, 42, 43, 100,
- /* 730 */ 101, 102, 189, 183, 190, 162, 227, 183, 170, 171,
- /* 740 */ 148, 148, 148, 148, 16, 148, 61, 62, 63, 64,
- /* 750 */ 65, 66, 67, 68, 69, 70, 71, 72, 73, 215,
- /* 760 */ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
- /* 770 */ 42, 43, 227, 148, 201, 183, 183, 227, 202, 203,
- /* 780 */ 236, 227, 239, 189, 189, 148, 189, 16, 148, 146,
- /* 790 */ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
- /* 800 */ 72, 73, 148, 75, 76, 77, 78, 79, 80, 81,
- /* 810 */ 82, 83, 84, 42, 43, 148, 20, 148, 22, 227,
- /* 820 */ 227, 193, 148, 148, 170, 171, 189, 148, 200, 189,
- /* 830 */ 242, 243, 125, 126, 63, 64, 65, 66, 67, 68,
- /* 840 */ 69, 70, 71, 72, 73, 148, 75, 76, 77, 78,
- /* 850 */ 79, 80, 81, 82, 83, 84, 16, 17, 148, 19,
- /* 860 */ 148, 25, 148, 23, 148, 29, 148, 170, 171, 148,
- /* 870 */ 19, 31, 16, 17, 148, 19, 209, 41, 209, 23,
- /* 880 */ 170, 171, 170, 171, 170, 171, 92, 31, 48, 214,
- /* 890 */ 148, 170, 171, 214, 22, 148, 170, 171, 104, 59,
- /* 900 */ 148, 148, 148, 27, 48, 189, 148, 189, 148, 192,
- /* 910 */ 34, 148, 7, 8, 148, 59, 148, 170, 171, 79,
- /* 920 */ 80, 156, 170, 171, 170, 171, 156, 87, 88, 89,
- /* 930 */ 170, 171, 92, 170, 171, 79, 80, 81, 170, 171,
- /* 940 */ 148, 19, 189, 87, 88, 89, 16, 17, 92, 19,
- /* 950 */ 148, 111, 148, 23, 148, 190, 20, 148, 22, 156,
- /* 960 */ 190, 31, 170, 171, 113, 125, 126, 127, 128, 129,
- /* 970 */ 130, 16, 170, 171, 170, 171, 170, 171, 48, 170,
- /* 980 */ 171, 125, 126, 127, 128, 129, 130, 91, 92, 59,
- /* 990 */ 5, 69, 148, 190, 122, 10, 11, 12, 13, 156,
- /* 1000 */ 20, 148, 22, 148, 20, 148, 22, 148, 162, 79,
- /* 1010 */ 80, 26, 148, 28, 170, 171, 204, 87, 88, 89,
- /* 1020 */ 35, 148, 92, 170, 171, 170, 171, 170, 171, 170,
- /* 1030 */ 171, 148, 47, 190, 49, 20, 20, 22, 22, 54,
- /* 1040 */ 148, 148, 57, 170, 171, 148, 148, 92, 148, 148,
- /* 1050 */ 20, 148, 22, 170, 171, 125, 126, 127, 128, 129,
- /* 1060 */ 130, 148, 170, 171, 179, 20, 148, 170, 171, 179,
- /* 1070 */ 170, 171, 148, 170, 171, 148, 148, 51, 52, 148,
- /* 1080 */ 20, 148, 22, 179, 232, 100, 101, 102, 170, 171,
- /* 1090 */ 148, 106, 148, 148, 170, 171, 111, 148, 170, 171,
- /* 1100 */ 233, 170, 171, 170, 171, 60, 20, 20, 22, 22,
- /* 1110 */ 20, 148, 22, 148, 148, 20, 148, 22, 148, 148,
- /* 1120 */ 135, 148, 148, 148, 148, 148, 148, 148, 194, 148,
- /* 1130 */ 173, 192, 150, 224, 173, 229, 229, 173, 178, 6,
- /* 1140 */ 173, 195, 173, 195, 147, 147, 174, 147, 147, 22,
- /* 1150 */ 155, 99, 40, 98, 122, 172, 119, 195, 172, 120,
- /* 1160 */ 172, 117, 172, 174, 121, 131, 223, 180, 97, 113,
- /* 1170 */ 153, 212, 23, 161, 153, 99, 19, 116, 15, 175,
- /* 1180 */ 161, 190, 172, 172, 153, 172, 153, 152, 196, 180,
- /* 1190 */ 197, 153, 198, 175, 153, 199, 38, 131, 152, 61,
- /* 1200 */ 153, 19, 153, 15, 153, 33, 153, 205, 185, 206,
- /* 1210 */ 205, 212, 206, 185, 1, 153, 138, 188, 160, 212,
- /* 1220 */ 212, 20, 195, 32, 188, 44, 19, 113, 188, 113,
- /* 1230 */ 113, 113, 20, 185, 19, 176, 20, 195, 216, 176,
- /* 1240 */ 216, 19, 92, 108, 11, 19, 22, 20, 234, 20,
- /* 1250 */ 118, 19, 22, 22, 118, 235, 115, 20, 113, 20,
- /* 1260 */ 19, 44, 237, 20, 19, 19, 19, 44, 104, 96,
- /* 1270 */ 16, 21, 17, 99, 36, 22, 134, 99, 19, 45,
- /* 1280 */ 45, 5, 1, 103, 123, 19, 14, 237, 231, 69,
- /* 1290 */ 69, 114, 116, 114, 240, 17, 103, 20, 123, 19,
- /* 1300 */ 14, 136, 58, 137, 19, 3, 247, 243, 4, 247,
- /* 1310 */ 247, 246,
+ /* 280 */ 72, 23, 74, 75, 76, 77, 78, 79, 80, 81,
+ /* 290 */ 82, 83, 84, 42, 43, 147, 16, 52, 147, 54,
+ /* 300 */ 147, 210, 55, 106, 153, 108, 109, 156, 157, 156,
+ /* 310 */ 157, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ /* 320 */ 69, 70, 71, 72, 22, 74, 75, 76, 77, 78,
+ /* 330 */ 79, 80, 81, 82, 83, 84, 188, 147, 92, 131,
+ /* 340 */ 16, 94, 16, 22, 20, 155, 88, 89, 90, 103,
+ /* 350 */ 147, 93, 94, 95, 167, 168, 161, 162, 163, 169,
+ /* 360 */ 170, 25, 104, 176, 84, 29, 42, 43, 165, 166,
+ /* 370 */ 90, 91, 92, 93, 94, 95, 96, 41, 133, 189,
+ /* 380 */ 133, 169, 131, 103, 60, 61, 62, 63, 64, 65,
+ /* 390 */ 66, 67, 68, 69, 70, 71, 72, 181, 74, 75,
+ /* 400 */ 76, 77, 78, 79, 80, 81, 82, 83, 84, 16,
+ /* 410 */ 84, 90, 22, 20, 93, 94, 95, 91, 92, 93,
+ /* 420 */ 94, 95, 96, 121, 147, 104, 147, 185, 186, 103,
+ /* 430 */ 227, 228, 155, 181, 160, 42, 43, 90, 176, 177,
+ /* 440 */ 93, 94, 95, 169, 161, 183, 169, 170, 169, 170,
+ /* 450 */ 155, 104, 155, 60, 61, 62, 63, 64, 65, 66,
+ /* 460 */ 67, 68, 69, 70, 71, 72, 189, 74, 75, 76,
+ /* 470 */ 77, 78, 79, 80, 81, 82, 83, 84, 16, 11,
+ /* 480 */ 244, 245, 20, 200, 189, 147, 189, 147, 211, 158,
+ /* 490 */ 211, 147, 161, 162, 163, 147, 201, 202, 42, 43,
+ /* 500 */ 223, 206, 223, 113, 42, 43, 147, 169, 170, 169,
+ /* 510 */ 170, 23, 19, 169, 170, 186, 23, 49, 155, 63,
+ /* 520 */ 64, 147, 60, 61, 62, 63, 64, 65, 66, 67,
+ /* 530 */ 68, 69, 70, 71, 72, 147, 74, 75, 76, 77,
+ /* 540 */ 78, 79, 80, 81, 82, 83, 84, 16, 92, 211,
+ /* 550 */ 12, 20, 189, 164, 165, 166, 208, 147, 16, 215,
+ /* 560 */ 220, 223, 24, 164, 165, 166, 23, 99, 100, 101,
+ /* 570 */ 155, 212, 23, 42, 43, 37, 88, 39, 110, 169,
+ /* 580 */ 170, 88, 89, 19, 20, 43, 22, 49, 185, 186,
+ /* 590 */ 23, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ /* 600 */ 69, 70, 71, 72, 189, 74, 75, 76, 77, 78,
+ /* 610 */ 79, 80, 81, 82, 83, 84, 16, 228, 0, 1,
+ /* 620 */ 2, 21, 19, 59, 147, 215, 23, 228, 213, 80,
+ /* 630 */ 147, 88, 89, 19, 20, 145, 22, 88, 89, 147,
+ /* 640 */ 98, 147, 42, 43, 20, 103, 169, 170, 20, 147,
+ /* 650 */ 147, 236, 169, 170, 20, 88, 89, 114, 147, 16,
+ /* 660 */ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ /* 670 */ 70, 71, 72, 59, 74, 75, 76, 77, 78, 79,
+ /* 680 */ 80, 81, 82, 83, 84, 42, 43, 147, 142, 143,
+ /* 690 */ 188, 88, 89, 130, 148, 132, 7, 8, 9, 188,
+ /* 700 */ 208, 155, 16, 60, 61, 62, 63, 64, 65, 66,
+ /* 710 */ 67, 68, 69, 70, 71, 72, 147, 74, 75, 76,
+ /* 720 */ 77, 78, 79, 80, 81, 82, 83, 84, 42, 43,
+ /* 730 */ 106, 147, 108, 109, 106, 189, 108, 109, 169, 170,
+ /* 740 */ 106, 147, 108, 109, 147, 16, 60, 61, 62, 63,
+ /* 750 */ 64, 65, 66, 67, 68, 69, 70, 71, 72, 213,
+ /* 760 */ 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
+ /* 770 */ 84, 42, 43, 99, 100, 101, 182, 147, 161, 182,
+ /* 780 */ 99, 100, 101, 14, 147, 147, 147, 241, 16, 191,
+ /* 790 */ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ /* 800 */ 71, 72, 147, 74, 75, 76, 77, 78, 79, 80,
+ /* 810 */ 81, 82, 83, 84, 42, 43, 23, 200, 188, 225,
+ /* 820 */ 182, 52, 225, 54, 169, 170, 147, 188, 22, 22,
+ /* 830 */ 147, 147, 201, 202, 62, 63, 64, 65, 66, 67,
+ /* 840 */ 68, 69, 70, 71, 72, 208, 74, 75, 76, 77,
+ /* 850 */ 78, 79, 80, 81, 82, 83, 84, 16, 17, 12,
+ /* 860 */ 19, 155, 19, 225, 23, 182, 23, 188, 147, 239,
+ /* 870 */ 147, 24, 31, 16, 17, 147, 19, 147, 147, 155,
+ /* 880 */ 23, 88, 89, 19, 37, 21, 39, 147, 31, 48,
+ /* 890 */ 169, 170, 169, 170, 147, 189, 89, 169, 170, 58,
+ /* 900 */ 169, 170, 147, 97, 147, 48, 147, 114, 225, 169,
+ /* 910 */ 170, 161, 147, 189, 16, 58, 169, 170, 147, 78,
+ /* 920 */ 79, 114, 155, 147, 169, 170, 169, 170, 87, 88,
+ /* 930 */ 89, 88, 80, 92, 147, 78, 79, 80, 147, 91,
+ /* 940 */ 169, 170, 212, 19, 87, 88, 89, 16, 17, 92,
+ /* 950 */ 19, 110, 147, 188, 23, 147, 189, 203, 110, 107,
+ /* 960 */ 169, 170, 31, 111, 188, 124, 125, 126, 127, 128,
+ /* 970 */ 129, 123, 147, 192, 169, 170, 43, 169, 170, 48,
+ /* 980 */ 199, 124, 125, 126, 127, 128, 129, 242, 243, 58,
+ /* 990 */ 92, 5, 68, 147, 169, 170, 10, 11, 12, 13,
+ /* 1000 */ 124, 125, 147, 147, 107, 147, 147, 147, 111, 78,
+ /* 1010 */ 79, 20, 26, 22, 28, 20, 147, 22, 87, 88,
+ /* 1020 */ 89, 35, 147, 92, 169, 170, 147, 169, 170, 169,
+ /* 1030 */ 170, 98, 20, 47, 188, 49, 27, 7, 8, 53,
+ /* 1040 */ 147, 147, 56, 34, 169, 170, 147, 147, 169, 170,
+ /* 1050 */ 147, 20, 147, 22, 147, 124, 125, 126, 127, 128,
+ /* 1060 */ 129, 178, 169, 170, 178, 20, 147, 22, 169, 170,
+ /* 1070 */ 30, 59, 169, 170, 169, 170, 147, 147, 91, 92,
+ /* 1080 */ 20, 147, 22, 147, 178, 99, 100, 101, 169, 170,
+ /* 1090 */ 50, 105, 147, 20, 147, 22, 110, 147, 169, 170,
+ /* 1100 */ 147, 147, 147, 169, 170, 169, 170, 20, 147, 22,
+ /* 1110 */ 147, 233, 232, 147, 169, 170, 169, 170, 147, 20,
+ /* 1120 */ 134, 22, 169, 170, 169, 170, 147, 20, 147, 22,
+ /* 1130 */ 169, 170, 169, 170, 149, 169, 170, 20, 229, 22,
+ /* 1140 */ 169, 170, 102, 20, 20, 22, 22, 147, 169, 170,
+ /* 1150 */ 147, 147, 147, 147, 147, 147, 191, 147, 147, 222,
+ /* 1160 */ 147, 147, 147, 193, 229, 172, 172, 177, 172, 172,
+ /* 1170 */ 172, 194, 173, 6, 194, 146, 22, 154, 146, 146,
+ /* 1180 */ 146, 189, 121, 194, 118, 116, 119, 23, 120, 130,
+ /* 1190 */ 221, 112, 98, 152, 152, 160, 195, 115, 196, 98,
+ /* 1200 */ 40, 97, 19, 179, 84, 179, 160, 171, 171, 171,
+ /* 1210 */ 226, 160, 173, 197, 171, 198, 15, 152, 174, 171,
+ /* 1220 */ 171, 171, 204, 151, 205, 204, 174, 205, 151, 38,
+ /* 1230 */ 152, 151, 130, 152, 60, 152, 151, 184, 152, 184,
+ /* 1240 */ 19, 194, 214, 152, 15, 187, 226, 152, 194, 187,
+ /* 1250 */ 187, 187, 33, 137, 184, 152, 159, 152, 1, 234,
+ /* 1260 */ 20, 112, 235, 175, 175, 112, 107, 112, 112, 92,
+ /* 1270 */ 214, 19, 11, 20, 20, 19, 114, 19, 117, 20,
+ /* 1280 */ 117, 112, 22, 20, 22, 19, 22, 20, 20, 44,
+ /* 1290 */ 19, 44, 19, 19, 237, 20, 19, 32, 19, 44,
+ /* 1300 */ 96, 103, 16, 21, 17, 98, 231, 22, 237, 133,
+ /* 1310 */ 98, 19, 36, 5, 240, 45, 1, 45, 102, 243,
+ /* 1320 */ 51, 122, 19, 113, 14, 102, 115, 113, 17, 123,
+ /* 1330 */ 246, 122, 19, 14, 20, 135, 19, 3, 57, 136,
+ /* 1340 */ 4, 247, 247, 247, 247, 247, 68, 247, 68,
};
-#define YY_SHIFT_USE_DFLT (-106)
-#define YY_SHIFT_MAX 382
+#define YY_SHIFT_USE_DFLT (-62)
+#define YY_SHIFT_MAX 385
static const short yy_shift_ofst[] = {
- /* 0 */ 99, 840, 985, -16, 840, 930, 930, 930, 274, -105,
- /* 10 */ 96, 930, 930, 930, 930, 930, -46, 250, 104, 540,
- /* 20 */ 551, 76, 76, 53, 165, 208, 251, 323, 392, 461,
- /* 30 */ 530, 599, 642, 685, 642, 642, 642, 642, 642, 642,
- /* 40 */ 642, 642, 642, 642, 642, 642, 642, 642, 642, 642,
- /* 50 */ 642, 728, 771, 771, 856, 930, 930, 930, 930, 930,
- /* 60 */ 930, 930, 930, 930, 930, 930, 930, 930, 930, 930,
- /* 70 */ 930, 930, 930, 930, 930, 930, 930, 930, 930, 930,
- /* 80 */ 930, 930, 930, 930, 930, 930, 930, 930, 930, 930,
- /* 90 */ 930, 930, 930, -62, -62, -14, 27, 27, -40, 219,
- /* 100 */ 463, 560, 540, 540, 540, 540, 540, 540, 540, 551,
- /* 110 */ -72, -106, -106, -106, 130, 252, 468, 468, 192, 563,
- /* 120 */ 150, 357, 540, 357, 540, 540, 540, 540, 540, 540,
- /* 130 */ 540, 540, 540, 540, 540, 540, 540, 214, 376, -105,
- /* 140 */ -105, -105, -106, -106, -106, 249, 249, 320, 343, 411,
- /* 150 */ 334, 477, 515, 542, 282, 529, 476, 538, 627, 540,
- /* 160 */ 540, 578, 540, 540, 397, 540, 540, 404, 540, 540,
- /* 170 */ 541, 404, 540, 540, 518, 518, 518, 540, 540, 541,
- /* 180 */ 540, 540, 541, 540, 836, 587, 540, 540, 541, 540,
- /* 190 */ 540, 540, 541, 540, 540, 540, 541, 541, 540, 540,
- /* 200 */ 540, 540, 540, 540, 204, 876, 448, 91, 707, 707,
- /* 210 */ 566, 876, 876, 459, 876, 876, 260, 872, 872, 1133,
- /* 220 */ 1133, 1133, 1133, 1127, 1052, 1052, 1112, 1052, 1055, 1052,
- /* 230 */ -105, 1032, 1037, 1039, 1044, 1043, 1034, 1056, 1071, 1149,
- /* 240 */ 1071, 1056, 1076, 1061, 1076, 1061, 1157, 1071, 1071, 1149,
- /* 250 */ 1112, 1052, 1052, 1052, 1157, 1163, 1056, 1056, 1056, 1056,
- /* 260 */ 1158, 1066, 1163, 1056, 1138, 1138, 1182, 1032, 1056, 1188,
- /* 270 */ 1188, 1188, 1032, 1138, 1182, 1056, 1172, 1172, 1056, 1056,
- /* 280 */ 1078, -106, -106, -106, -106, -106, -106, 317, 132, 629,
- /* 290 */ 590, 794, 905, 851, 796, 955, 936, 980, 984, 896,
- /* 300 */ 1015, 1016, 1030, 1026, 1060, 1086, 1087, 1090, 922, 1095,
- /* 310 */ 1045, 1213, 1201, 1191, 1181, 1207, 1114, 1116, 1117, 1118,
- /* 320 */ 1215, 1212, 1216, 1150, 1135, 1222, 1233, 1226, 1227, 1224,
- /* 330 */ 1229, 1132, 1230, 1136, 1231, 1141, 1232, 1237, 1145, 1239,
- /* 340 */ 1217, 1241, 1243, 1245, 1246, 1223, 1247, 1173, 1164, 1254,
- /* 350 */ 1255, 1250, 1174, 1238, 1234, 1253, 1235, 1142, 1178, 1259,
- /* 360 */ 1276, 1281, 1180, 1220, 1221, 1161, 1266, 1177, 1272, 1176,
- /* 370 */ 1278, 1179, 1193, 1175, 1280, 1277, 1286, 1244, 1165, 1166,
- /* 380 */ 1285, 1302, 1304,
+ /* 0 */ 23, 841, 986, -16, 841, 931, 931, 931, 258, 123,
+ /* 10 */ -36, 96, 931, 931, 931, 931, 931, -45, 468, 19,
+ /* 20 */ 567, 488, -38, -38, 53, 165, 208, 251, 324, 393,
+ /* 30 */ 462, 531, 600, 643, 686, 643, 643, 643, 643, 643,
+ /* 40 */ 643, 643, 643, 643, 643, 643, 643, 643, 643, 643,
+ /* 50 */ 643, 643, 729, 772, 772, 857, 931, 931, 931, 931,
+ /* 60 */ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ /* 70 */ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ /* 80 */ 931, 931, 931, 931, 931, 931, 931, 931, 931, 931,
+ /* 90 */ 931, 931, 931, 931, -61, -61, 6, 6, 280, 22,
+ /* 100 */ 61, 542, 247, 567, 567, 567, 567, 567, 567, 567,
+ /* 110 */ 115, 488, 106, -62, -62, 131, 326, 538, 538, 564,
+ /* 120 */ 614, 618, 132, 567, 132, 567, 567, 567, 567, 567,
+ /* 130 */ 567, 567, 567, 567, 567, 567, 567, 567, 848, -53,
+ /* 140 */ -36, -36, -36, -62, -62, -62, -15, -15, 321, 347,
+ /* 150 */ 624, 493, 628, 634, 847, 543, 793, 603, 549, 689,
+ /* 160 */ 567, 567, 852, 567, 567, 843, 567, 567, 807, 567,
+ /* 170 */ 567, 197, 807, 567, 567, 1040, 1040, 1040, 567, 567,
+ /* 180 */ 197, 567, 567, 197, 567, 336, 674, 567, 567, 197,
+ /* 190 */ 567, 567, 567, 197, 567, 567, 567, 197, 197, 567,
+ /* 200 */ 567, 567, 567, 567, 864, 897, 390, 876, 876, 563,
+ /* 210 */ 1009, 1009, 1009, 933, 1009, 1009, 806, 302, 302, 1167,
+ /* 220 */ 1167, 1167, 1167, 1154, -36, 1061, 1066, 1067, 1069, 1068,
+ /* 230 */ 1164, 1059, 1079, 1079, 1094, 1082, 1094, 1082, 1101, 1101,
+ /* 240 */ 1160, 1101, 1104, 1101, 1183, 1120, 1164, 1120, 1164, 1160,
+ /* 250 */ 1101, 1101, 1101, 1183, 1201, 1079, 1201, 1079, 1201, 1079,
+ /* 260 */ 1079, 1191, 1102, 1201, 1079, 1174, 1174, 1221, 1061, 1079,
+ /* 270 */ 1229, 1229, 1229, 1229, 1061, 1174, 1221, 1079, 1219, 1219,
+ /* 280 */ 1079, 1079, 1116, -62, -62, -62, -62, -62, -62, 456,
+ /* 290 */ 245, 681, 769, 73, 898, 991, 995, 1031, 1045, 246,
+ /* 300 */ 1030, 987, 1060, 1073, 1087, 1099, 1107, 1117, 1123, 924,
+ /* 310 */ 1124, 1012, 1257, 1240, 1149, 1153, 1155, 1156, 1177, 1159,
+ /* 320 */ 1252, 1253, 1254, 1256, 1261, 1258, 1259, 1260, 1263, 1161,
+ /* 330 */ 1262, 1163, 1264, 1162, 1266, 1267, 1169, 1268, 1265, 1245,
+ /* 340 */ 1271, 1247, 1273, 1275, 1274, 1277, 1255, 1279, 1204, 1198,
+ /* 350 */ 1286, 1287, 1282, 1207, 1276, 1269, 1270, 1285, 1272, 1176,
+ /* 360 */ 1212, 1292, 1308, 1315, 1216, 1278, 1280, 1199, 1303, 1210,
+ /* 370 */ 1310, 1211, 1311, 1214, 1223, 1209, 1313, 1206, 1314, 1319,
+ /* 380 */ 1281, 1200, 1203, 1317, 1334, 1336,
};
-#define YY_REDUCE_USE_DFLT (-218)
-#define YY_REDUCE_MAX 286
+#define YY_REDUCE_USE_DFLT (-165)
+#define YY_REDUCE_MAX 288
static const short yy_reduce_ofst[] = {
- /* 0 */ -56, 276, -2, -19, 399, 269, 49, 271, 270, 14,
- /* 10 */ -147, -78, 273, 338, 340, 342, 44, 544, 263, -60,
- /* 20 */ 32, 144, 349, -217, -217, -217, -217, -217, -217, -217,
- /* 30 */ -217, -217, -217, -217, -217, -217, -217, -217, -217, -217,
- /* 40 */ -217, -217, -217, -217, -217, -217, -217, -217, -217, -217,
- /* 50 */ -217, -217, -217, -217, 405, 482, 485, 525, 568, 654,
- /* 60 */ 697, 710, 712, 714, 721, 726, 747, 752, 754, 760,
- /* 70 */ 763, 768, 792, 802, 804, 806, 809, 844, 853, 855,
- /* 80 */ 857, 859, 873, 883, 892, 897, 900, 903, 918, 924,
- /* 90 */ 928, 931, 933, -217, -217, 127, -217, -217, -217, -217,
- /* 100 */ 454, 147, 509, 550, 554, 592, 593, 543, 489, -139,
- /* 110 */ -217, -217, -217, -217, 45, 21, 67, 120, 110, 110,
- /* 120 */ 3, 389, 440, 573, 545, 594, 667, 675, 669, 595,
- /* 130 */ 597, 637, 640, 716, 718, 679, 753, 293, 765, 770,
- /* 140 */ 803, 843, 628, 576, 588, -112, -83, 18, 154, 287,
- /* 150 */ 302, 287, 287, 71, 423, 432, 492, 625, 643, 674,
- /* 160 */ 742, 717, 625, 758, 846, 766, 864, 812, 893, 898,
- /* 170 */ 287, 812, 901, 913, 885, 890, 904, 927, 942, 287,
- /* 180 */ 944, 945, 287, 949, 852, 867, 963, 965, 287, 966,
- /* 190 */ 968, 970, 287, 971, 973, 974, 287, 287, 975, 976,
- /* 200 */ 977, 978, 979, 981, 982, 957, 939, 934, 906, 907,
- /* 210 */ 909, 961, 964, 960, 967, 969, 972, 946, 948, 997,
- /* 220 */ 998, 1000, 1001, 995, 983, 986, 987, 988, 989, 990,
- /* 230 */ 991, 962, 992, 993, 994, 996, 943, 1017, 959, 1012,
- /* 240 */ 999, 1021, 1002, 1003, 1005, 1006, 1004, 1007, 1008, 1019,
- /* 250 */ 1009, 1010, 1011, 1013, 1018, 1035, 1031, 1033, 1038, 1041,
- /* 260 */ 1014, 1020, 1046, 1047, 1023, 1028, 1022, 1027, 1049, 1029,
- /* 270 */ 1036, 1040, 1042, 1048, 1024, 1051, 1025, 1050, 1053, 1062,
- /* 280 */ 1054, 1058, 1059, 1063, 1057, 1064, 1065,
+ /* 0 */ -138, 277, 546, -13, 190, 279, 44, 338, 36, 203,
+ /* 10 */ 295, -140, 340, -76, 91, 344, 410, -22, 415, 35,
+ /* 20 */ 151, 331, 389, 399, -67, -67, -67, -67, -67, -67,
+ /* 30 */ -67, -67, -67, -67, -67, -67, -67, -67, -67, -67,
+ /* 40 */ -67, -67, -67, -67, -67, -67, -67, -67, -67, -67,
+ /* 50 */ -67, -67, -67, -67, -67, 477, 483, 569, 655, 721,
+ /* 60 */ 723, 728, 731, 740, 747, 755, 757, 771, 791, 805,
+ /* 70 */ 808, 825, 855, 858, 860, 875, 879, 893, 899, 903,
+ /* 80 */ 905, 919, 929, 934, 936, 945, 947, 953, 955, 961,
+ /* 90 */ 963, 966, 971, 979, -67, -67, -67, -67, 187, -67,
+ /* 100 */ -67, 262, 34, -56, 594, 597, 638, 683, 630, 153,
+ /* 110 */ -67, 195, -67, -67, -67, 274, -164, 242, 403, 236,
+ /* 120 */ 236, 74, 283, 348, 617, 41, 148, 492, 359, 637,
+ /* 130 */ 502, 511, 639, 679, 765, 776, 730, 846, 297, 363,
+ /* 140 */ 706, 724, 767, 781, 631, 745, 83, 212, 216, 252,
+ /* 150 */ 14, 75, 14, 14, 329, 374, 388, 494, 503, 490,
+ /* 160 */ 540, 584, 598, 503, 684, 750, 759, 787, 754, 856,
+ /* 170 */ 859, 14, 754, 869, 894, 883, 886, 906, 900, 907,
+ /* 180 */ 14, 930, 950, 14, 954, 880, 878, 981, 1000, 14,
+ /* 190 */ 1003, 1004, 1005, 14, 1006, 1007, 1008, 14, 14, 1010,
+ /* 200 */ 1011, 1013, 1014, 1015, 985, 965, 970, 909, 935, 937,
+ /* 210 */ 993, 994, 996, 990, 997, 998, 999, 977, 980, 1029,
+ /* 220 */ 1032, 1033, 1034, 1023, 992, 989, 1001, 1002, 1016, 1017,
+ /* 230 */ 1035, 969, 1041, 1042, 1018, 1019, 1021, 1022, 1036, 1037,
+ /* 240 */ 1024, 1038, 1039, 1043, 1044, 984, 1046, 1020, 1051, 1026,
+ /* 250 */ 1048, 1049, 1050, 1052, 1072, 1065, 1077, 1078, 1080, 1081,
+ /* 260 */ 1083, 1025, 1027, 1085, 1086, 1053, 1055, 1028, 1047, 1091,
+ /* 270 */ 1058, 1062, 1063, 1064, 1054, 1070, 1056, 1095, 1057, 1071,
+ /* 280 */ 1103, 1105, 1074, 1097, 1088, 1089, 1075, 1076, 1084,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 587, 813, 890, 702, 890, 813, 890, 813, 890, 706,
- /* 10 */ 864, 809, 813, 890, 890, 890, 784, 890, 835, 890,
- /* 20 */ 618, 835, 835, 737, 890, 890, 890, 890, 890, 890,
- /* 30 */ 890, 890, 738, 890, 812, 808, 804, 806, 805, 739,
- /* 40 */ 726, 735, 742, 718, 849, 744, 745, 750, 751, 865,
- /* 50 */ 868, 772, 790, 771, 890, 890, 890, 890, 890, 890,
- /* 60 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
- /* 70 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
- /* 80 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
- /* 90 */ 890, 890, 890, 774, 795, 611, 773, 783, 775, 776,
- /* 100 */ 671, 606, 890, 890, 890, 890, 890, 890, 890, 890,
- /* 110 */ 777, 778, 791, 792, 890, 890, 890, 890, 890, 890,
- /* 120 */ 587, 702, 890, 702, 890, 890, 890, 890, 890, 890,
- /* 130 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
- /* 140 */ 890, 890, 696, 706, 883, 890, 890, 662, 890, 890,
- /* 150 */ 890, 890, 890, 890, 890, 890, 890, 890, 594, 592,
- /* 160 */ 890, 694, 890, 890, 620, 890, 890, 704, 890, 890,
- /* 170 */ 709, 710, 890, 890, 890, 890, 890, 890, 890, 608,
- /* 180 */ 890, 890, 683, 890, 841, 890, 890, 890, 856, 890,
- /* 190 */ 890, 890, 854, 890, 890, 890, 685, 747, 823, 890,
- /* 200 */ 890, 869, 871, 890, 890, 729, 694, 703, 890, 890,
- /* 210 */ 807, 729, 729, 641, 729, 729, 644, 741, 741, 591,
- /* 220 */ 591, 591, 591, 661, 673, 673, 658, 673, 644, 673,
- /* 230 */ 890, 741, 732, 734, 722, 736, 890, 711, 730, 890,
- /* 240 */ 730, 711, 719, 721, 719, 721, 817, 730, 730, 890,
- /* 250 */ 658, 673, 673, 673, 817, 603, 711, 711, 711, 711,
- /* 260 */ 845, 848, 603, 711, 675, 675, 752, 741, 711, 682,
- /* 270 */ 682, 682, 741, 675, 752, 711, 867, 867, 711, 711,
- /* 280 */ 876, 628, 646, 646, 851, 883, 888, 890, 890, 890,
- /* 290 */ 890, 890, 890, 759, 890, 890, 890, 890, 890, 890,
- /* 300 */ 890, 890, 890, 890, 890, 890, 890, 890, 830, 890,
- /* 310 */ 890, 890, 890, 890, 890, 890, 764, 760, 890, 761,
- /* 320 */ 890, 890, 890, 890, 688, 890, 890, 890, 890, 890,
- /* 330 */ 890, 890, 723, 890, 733, 890, 890, 890, 890, 890,
- /* 340 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
- /* 350 */ 890, 890, 890, 890, 843, 844, 890, 890, 890, 890,
- /* 360 */ 890, 890, 890, 890, 890, 890, 890, 890, 890, 890,
- /* 370 */ 890, 890, 890, 890, 890, 890, 890, 875, 890, 890,
- /* 380 */ 878, 588, 890, 582, 585, 584, 586, 590, 593, 615,
- /* 390 */ 616, 617, 595, 596, 597, 598, 599, 600, 601, 607,
- /* 400 */ 609, 627, 629, 636, 674, 677, 678, 679, 859, 860,
- /* 410 */ 861, 637, 656, 659, 660, 638, 645, 727, 728, 639,
- /* 420 */ 692, 693, 756, 686, 687, 691, 758, 762, 763, 765,
- /* 430 */ 766, 614, 621, 622, 625, 626, 831, 833, 832, 834,
- /* 440 */ 624, 623, 767, 770, 779, 780, 782, 788, 794, 797,
- /* 450 */ 781, 786, 787, 789, 793, 796, 689, 690, 800, 802,
- /* 460 */ 803, 857, 858, 798, 810, 811, 712, 801, 785, 724,
- /* 470 */ 613, 731, 725, 695, 705, 714, 715, 716, 717, 700,
- /* 480 */ 701, 707, 720, 754, 755, 708, 697, 698, 699, 799,
- /* 490 */ 757, 768, 769, 640, 647, 648, 649, 652, 653, 654,
- /* 500 */ 655, 650, 651, 818, 819, 821, 820, 642, 643, 657,
- /* 510 */ 630, 631, 632, 633, 764, 634, 635, 619, 612, 663,
- /* 520 */ 666, 667, 668, 669, 670, 672, 664, 665, 610, 602,
- /* 530 */ 604, 713, 837, 846, 847, 842, 838, 839, 840, 605,
- /* 540 */ 814, 815, 676, 748, 749, 836, 850, 852, 753, 853,
- /* 550 */ 855, 880, 680, 681, 684, 822, 862, 740, 743, 746,
- /* 560 */ 824, 825, 826, 827, 828, 829, 863, 866, 870, 872,
- /* 570 */ 873, 874, 877, 879, 884, 885, 886, 889, 887, 589,
- /* 580 */ 583,
+ /* 0 */ 592, 818, 897, 707, 897, 818, 897, 818, 897, 843,
+ /* 10 */ 711, 872, 814, 818, 897, 897, 897, 789, 897, 843,
+ /* 20 */ 897, 623, 843, 843, 740, 897, 897, 897, 897, 897,
+ /* 30 */ 897, 897, 897, 741, 897, 817, 813, 809, 811, 810,
+ /* 40 */ 742, 731, 738, 745, 723, 856, 747, 748, 754, 755,
+ /* 50 */ 873, 871, 777, 776, 795, 897, 897, 897, 897, 897,
+ /* 60 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897,
+ /* 70 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897,
+ /* 80 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897,
+ /* 90 */ 897, 897, 897, 897, 779, 800, 778, 788, 616, 780,
+ /* 100 */ 781, 676, 611, 897, 897, 897, 897, 897, 897, 897,
+ /* 110 */ 782, 897, 783, 796, 797, 897, 897, 897, 897, 897,
+ /* 120 */ 897, 592, 707, 897, 707, 897, 897, 897, 897, 897,
+ /* 130 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897,
+ /* 140 */ 897, 897, 897, 701, 711, 890, 897, 897, 667, 897,
+ /* 150 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 599,
+ /* 160 */ 597, 897, 699, 897, 897, 625, 897, 897, 709, 897,
+ /* 170 */ 897, 714, 715, 897, 897, 897, 897, 897, 897, 897,
+ /* 180 */ 613, 897, 897, 688, 897, 849, 897, 897, 897, 863,
+ /* 190 */ 897, 897, 897, 861, 897, 897, 897, 690, 750, 830,
+ /* 200 */ 897, 876, 878, 897, 897, 699, 708, 897, 897, 812,
+ /* 210 */ 734, 734, 734, 646, 734, 734, 649, 744, 744, 596,
+ /* 220 */ 596, 596, 596, 666, 897, 744, 735, 737, 727, 739,
+ /* 230 */ 897, 897, 716, 716, 724, 726, 724, 726, 678, 678,
+ /* 240 */ 663, 678, 649, 678, 822, 827, 897, 827, 897, 663,
+ /* 250 */ 678, 678, 678, 822, 608, 716, 608, 716, 608, 716,
+ /* 260 */ 716, 853, 855, 608, 716, 680, 680, 756, 744, 716,
+ /* 270 */ 687, 687, 687, 687, 744, 680, 756, 716, 875, 875,
+ /* 280 */ 716, 716, 883, 633, 651, 651, 858, 890, 895, 897,
+ /* 290 */ 897, 897, 897, 763, 897, 897, 897, 897, 897, 897,
+ /* 300 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 836,
+ /* 310 */ 897, 897, 897, 897, 768, 764, 897, 765, 897, 693,
+ /* 320 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897,
+ /* 330 */ 728, 897, 736, 897, 897, 897, 897, 897, 897, 897,
+ /* 340 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897,
+ /* 350 */ 897, 897, 897, 897, 897, 897, 851, 852, 897, 897,
+ /* 360 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897,
+ /* 370 */ 897, 897, 897, 897, 897, 897, 897, 897, 897, 897,
+ /* 380 */ 882, 897, 897, 885, 593, 897, 587, 590, 589, 591,
+ /* 390 */ 595, 598, 620, 621, 622, 600, 601, 602, 603, 604,
+ /* 400 */ 605, 606, 612, 614, 632, 634, 618, 636, 697, 698,
+ /* 410 */ 760, 691, 692, 696, 771, 762, 766, 767, 769, 770,
+ /* 420 */ 784, 785, 787, 793, 799, 802, 786, 791, 792, 794,
+ /* 430 */ 798, 801, 694, 695, 805, 619, 626, 627, 630, 631,
+ /* 440 */ 839, 841, 840, 842, 629, 628, 772, 775, 807, 808,
+ /* 450 */ 864, 865, 866, 867, 868, 803, 815, 816, 717, 806,
+ /* 460 */ 790, 729, 732, 733, 730, 700, 710, 719, 720, 721,
+ /* 470 */ 722, 705, 706, 712, 725, 758, 759, 713, 702, 703,
+ /* 480 */ 704, 804, 761, 773, 774, 637, 638, 768, 639, 640,
+ /* 490 */ 641, 679, 682, 683, 684, 642, 661, 664, 665, 643,
+ /* 500 */ 650, 644, 645, 652, 653, 654, 657, 658, 659, 660,
+ /* 510 */ 655, 656, 823, 824, 828, 826, 825, 647, 648, 662,
+ /* 520 */ 635, 624, 617, 668, 671, 672, 673, 674, 675, 677,
+ /* 530 */ 669, 670, 615, 607, 609, 718, 845, 854, 850, 846,
+ /* 540 */ 847, 848, 610, 819, 820, 681, 752, 753, 844, 857,
+ /* 550 */ 859, 757, 860, 862, 887, 685, 686, 689, 829, 869,
+ /* 560 */ 743, 746, 749, 751, 831, 832, 833, 834, 837, 838,
+ /* 570 */ 835, 870, 874, 877, 879, 880, 881, 884, 886, 891,
+ /* 580 */ 892, 893, 896, 894, 594, 588,
};
#define YY_SZ_ACTTAB (int)(sizeof(yy_action)/sizeof(yy_action[0]))
@@ -646,7 +655,6 @@ static const YYCODETYPE yyFallback[] = {
23, /* REPLACE => ID */
23, /* RESTRICT => ID */
23, /* ROW => ID */
- 23, /* STATEMENT => ID */
23, /* TRIGGER => ID */
23, /* VACUUM => ID */
23, /* VIEW => ID */
@@ -679,6 +687,7 @@ static const YYCODETYPE yyFallback[] = {
0, /* SLASH => nothing */
0, /* REM => nothing */
0, /* CONCAT => nothing */
+ 0, /* COLLATE => nothing */
0, /* UMINUS => nothing */
0, /* UPLUS => nothing */
0, /* BITNOT => nothing */
@@ -691,7 +700,6 @@ static const YYCODETYPE yyFallback[] = {
0, /* UNIQUE => nothing */
0, /* CHECK => nothing */
0, /* REFERENCES => nothing */
- 0, /* COLLATE => nothing */
0, /* AUTOINCR => nothing */
0, /* ON => nothing */
0, /* DELETE => nothing */
@@ -763,7 +771,12 @@ struct yyParser {
int yyidx; /* Index of top element in stack */
int yyerrcnt; /* Shifts left before out of the error */
sqlite3ParserARG_SDECL /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+ int yystksz; /* Current side of the stack */
+ yyStackEntry *yystack; /* The parser's stack */
+#else
yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+#endif
};
typedef struct yyParser yyParser;
@@ -816,50 +829,50 @@ static const char *const yyTokenName[] = {
"INITIALLY", "INSTEAD", "LIKE_KW", "MATCH",
"KEY", "OF", "OFFSET", "PRAGMA",
"RAISE", "REPLACE", "RESTRICT", "ROW",
- "STATEMENT", "TRIGGER", "VACUUM", "VIEW",
- "VIRTUAL", "REINDEX", "RENAME", "CTIME_KW",
- "ANY", "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",
+ "TRIGGER", "VACUUM", "VIEW", "VIRTUAL",
+ "REINDEX", "RENAME", "CTIME_KW", "ANY",
+ "OR", "AND", "IS", "BETWEEN",
+ "IN", "ISNULL", "NOTNULL", "NE",
+ "EQ", "GT", "LE", "LT",
+ "GE", "ESCAPE", "BITAND", "BITOR",
+ "LSHIFT", "RSHIFT", "PLUS", "MINUS",
+ "STAR", "SLASH", "REM", "CONCAT",
+ "COLLATE", "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",
- "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",
+ "REFERENCES", "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", "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", "exprlist",
+ "setlist", "insert_cmd", "inscollist_opt", "itemlist",
+ "likeop", "escape", "between_op", "in_op",
+ "case_operand", "case_exprlist", "case_else", "expritem",
+ "uniqueflag", "idxitem", "collate", "nmnum",
"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",
@@ -922,11 +935,11 @@ static const char *const yyRuleName[] = {
/* 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",
+ /* 50 */ "ccons ::= DEFAULT term",
+ /* 51 */ "ccons ::= DEFAULT LP expr RP",
+ /* 52 */ "ccons ::= DEFAULT PLUS term",
+ /* 53 */ "ccons ::= DEFAULT MINUS term",
+ /* 54 */ "ccons ::= DEFAULT id",
/* 55 */ "ccons ::= NULL onconf",
/* 56 */ "ccons ::= NOT NULL onconf",
/* 57 */ "ccons ::= PRIMARY KEY sortorder onconf autoinc",
@@ -974,7 +987,7 @@ static const char *const yyRuleName[] = {
/* 99 */ "cmd ::= DROP TABLE ifexists fullname",
/* 100 */ "ifexists ::= IF EXISTS",
/* 101 */ "ifexists ::=",
- /* 102 */ "cmd ::= CREATE temp VIEW nm dbnm AS select",
+ /* 102 */ "cmd ::= CREATE temp VIEW ifnotexists nm dbnm AS select",
/* 103 */ "cmd ::= DROP VIEW ifexists fullname",
/* 104 */ "cmd ::= select",
/* 105 */ "select ::= oneselect",
@@ -1015,49 +1028,49 @@ static const char *const yyRuleName[] = {
/* 140 */ "using_opt ::=",
/* 141 */ "orderby_opt ::=",
/* 142 */ "orderby_opt ::= ORDER BY sortlist",
- /* 143 */ "sortlist ::= sortlist COMMA sortitem collate sortorder",
- /* 144 */ "sortlist ::= sortitem collate sortorder",
+ /* 143 */ "sortlist ::= sortlist COMMA sortitem sortorder",
+ /* 144 */ "sortlist ::= sortitem 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 */ "expr ::= REGISTER",
- /* 185 */ "expr ::= VARIABLE",
+ /* 149 */ "groupby_opt ::=",
+ /* 150 */ "groupby_opt ::= GROUP BY exprlist",
+ /* 151 */ "having_opt ::=",
+ /* 152 */ "having_opt ::= HAVING expr",
+ /* 153 */ "limit_opt ::=",
+ /* 154 */ "limit_opt ::= LIMIT expr",
+ /* 155 */ "limit_opt ::= LIMIT expr OFFSET expr",
+ /* 156 */ "limit_opt ::= LIMIT expr COMMA expr",
+ /* 157 */ "cmd ::= DELETE FROM fullname where_opt",
+ /* 158 */ "where_opt ::=",
+ /* 159 */ "where_opt ::= WHERE expr",
+ /* 160 */ "cmd ::= UPDATE orconf fullname SET setlist where_opt",
+ /* 161 */ "setlist ::= setlist COMMA nm EQ expr",
+ /* 162 */ "setlist ::= nm EQ expr",
+ /* 163 */ "cmd ::= insert_cmd INTO fullname inscollist_opt VALUES LP itemlist RP",
+ /* 164 */ "cmd ::= insert_cmd INTO fullname inscollist_opt select",
+ /* 165 */ "cmd ::= insert_cmd INTO fullname inscollist_opt DEFAULT VALUES",
+ /* 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|FLOAT|BLOB",
+ /* 182 */ "term ::= STRING",
+ /* 183 */ "expr ::= REGISTER",
+ /* 184 */ "expr ::= VARIABLE",
+ /* 185 */ "expr ::= expr COLLATE id",
/* 186 */ "expr ::= CAST LP expr AS typetoken RP",
/* 187 */ "expr ::= ID LP distinct exprlist RP",
/* 188 */ "expr ::= ID LP STAR RP",
@@ -1113,92 +1126,102 @@ static const char *const yyRuleName[] = {
/* 238 */ "idxlist ::= idxlist COMMA idxitem collate sortorder",
/* 239 */ "idxlist ::= idxitem collate sortorder",
/* 240 */ "idxitem ::= nm",
- /* 241 */ "cmd ::= DROP INDEX ifexists fullname",
- /* 242 */ "cmd ::= VACUUM",
- /* 243 */ "cmd ::= VACUUM nm",
- /* 244 */ "cmd ::= PRAGMA nm dbnm EQ nm",
- /* 245 */ "cmd ::= PRAGMA nm dbnm EQ ON",
- /* 246 */ "cmd ::= PRAGMA nm dbnm EQ plus_num",
- /* 247 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 248 */ "cmd ::= PRAGMA nm dbnm LP nm RP",
- /* 249 */ "cmd ::= PRAGMA nm dbnm",
- /* 250 */ "plus_num ::= plus_opt number",
- /* 251 */ "minus_num ::= MINUS number",
- /* 252 */ "number ::= INTEGER|FLOAT",
- /* 253 */ "plus_opt ::= PLUS",
- /* 254 */ "plus_opt ::=",
- /* 255 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END",
- /* 256 */ "trigger_decl ::= temp TRIGGER nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 257 */ "trigger_time ::= BEFORE",
- /* 258 */ "trigger_time ::= AFTER",
- /* 259 */ "trigger_time ::= INSTEAD OF",
- /* 260 */ "trigger_time ::=",
- /* 261 */ "trigger_event ::= DELETE|INSERT",
- /* 262 */ "trigger_event ::= UPDATE",
- /* 263 */ "trigger_event ::= UPDATE OF inscollist",
- /* 264 */ "foreach_clause ::=",
- /* 265 */ "foreach_clause ::= FOR EACH ROW",
- /* 266 */ "foreach_clause ::= FOR EACH STATEMENT",
- /* 267 */ "when_clause ::=",
- /* 268 */ "when_clause ::= WHEN expr",
- /* 269 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
- /* 270 */ "trigger_cmd_list ::=",
- /* 271 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt",
- /* 272 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP",
- /* 273 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select",
- /* 274 */ "trigger_cmd ::= DELETE FROM nm where_opt",
- /* 275 */ "trigger_cmd ::= select",
- /* 276 */ "expr ::= RAISE LP IGNORE RP",
- /* 277 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 278 */ "raisetype ::= ROLLBACK",
- /* 279 */ "raisetype ::= ABORT",
- /* 280 */ "raisetype ::= FAIL",
- /* 281 */ "cmd ::= DROP TRIGGER fullname",
- /* 282 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
- /* 283 */ "key_opt ::=",
- /* 284 */ "key_opt ::= KEY expr",
- /* 285 */ "database_kw_opt ::= DATABASE",
- /* 286 */ "database_kw_opt ::=",
- /* 287 */ "cmd ::= DETACH database_kw_opt expr",
- /* 288 */ "cmd ::= REINDEX",
- /* 289 */ "cmd ::= REINDEX nm dbnm",
- /* 290 */ "cmd ::= ANALYZE",
- /* 291 */ "cmd ::= ANALYZE nm dbnm",
- /* 292 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 293 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
- /* 294 */ "add_column_fullname ::= fullname",
- /* 295 */ "kwcolumn_opt ::=",
- /* 296 */ "kwcolumn_opt ::= COLUMNKW",
- /* 297 */ "cmd ::= create_vtab",
- /* 298 */ "cmd ::= create_vtab LP vtabarglist RP",
- /* 299 */ "create_vtab ::= CREATE VIRTUAL TABLE nm dbnm USING nm",
- /* 300 */ "vtabarglist ::= vtabarg",
- /* 301 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
- /* 302 */ "vtabarg ::=",
- /* 303 */ "vtabarg ::= vtabarg vtabargtoken",
- /* 304 */ "vtabargtoken ::= ANY",
- /* 305 */ "vtabargtoken ::= lp anylist RP",
- /* 306 */ "lp ::= LP",
- /* 307 */ "anylist ::=",
- /* 308 */ "anylist ::= anylist ANY",
+ /* 241 */ "collate ::=",
+ /* 242 */ "collate ::= COLLATE id",
+ /* 243 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 244 */ "cmd ::= VACUUM",
+ /* 245 */ "cmd ::= VACUUM nm",
+ /* 246 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 247 */ "cmd ::= PRAGMA nm dbnm EQ ON",
+ /* 248 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 249 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 250 */ "cmd ::= PRAGMA nm dbnm",
+ /* 251 */ "nmnum ::= plus_num",
+ /* 252 */ "nmnum ::= nm",
+ /* 253 */ "plus_num ::= plus_opt number",
+ /* 254 */ "minus_num ::= MINUS number",
+ /* 255 */ "number ::= INTEGER|FLOAT",
+ /* 256 */ "plus_opt ::= PLUS",
+ /* 257 */ "plus_opt ::=",
+ /* 258 */ "cmd ::= CREATE trigger_decl BEGIN trigger_cmd_list END",
+ /* 259 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 260 */ "trigger_time ::= BEFORE",
+ /* 261 */ "trigger_time ::= AFTER",
+ /* 262 */ "trigger_time ::= INSTEAD OF",
+ /* 263 */ "trigger_time ::=",
+ /* 264 */ "trigger_event ::= DELETE|INSERT",
+ /* 265 */ "trigger_event ::= UPDATE",
+ /* 266 */ "trigger_event ::= UPDATE OF inscollist",
+ /* 267 */ "foreach_clause ::=",
+ /* 268 */ "foreach_clause ::= FOR EACH ROW",
+ /* 269 */ "when_clause ::=",
+ /* 270 */ "when_clause ::= WHEN expr",
+ /* 271 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 272 */ "trigger_cmd_list ::=",
+ /* 273 */ "trigger_cmd ::= UPDATE orconf nm SET setlist where_opt",
+ /* 274 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt VALUES LP itemlist RP",
+ /* 275 */ "trigger_cmd ::= insert_cmd INTO nm inscollist_opt select",
+ /* 276 */ "trigger_cmd ::= DELETE FROM nm where_opt",
+ /* 277 */ "trigger_cmd ::= select",
+ /* 278 */ "expr ::= RAISE LP IGNORE RP",
+ /* 279 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 280 */ "raisetype ::= ROLLBACK",
+ /* 281 */ "raisetype ::= ABORT",
+ /* 282 */ "raisetype ::= FAIL",
+ /* 283 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 284 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 285 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 286 */ "key_opt ::=",
+ /* 287 */ "key_opt ::= KEY expr",
+ /* 288 */ "database_kw_opt ::= DATABASE",
+ /* 289 */ "database_kw_opt ::=",
+ /* 290 */ "cmd ::= REINDEX",
+ /* 291 */ "cmd ::= REINDEX nm dbnm",
+ /* 292 */ "cmd ::= ANALYZE",
+ /* 293 */ "cmd ::= ANALYZE nm dbnm",
+ /* 294 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 295 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt column",
+ /* 296 */ "add_column_fullname ::= fullname",
+ /* 297 */ "kwcolumn_opt ::=",
+ /* 298 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 299 */ "cmd ::= create_vtab",
+ /* 300 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 301 */ "create_vtab ::= CREATE VIRTUAL TABLE nm dbnm USING nm",
+ /* 302 */ "vtabarglist ::= vtabarg",
+ /* 303 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 304 */ "vtabarg ::=",
+ /* 305 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 306 */ "vtabargtoken ::= ANY",
+ /* 307 */ "vtabargtoken ::= lp anylist RP",
+ /* 308 */ "lp ::= LP",
+ /* 309 */ "anylist ::=",
+ /* 310 */ "anylist ::= anylist ANY",
};
#endif /* NDEBUG */
+
+#if YYSTACKDEPTH<=0
/*
-** This function returns the symbolic name associated with a token
-** value.
+** Try to increase the size of the parser stack.
*/
-const char *sqlite3ParserTokenName(int tokenType){
+static void yyGrowStack(yyParser *p){
+ int newSize;
+ yyStackEntry *pNew;
+
+ newSize = p->yystksz*2 + 100;
+ pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ if( pNew ){
+ p->yystack = pNew;
+ p->yystksz = newSize;
#ifndef NDEBUG
- if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
- return yyTokenName[tokenType];
- }else{
- return "Unknown";
- }
-#else
- return "";
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack grows to %d entries!\n",
+ yyTracePrompt, p->yystksz);
+ }
#endif
+ }
}
+#endif
/*
** This function allocates a new parser.
@@ -1217,6 +1240,9 @@ void *sqlite3ParserAlloc(void *(*mallocProc)(size_t)){
pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
if( pParser ){
pParser->yyidx = -1;
+#if YYSTACKDEPTH<=0
+ yyGrowStack(pParser);
+#endif
}
return pParser;
}
@@ -1238,81 +1264,73 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
** which appear on the RHS of the rule, but which are not used
** inside the C code.
*/
- case 156:
- case 190:
- case 207:
+ case 155:
+ case 189:
+ case 206:
#line 374 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3SelectDelete((yypminor->yy219));}
-#line 1248 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1274 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
+ case 169:
case 170:
- case 171:
- case 195:
- case 197:
- case 205:
- case 211:
- case 219:
- case 222:
- case 224:
- case 225:
- case 235:
-#line 631 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3ExprDelete((yypminor->yy172));}
-#line 1263 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 175:
- case 183:
- case 193:
+ case 194:
case 196:
- case 198:
- case 200:
+ case 204:
case 210:
- case 213:
- case 214:
case 217:
+ case 220:
+ case 222:
case 223:
-#line 865 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 235:
+#line 623 "ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3ExprDelete((yypminor->yy172));}
+#line 1289 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 174:
+ case 182:
+ case 192:
+ case 195:
+ case 197:
+ case 199:
+ case 209:
+ case 211:
+ case 212:
+ case 215:
+ case 221:
+#line 863 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3ExprListDelete((yypminor->yy174));}
-#line 1278 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1304 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 189:
- case 194:
+ case 188:
+ case 193:
+ case 201:
case 202:
- case 203:
-#line 502 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 487 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3SrcListDelete((yypminor->yy373));}
-#line 1286 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 199:
-#line 563 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- sqlite3ExprDelete((yypminor->yy234).pLimit);
- sqlite3ExprDelete((yypminor->yy234).pOffset);
-}
-#line 1294 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1312 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 206:
- case 209:
- case 216:
-#line 519 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 205:
+ case 208:
+ case 214:
+#line 504 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3IdListDelete((yypminor->yy432));}
-#line 1301 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1319 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 231:
case 236:
-#line 959 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 964 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3DeleteTriggerStep((yypminor->yy243));}
-#line 1307 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1325 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 233:
-#line 943 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 950 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3IdListDelete((yypminor->yy370).b);}
-#line 1312 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1330 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 238:
-#line 1027 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 1037 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3ExprDelete((yypminor->yy386));}
-#line 1317 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1335 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
default: break; /* If no destructor action specified: do nothing */
}
@@ -1363,6 +1381,9 @@ void sqlite3ParserFree(
yyParser *pParser = (yyParser*)p;
if( pParser==0 ) return;
while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+ free(pParser->yystack);
+#endif
(*freeProc)((void*)pParser);
}
@@ -1455,6 +1476,28 @@ static int yy_find_reduce_action(
}
/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){
+ sqlite3ParserARG_FETCH;
+ yypParser->yyidx--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+#line 44 "ext/pdo_sqlite/sqlite/src/parse.y"
+
+ sqlite3ErrorMsg(pParse, "parser stack overflow");
+ pParse->parseError = 1;
+#line 1499 "ext/pdo_sqlite/sqlite/src/parse.c"
+ sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
+}
+
+/*
** Perform a shift action.
*/
static void yy_shift(
@@ -1465,25 +1508,20 @@ static void yy_shift(
){
yyStackEntry *yytos;
yypParser->yyidx++;
+#if YYSTACKDEPTH>0
if( yypParser->yyidx>=YYSTACKDEPTH ){
- sqlite3ParserARG_FETCH;
- yypParser->yyidx--;
-#ifndef NDEBUG
- if( yyTraceFILE ){
- fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
- }
-#endif
- while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
- /* Here code is inserted which will execute if the parser
- ** stack every overflows */
-#line 44 "ext/pdo_sqlite/sqlite/src/parse.y"
-
- sqlite3ErrorMsg(pParse, "parser stack overflow");
- pParse->parseError = 1;
-#line 1486 "ext/pdo_sqlite/sqlite/src/parse.c"
- sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument var */
- return;
+ yyStackOverflow(yypParser, yypMinor);
+ return;
}
+#else
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyGrowStack(yypParser);
+ if( yypParser->yyidx>=yypParser->yystksz ){
+ yyStackOverflow(yypParser, yypMinor);
+ return;
+ }
+ }
+#endif
yytos = &yypParser->yystack[yypParser->yyidx];
yytos->stateno = yyNewState;
yytos->major = yyMajor;
@@ -1507,263 +1545,266 @@ 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[] = {
+ { 139, 1 },
+ { 140, 2 },
{ 140, 1 },
- { 141, 2 },
- { 141, 1 },
- { 143, 1 },
{ 142, 1 },
- { 142, 3 },
- { 145, 0 },
- { 145, 1 },
- { 145, 3 },
+ { 141, 1 },
+ { 141, 3 },
+ { 144, 0 },
+ { 144, 1 },
{ 144, 3 },
- { 147, 0 },
- { 147, 1 },
- { 147, 2 },
+ { 143, 3 },
{ 146, 0 },
{ 146, 1 },
- { 146, 1 },
- { 146, 1 },
- { 144, 2 },
- { 144, 2 },
- { 144, 2 },
- { 144, 2 },
- { 149, 6 },
- { 152, 0 },
- { 152, 3 },
- { 151, 1 },
+ { 146, 2 },
+ { 145, 0 },
+ { 145, 1 },
+ { 145, 1 },
+ { 145, 1 },
+ { 143, 2 },
+ { 143, 2 },
+ { 143, 2 },
+ { 143, 2 },
+ { 148, 6 },
{ 151, 0 },
- { 150, 4 },
- { 150, 2 },
- { 154, 3 },
- { 154, 1 },
- { 157, 3 },
- { 158, 1 },
+ { 151, 3 },
+ { 150, 1 },
+ { 150, 0 },
+ { 149, 4 },
+ { 149, 2 },
+ { 153, 3 },
+ { 153, 1 },
+ { 156, 3 },
+ { 157, 1 },
+ { 160, 1 },
{ 161, 1 },
+ { 147, 1 },
+ { 147, 1 },
+ { 147, 1 },
+ { 158, 0 },
+ { 158, 1 },
{ 162, 1 },
- { 148, 1 },
- { 148, 1 },
- { 148, 1 },
- { 159, 0 },
- { 159, 1 },
+ { 162, 4 },
+ { 162, 6 },
{ 163, 1 },
- { 163, 4 },
- { 163, 6 },
+ { 163, 2 },
{ 164, 1 },
- { 164, 2 },
- { 165, 1 },
- { 165, 1 },
- { 160, 2 },
- { 160, 0 },
- { 168, 3 },
- { 168, 1 },
+ { 164, 1 },
+ { 159, 2 },
+ { 159, 0 },
+ { 167, 3 },
+ { 167, 1 },
{ 168, 2 },
{ 168, 4 },
{ 168, 3 },
{ 168, 3 },
{ 168, 2 },
- { 169, 2 },
- { 169, 3 },
- { 169, 5 },
- { 169, 2 },
- { 169, 4 },
- { 169, 4 },
- { 169, 1 },
- { 169, 2 },
- { 174, 0 },
- { 174, 1 },
- { 176, 0 },
- { 176, 2 },
+ { 168, 2 },
+ { 168, 3 },
+ { 168, 5 },
+ { 168, 2 },
+ { 168, 4 },
+ { 168, 4 },
+ { 168, 1 },
+ { 168, 2 },
+ { 173, 0 },
+ { 173, 1 },
+ { 175, 0 },
+ { 175, 2 },
+ { 177, 2 },
+ { 177, 3 },
+ { 177, 3 },
+ { 177, 3 },
{ 178, 2 },
- { 178, 3 },
- { 178, 3 },
- { 178, 3 },
+ { 178, 2 },
+ { 178, 1 },
+ { 178, 1 },
+ { 176, 3 },
+ { 176, 2 },
+ { 179, 0 },
{ 179, 2 },
{ 179, 2 },
- { 179, 1 },
- { 179, 1 },
- { 177, 3 },
- { 177, 2 },
- { 180, 0 },
+ { 154, 0 },
+ { 154, 2 },
+ { 180, 3 },
{ 180, 2 },
- { 180, 2 },
- { 155, 0 },
- { 155, 2 },
- { 181, 3 },
+ { 180, 1 },
{ 181, 2 },
- { 181, 1 },
- { 182, 2 },
- { 182, 7 },
- { 182, 5 },
- { 182, 5 },
- { 182, 10 },
+ { 181, 7 },
+ { 181, 5 },
+ { 181, 5 },
+ { 181, 10 },
+ { 183, 0 },
+ { 183, 1 },
+ { 171, 0 },
+ { 171, 3 },
{ 184, 0 },
- { 184, 1 },
- { 172, 0 },
- { 172, 3 },
- { 185, 0 },
- { 185, 2 },
- { 186, 1 },
- { 186, 1 },
- { 186, 1 },
- { 144, 4 },
- { 188, 2 },
- { 188, 0 },
- { 144, 7 },
- { 144, 4 },
- { 144, 1 },
- { 156, 1 },
- { 156, 3 },
+ { 184, 2 },
+ { 185, 1 },
+ { 185, 1 },
+ { 185, 1 },
+ { 143, 4 },
+ { 187, 2 },
+ { 187, 0 },
+ { 143, 8 },
+ { 143, 4 },
+ { 143, 1 },
+ { 155, 1 },
+ { 155, 3 },
+ { 190, 1 },
+ { 190, 2 },
+ { 190, 1 },
+ { 189, 9 },
{ 191, 1 },
- { 191, 2 },
{ 191, 1 },
- { 190, 9 },
- { 192, 1 },
- { 192, 1 },
- { 192, 0 },
+ { 191, 0 },
+ { 199, 2 },
+ { 199, 0 },
+ { 192, 3 },
+ { 192, 2 },
+ { 192, 4 },
{ 200, 2 },
+ { 200, 1 },
{ 200, 0 },
- { 193, 3 },
+ { 193, 0 },
{ 193, 2 },
- { 193, 4 },
- { 201, 2 },
- { 201, 1 },
- { 201, 0 },
- { 194, 0 },
- { 194, 2 },
+ { 202, 2 },
+ { 202, 0 },
+ { 201, 6 },
+ { 201, 7 },
+ { 206, 1 },
+ { 206, 1 },
+ { 152, 0 },
+ { 152, 2 },
+ { 188, 2 },
+ { 203, 1 },
{ 203, 2 },
- { 203, 0 },
- { 202, 6 },
- { 202, 7 },
- { 207, 1 },
- { 207, 1 },
- { 153, 0 },
- { 153, 2 },
- { 189, 2 },
- { 204, 1 },
+ { 203, 3 },
+ { 203, 4 },
{ 204, 2 },
- { 204, 3 },
- { 204, 4 },
- { 205, 2 },
+ { 204, 0 },
+ { 205, 4 },
{ 205, 0 },
- { 206, 4 },
- { 206, 0 },
- { 198, 0 },
- { 198, 3 },
- { 210, 5 },
- { 210, 3 },
- { 211, 1 },
- { 173, 1 },
- { 173, 1 },
- { 173, 0 },
- { 212, 0 },
- { 212, 2 },
- { 196, 0 },
- { 196, 3 },
{ 197, 0 },
- { 197, 2 },
- { 199, 0 },
- { 199, 2 },
- { 199, 4 },
- { 199, 4 },
- { 144, 4 },
+ { 197, 3 },
+ { 209, 4 },
+ { 209, 2 },
+ { 210, 1 },
+ { 172, 1 },
+ { 172, 1 },
+ { 172, 0 },
{ 195, 0 },
- { 195, 2 },
- { 144, 6 },
- { 214, 5 },
- { 214, 3 },
- { 144, 8 },
- { 144, 5 },
- { 215, 2 },
+ { 195, 3 },
+ { 196, 0 },
+ { 196, 2 },
+ { 198, 0 },
+ { 198, 2 },
+ { 198, 4 },
+ { 198, 4 },
+ { 143, 4 },
+ { 194, 0 },
+ { 194, 2 },
+ { 143, 6 },
+ { 212, 5 },
+ { 212, 3 },
+ { 143, 8 },
+ { 143, 5 },
+ { 143, 6 },
+ { 213, 2 },
+ { 213, 1 },
+ { 215, 3 },
{ 215, 1 },
- { 217, 3 },
- { 217, 1 },
- { 216, 0 },
- { 216, 3 },
- { 209, 3 },
- { 209, 1 },
- { 171, 1 },
- { 171, 3 },
+ { 214, 0 },
+ { 214, 3 },
+ { 208, 3 },
+ { 208, 1 },
{ 170, 1 },
- { 171, 1 },
- { 171, 1 },
- { 171, 3 },
- { 171, 5 },
+ { 170, 3 },
+ { 169, 1 },
{ 170, 1 },
{ 170, 1 },
- { 171, 1 },
- { 171, 1 },
- { 171, 6 },
- { 171, 5 },
- { 171, 4 },
+ { 170, 3 },
+ { 170, 5 },
+ { 169, 1 },
+ { 169, 1 },
{ 170, 1 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 171, 3 },
- { 218, 1 },
- { 218, 2 },
+ { 170, 1 },
+ { 170, 3 },
+ { 170, 6 },
+ { 170, 5 },
+ { 170, 4 },
+ { 169, 1 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 3 },
+ { 216, 1 },
+ { 216, 2 },
+ { 216, 1 },
+ { 216, 2 },
+ { 217, 2 },
+ { 217, 0 },
+ { 170, 4 },
+ { 170, 2 },
+ { 170, 3 },
+ { 170, 3 },
+ { 170, 4 },
+ { 170, 2 },
+ { 170, 2 },
+ { 170, 2 },
{ 218, 1 },
{ 218, 2 },
+ { 170, 5 },
+ { 219, 1 },
{ 219, 2 },
- { 219, 0 },
- { 171, 4 },
- { 171, 2 },
- { 171, 3 },
- { 171, 3 },
- { 171, 4 },
- { 171, 2 },
- { 171, 2 },
- { 171, 2 },
+ { 170, 5 },
+ { 170, 3 },
+ { 170, 5 },
+ { 170, 4 },
+ { 170, 4 },
+ { 170, 5 },
+ { 221, 5 },
+ { 221, 4 },
+ { 222, 2 },
+ { 222, 0 },
{ 220, 1 },
- { 220, 2 },
- { 171, 5 },
- { 221, 1 },
- { 221, 2 },
- { 171, 5 },
- { 171, 3 },
- { 171, 5 },
- { 171, 4 },
- { 171, 4 },
- { 171, 5 },
- { 223, 5 },
- { 223, 4 },
- { 224, 2 },
+ { 220, 0 },
+ { 211, 3 },
+ { 211, 1 },
+ { 223, 1 },
+ { 223, 0 },
+ { 143, 11 },
+ { 224, 1 },
{ 224, 0 },
- { 222, 1 },
- { 222, 0 },
- { 213, 3 },
- { 213, 1 },
+ { 174, 0 },
+ { 174, 3 },
+ { 182, 5 },
+ { 182, 3 },
{ 225, 1 },
- { 225, 0 },
- { 144, 11 },
- { 226, 1 },
{ 226, 0 },
- { 175, 0 },
- { 175, 3 },
- { 183, 5 },
- { 183, 3 },
+ { 226, 2 },
+ { 143, 4 },
+ { 143, 1 },
+ { 143, 2 },
+ { 143, 5 },
+ { 143, 5 },
+ { 143, 5 },
+ { 143, 6 },
+ { 143, 3 },
{ 227, 1 },
- { 144, 4 },
- { 144, 1 },
- { 144, 2 },
- { 144, 5 },
- { 144, 5 },
- { 144, 5 },
- { 144, 5 },
- { 144, 6 },
- { 144, 3 },
+ { 227, 1 },
+ { 165, 2 },
{ 166, 2 },
- { 167, 2 },
{ 229, 1 },
{ 228, 1 },
{ 228, 0 },
- { 144, 5 },
- { 230, 10 },
+ { 143, 5 },
+ { 230, 11 },
{ 232, 1 },
{ 232, 1 },
{ 232, 2 },
@@ -1773,7 +1814,6 @@ static const struct {
{ 233, 3 },
{ 234, 0 },
{ 234, 3 },
- { 234, 3 },
{ 235, 0 },
{ 235, 2 },
{ 231, 3 },
@@ -1783,29 +1823,29 @@ static const struct {
{ 236, 5 },
{ 236, 4 },
{ 236, 1 },
- { 171, 4 },
- { 171, 6 },
- { 187, 1 },
- { 187, 1 },
- { 187, 1 },
- { 144, 3 },
- { 144, 6 },
+ { 170, 4 },
+ { 170, 6 },
+ { 186, 1 },
+ { 186, 1 },
+ { 186, 1 },
+ { 143, 4 },
+ { 143, 6 },
+ { 143, 3 },
{ 238, 0 },
{ 238, 2 },
{ 237, 1 },
{ 237, 0 },
- { 144, 3 },
- { 144, 1 },
- { 144, 3 },
- { 144, 1 },
- { 144, 3 },
- { 144, 6 },
- { 144, 6 },
+ { 143, 1 },
+ { 143, 3 },
+ { 143, 1 },
+ { 143, 3 },
+ { 143, 6 },
+ { 143, 6 },
{ 239, 1 },
{ 240, 0 },
{ 240, 1 },
- { 144, 1 },
- { 144, 4 },
+ { 143, 1 },
+ { 143, 4 },
{ 241, 7 },
{ 242, 1 },
{ 242, 3 },
@@ -1843,7 +1883,6 @@ static void yy_reduce(
}
#endif /* NDEBUG */
-#ifndef NDEBUG
/* Silence complaints from purify about yygotominor being uninitialized
** in some cases when it is copied into the stack after the following
** switch. yygotominor is uninitialized when a rule reduces that does
@@ -1851,9 +1890,15 @@ static void yy_reduce(
** value of the nonterminal uninitialized is utterly harmless as long
** as the value is never used. So really the only thing this code
** accomplishes is to quieten purify.
+ **
+ ** 2007-01-16: The wireshark project (www.wireshark.org) reports that
+ ** without this code, their parser segfaults. I'm not sure what there
+ ** parser is doing to make this happen. This is the second bug report
+ ** from wireshark this week. Clearly they are stressing Lemon in ways
+ ** that it has not been previously stressed... (SQLite ticket #2172)
*/
memset(&yygotominor, 0, sizeof(yygotominor));
-#endif
+
switch( yyruleno ){
/* Beginning here are the reduction cases. A typical example
@@ -1864,35 +1909,75 @@ static void yy_reduce(
** #line <lineno> <thisfile>
** break;
*/
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ case 5:
+ case 10:
+ case 11:
+ case 12:
+ case 20:
+ case 28:
+ case 29:
+ case 37:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ case 55:
+ case 82:
+ case 83:
+ case 84:
+ case 85:
+ case 256:
+ case 257:
+ case 267:
+ case 268:
+ case 288:
+ case 289:
+ case 297:
+ case 298:
+ case 302:
+ case 303:
+ case 305:
+ case 309:
+#line 97 "ext/pdo_sqlite/sqlite/src/parse.y"
+{
+}
+#line 1953 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
case 3:
#line 100 "ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3FinishCoding(pParse); }
-#line 1873 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1958 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 6:
#line 103 "ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3BeginParse(pParse, 0); }
-#line 1878 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1963 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 7:
#line 105 "ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3BeginParse(pParse, 1); }
-#line 1883 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1968 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 8:
#line 106 "ext/pdo_sqlite/sqlite/src/parse.y"
{ sqlite3BeginParse(pParse, 2); }
-#line 1888 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1973 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 9:
#line 112 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3BeginTransaction(pParse, yymsp[-1].minor.yy46);}
-#line 1893 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1978 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 13:
#line 117 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = TK_DEFERRED;}
-#line 1898 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1983 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 14:
case 15:
@@ -1901,25 +1986,25 @@ static void yy_reduce(
case 109:
#line 118 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = yymsp[0].major;}
-#line 1907 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1992 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 17:
case 18:
#line 121 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3CommitTransaction(pParse);}
-#line 1913 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 1998 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 19:
#line 123 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3RollbackTransaction(pParse);}
-#line 1918 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2003 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 21:
#line 128 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3StartTable(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410,yymsp[-4].minor.yy46,0,0,yymsp[-2].minor.yy46);
}
-#line 1925 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2010 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 22:
case 25:
@@ -1934,7 +2019,7 @@ static void yy_reduce(
case 215:
#line 132 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = 0;}
-#line 1940 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2025 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 23:
case 24:
@@ -1946,14 +2031,14 @@ static void yy_reduce(
case 216:
#line 133 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = 1;}
-#line 1952 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2037 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 26:
#line 139 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3EndTable(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy0,0);
}
-#line 1959 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2044 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 27:
#line 142 "ext/pdo_sqlite/sqlite/src/parse.y"
@@ -1961,7 +2046,7 @@ static void yy_reduce(
sqlite3EndTable(pParse,0,0,yymsp[0].minor.yy219);
sqlite3SelectDelete(yymsp[0].minor.yy219);
}
-#line 1967 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2052 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 30:
#line 154 "ext/pdo_sqlite/sqlite/src/parse.y"
@@ -1969,7 +2054,7 @@ static void yy_reduce(
yygotominor.yy410.z = yymsp[-2].minor.yy410.z;
yygotominor.yy410.n = (pParse->sLastToken.z-yymsp[-2].minor.yy410.z) + pParse->sLastToken.n;
}
-#line 1975 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2060 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 31:
#line 158 "ext/pdo_sqlite/sqlite/src/parse.y"
@@ -1977,77 +2062,69 @@ static void yy_reduce(
sqlite3AddColumn(pParse,&yymsp[0].minor.yy410);
yygotominor.yy410 = yymsp[0].minor.yy410;
}
-#line 1983 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2068 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 32:
case 33:
case 34:
case 35:
case 36:
- case 252:
+ case 255:
#line 168 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410 = yymsp[0].minor.yy0;}
-#line 1993 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2078 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 38:
-#line 228 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 229 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddColumnType(pParse,&yymsp[0].minor.yy410);}
-#line 1998 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2083 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 39:
case 42:
case 119:
case 120:
case 131:
- case 150:
case 240:
- case 250:
+ case 242:
case 251:
-#line 229 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 252:
+ case 253:
+ case 254:
+#line 230 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410 = yymsp[0].minor.yy410;}
-#line 2011 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2098 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 40:
-#line 230 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 231 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy410.z = yymsp[-3].minor.yy410.z;
yygotominor.yy410.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-3].minor.yy410.z;
}
-#line 2019 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2106 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 41:
-#line 234 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 235 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy410.z = yymsp[-5].minor.yy410.z;
yygotominor.yy410.n = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n] - yymsp[-5].minor.yy410.z;
}
-#line 2027 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2114 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 43:
-#line 240 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 241 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410.z=yymsp[-1].minor.yy410.z; yygotominor.yy410.n=yymsp[0].minor.yy410.n+(yymsp[0].minor.yy410.z-yymsp[-1].minor.yy410.z);}
-#line 2032 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 44:
-#line 242 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy46 = atoi((char*)yymsp[0].minor.yy410.z); }
-#line 2037 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 45:
-#line 243 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy46 = -atoi((char*)yymsp[0].minor.yy410.z); }
-#line 2042 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2119 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 50:
case 52:
#line 252 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddDefaultValue(pParse,yymsp[0].minor.yy172);}
-#line 2048 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2125 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 51:
#line 253 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddDefaultValue(pParse,yymsp[-1].minor.yy172);}
-#line 2053 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2130 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 53:
#line 255 "ext/pdo_sqlite/sqlite/src/parse.y"
@@ -2055,7 +2132,7 @@ static void yy_reduce(
Expr *p = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy172, 0, 0);
sqlite3AddDefaultValue(pParse,p);
}
-#line 2061 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2138 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 54:
#line 259 "ext/pdo_sqlite/sqlite/src/parse.y"
@@ -2063,92 +2140,92 @@ static void yy_reduce(
Expr *p = sqlite3Expr(TK_STRING, 0, 0, &yymsp[0].minor.yy410);
sqlite3AddDefaultValue(pParse,p);
}
-#line 2069 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2146 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 56:
#line 268 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddNotNull(pParse, yymsp[0].minor.yy46);}
-#line 2074 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2151 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 57:
#line 270 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddPrimaryKey(pParse,0,yymsp[-1].minor.yy46,yymsp[0].minor.yy46,yymsp[-2].minor.yy46);}
-#line 2079 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2156 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 58:
#line 271 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3CreateIndex(pParse,0,0,0,0,yymsp[0].minor.yy46,0,0,0,0);}
-#line 2084 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2161 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 59:
#line 272 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddCheckConstraint(pParse,yymsp[-1].minor.yy172);}
-#line 2089 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2166 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 60:
#line 274 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3CreateForeignKey(pParse,0,&yymsp[-2].minor.yy410,yymsp[-1].minor.yy174,yymsp[0].minor.yy46);}
-#line 2094 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2171 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 61:
#line 275 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3DeferForeignKey(pParse,yymsp[0].minor.yy46);}
-#line 2099 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2176 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 62:
#line 276 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddCollateType(pParse, (char*)yymsp[0].minor.yy410.z, yymsp[0].minor.yy410.n);}
-#line 2104 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2181 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 65:
#line 289 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = OE_Restrict * 0x010101; }
-#line 2109 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2186 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 66:
#line 290 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = (yymsp[-1].minor.yy46 & yymsp[0].minor.yy405.mask) | yymsp[0].minor.yy405.value; }
-#line 2114 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2191 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 67:
#line 292 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy405.value = 0; yygotominor.yy405.mask = 0x000000; }
-#line 2119 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2196 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 68:
#line 293 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy405.value = yymsp[0].minor.yy46; yygotominor.yy405.mask = 0x0000ff; }
-#line 2124 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2201 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 69:
#line 294 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy405.value = yymsp[0].minor.yy46<<8; yygotominor.yy405.mask = 0x00ff00; }
-#line 2129 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2206 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 70:
#line 295 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy405.value = yymsp[0].minor.yy46<<16; yygotominor.yy405.mask = 0xff0000; }
-#line 2134 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2211 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 71:
#line 297 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = OE_SetNull; }
-#line 2139 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2216 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 72:
#line 298 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = OE_SetDflt; }
-#line 2144 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2221 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 73:
#line 299 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = OE_Cascade; }
-#line 2149 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2226 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 74:
#line 300 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = OE_Restrict; }
-#line 2154 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2231 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 75:
case 76:
@@ -2156,35 +2233,35 @@ static void yy_reduce(
case 93:
case 95:
case 96:
- case 167:
+ case 166:
#line 302 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = yymsp[0].minor.yy46;}
-#line 2165 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2242 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 80:
#line 312 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410.n = 0; yygotominor.yy410.z = 0;}
-#line 2170 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2247 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 81:
#line 313 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410 = yymsp[-1].minor.yy0;}
-#line 2175 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2252 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 86:
#line 319 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddPrimaryKey(pParse,yymsp[-3].minor.yy174,yymsp[0].minor.yy46,yymsp[-2].minor.yy46,0);}
-#line 2180 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2257 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 87:
#line 321 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3CreateIndex(pParse,0,0,0,yymsp[-2].minor.yy174,yymsp[0].minor.yy46,0,0,0,0);}
-#line 2185 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2262 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 88:
#line 322 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3AddCheckConstraint(pParse,yymsp[-2].minor.yy172);}
-#line 2190 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2267 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 89:
#line 324 "ext/pdo_sqlite/sqlite/src/parse.y"
@@ -2192,45 +2269,45 @@ static void yy_reduce(
sqlite3CreateForeignKey(pParse, yymsp[-6].minor.yy174, &yymsp[-3].minor.yy410, yymsp[-2].minor.yy174, yymsp[-1].minor.yy46);
sqlite3DeferForeignKey(pParse, yymsp[0].minor.yy46);
}
-#line 2198 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2275 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 92:
case 94:
#line 338 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Default;}
-#line 2204 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2281 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 97:
#line 343 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Ignore;}
-#line 2209 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2286 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 98:
- case 168:
+ case 167:
#line 344 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Replace;}
-#line 2215 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2292 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 99:
#line 348 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3DropTable(pParse, yymsp[0].minor.yy373, 0, yymsp[-1].minor.yy46);
}
-#line 2222 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2299 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 102:
#line 358 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, yymsp[0].minor.yy219, yymsp[-5].minor.yy46);
+ sqlite3CreateView(pParse, &yymsp[-7].minor.yy0, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, yymsp[0].minor.yy219, yymsp[-6].minor.yy46, yymsp[-4].minor.yy46);
}
-#line 2229 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2306 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 103:
#line 361 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3DropTable(pParse, yymsp[0].minor.yy373, 1, yymsp[-1].minor.yy46);
}
-#line 2236 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2313 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 104:
#line 368 "ext/pdo_sqlite/sqlite/src/parse.y"
@@ -2238,13 +2315,13 @@ static void yy_reduce(
sqlite3Select(pParse, yymsp[0].minor.yy219, SRT_Callback, 0, 0, 0, 0, 0);
sqlite3SelectDelete(yymsp[0].minor.yy219);
}
-#line 2244 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2321 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 105:
case 128:
#line 378 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy219 = yymsp[0].minor.yy219;}
-#line 2250 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2327 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 106:
#line 380 "ext/pdo_sqlite/sqlite/src/parse.y"
@@ -2255,47 +2332,47 @@ static void yy_reduce(
}
yygotominor.yy219 = yymsp[0].minor.yy219;
}
-#line 2261 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2338 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 108:
#line 389 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = TK_ALL;}
-#line 2266 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2343 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 110:
#line 393 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy219 = sqlite3SelectNew(yymsp[-6].minor.yy174,yymsp[-5].minor.yy373,yymsp[-4].minor.yy172,yymsp[-3].minor.yy174,yymsp[-2].minor.yy172,yymsp[-1].minor.yy174,yymsp[-7].minor.yy46,yymsp[0].minor.yy234.pLimit,yymsp[0].minor.yy234.pOffset);
}
-#line 2273 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2350 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 114:
case 237:
#line 414 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy174 = yymsp[-1].minor.yy174;}
-#line 2279 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2356 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 115:
case 141:
- case 151:
+ case 149:
case 236:
#line 415 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy174 = 0;}
-#line 2287 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2364 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 116:
#line 416 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-2].minor.yy174,yymsp[-1].minor.yy172,yymsp[0].minor.yy410.n?&yymsp[0].minor.yy410:0);
}
-#line 2294 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2371 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 117:
#line 419 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-1].minor.yy174, sqlite3Expr(TK_ALL, 0, 0, 0), 0);
}
-#line 2301 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2378 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 118:
#line 422 "ext/pdo_sqlite/sqlite/src/parse.y"
@@ -2304,281 +2381,266 @@ static void yy_reduce(
Expr *pLeft = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy410);
yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-3].minor.yy174, sqlite3Expr(TK_DOT, pLeft, pRight, 0), 0);
}
-#line 2310 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2387 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 121:
#line 434 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410.n = 0;}
-#line 2315 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2392 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 122:
#line 446 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy373 = sqliteMalloc(sizeof(*yygotominor.yy373));}
-#line 2320 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2397 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 123:
#line 447 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy373 = yymsp[0].minor.yy373;}
-#line 2325 "ext/pdo_sqlite/sqlite/src/parse.c"
+{
+ yygotominor.yy373 = yymsp[0].minor.yy373;
+ sqlite3SrcListShiftJoinType(yygotominor.yy373);
+}
+#line 2405 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 124:
-#line 452 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 455 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy373 = yymsp[-1].minor.yy373;
if( yygotominor.yy373 && yygotominor.yy373->nSrc>0 ) yygotominor.yy373->a[yygotominor.yy373->nSrc-1].jointype = yymsp[0].minor.yy46;
}
-#line 2333 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2413 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 125:
-#line 456 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 459 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy373 = 0;}
-#line 2338 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2418 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 126:
-#line 457 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 460 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy373 = sqlite3SrcListAppend(yymsp[-5].minor.yy373,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410);
- if( yymsp[-2].minor.yy410.n ) sqlite3SrcListAddAlias(yygotominor.yy373,&yymsp[-2].minor.yy410);
- if( yymsp[-1].minor.yy172 ){
- if( yygotominor.yy373 && yygotominor.yy373->nSrc>1 ){ yygotominor.yy373->a[yygotominor.yy373->nSrc-2].pOn = yymsp[-1].minor.yy172; }
- else { sqlite3ExprDelete(yymsp[-1].minor.yy172); }
- }
- if( yymsp[0].minor.yy432 ){
- if( yygotominor.yy373 && yygotominor.yy373->nSrc>1 ){ yygotominor.yy373->a[yygotominor.yy373->nSrc-2].pUsing = yymsp[0].minor.yy432; }
- else { sqlite3IdListDelete(yymsp[0].minor.yy432); }
- }
+ yygotominor.yy373 = sqlite3SrcListAppendFromTerm(yymsp[-5].minor.yy373,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,0,yymsp[-1].minor.yy172,yymsp[0].minor.yy432);
}
-#line 2354 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2425 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 127:
-#line 471 "ext/pdo_sqlite/sqlite/src/parse.y"
-{
- yygotominor.yy373 = sqlite3SrcListAppend(yymsp[-6].minor.yy373,0,0);
- if( yygotominor.yy373 && yygotominor.yy373->nSrc>0 ) yygotominor.yy373->a[yygotominor.yy373->nSrc-1].pSelect = yymsp[-4].minor.yy219;
- if( yymsp[-2].minor.yy410.n ) sqlite3SrcListAddAlias(yygotominor.yy373,&yymsp[-2].minor.yy410);
- if( yymsp[-1].minor.yy172 ){
- if( yygotominor.yy373 && yygotominor.yy373->nSrc>1 ){ yygotominor.yy373->a[yygotominor.yy373->nSrc-2].pOn = yymsp[-1].minor.yy172; }
- else { sqlite3ExprDelete(yymsp[-1].minor.yy172); }
- }
- if( yymsp[0].minor.yy432 ){
- if( yygotominor.yy373 && yygotominor.yy373->nSrc>1 ){ yygotominor.yy373->a[yygotominor.yy373->nSrc-2].pUsing = yymsp[0].minor.yy432; }
- else { sqlite3IdListDelete(yymsp[0].minor.yy432); }
- }
+#line 465 "ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ yygotominor.yy373 = sqlite3SrcListAppendFromTerm(yymsp[-6].minor.yy373,0,0,&yymsp[-2].minor.yy410,yymsp[-4].minor.yy219,yymsp[-1].minor.yy172,yymsp[0].minor.yy432);
}
-#line 2371 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2432 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 129:
-#line 492 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 476 "ext/pdo_sqlite/sqlite/src/parse.y"
{
+ sqlite3SrcListShiftJoinType(yymsp[0].minor.yy373);
yygotominor.yy219 = sqlite3SelectNew(0,yymsp[0].minor.yy373,0,0,0,0,0,0,0);
}
-#line 2378 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2440 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 130:
-#line 498 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 483 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy410.z=0; yygotominor.yy410.n=0;}
-#line 2383 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2445 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 132:
-#line 503 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 488 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy373 = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410);}
-#line 2388 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2450 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 133:
-#line 507 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 492 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = JT_INNER; }
-#line 2393 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2455 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 134:
-#line 508 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 493 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0); }
-#line 2398 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2460 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 135:
-#line 509 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 494 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy410,0); }
-#line 2403 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2465 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 136:
-#line 511 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 496 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy410,&yymsp[-1].minor.yy410); }
-#line 2408 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2470 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 137:
case 145:
- case 154:
- case 161:
- case 175:
+ case 152:
+ case 159:
+ case 174:
case 202:
case 225:
case 227:
case 231:
-#line 515 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 500 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy172 = yymsp[0].minor.yy172;}
-#line 2421 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2483 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 138:
- case 153:
- case 160:
+ case 151:
+ case 158:
case 203:
case 226:
case 228:
case 232:
-#line 516 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 501 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy172 = 0;}
-#line 2432 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2494 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 139:
- case 172:
-#line 520 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 171:
+#line 505 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy432 = yymsp[-1].minor.yy432;}
-#line 2438 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2500 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 140:
- case 171:
-#line 521 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 170:
+#line 506 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy432 = 0;}
-#line 2444 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2506 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 142:
- case 152:
-#line 532 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 150:
+#line 517 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy174 = yymsp[0].minor.yy174;}
-#line 2450 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2512 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 143:
-#line 533 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 518 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174,yymsp[-2].minor.yy172,yymsp[-1].minor.yy410.n>0?&yymsp[-1].minor.yy410:0);
+ yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-3].minor.yy174,yymsp[-1].minor.yy172,0);
if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46;
}
-#line 2458 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2520 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 144:
-#line 537 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 522 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[-2].minor.yy172,yymsp[-1].minor.yy410.n>0?&yymsp[-1].minor.yy410:0);
+ yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[-1].minor.yy172,0);
if( yygotominor.yy174 && yygotominor.yy174->a ) yygotominor.yy174->a[0].sortOrder = yymsp[0].minor.yy46;
}
-#line 2466 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2528 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 146:
case 148:
-#line 546 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 530 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = SQLITE_SO_ASC;}
-#line 2472 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2534 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 147:
-#line 547 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 531 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = SQLITE_SO_DESC;}
-#line 2477 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 149:
-#line 549 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy410.z = 0; yygotominor.yy410.n = 0;}
-#line 2482 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2539 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 155:
-#line 567 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 153:
+#line 557 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy234.pLimit = 0; yygotominor.yy234.pOffset = 0;}
-#line 2487 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2544 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 156:
-#line 568 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 154:
+#line 558 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy234.pLimit = yymsp[0].minor.yy172; yygotominor.yy234.pOffset = 0;}
-#line 2492 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2549 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 157:
-#line 570 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 155:
+#line 560 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy234.pLimit = yymsp[-2].minor.yy172; yygotominor.yy234.pOffset = yymsp[0].minor.yy172;}
-#line 2497 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2554 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 158:
-#line 572 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 156:
+#line 562 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy234.pOffset = yymsp[-2].minor.yy172; yygotominor.yy234.pLimit = yymsp[0].minor.yy172;}
-#line 2502 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2559 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 159:
-#line 576 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 157:
+#line 566 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3DeleteFrom(pParse,yymsp[-1].minor.yy373,yymsp[0].minor.yy172);}
-#line 2507 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2564 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 162:
-#line 587 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 160:
+#line 577 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Update(pParse,yymsp[-3].minor.yy373,yymsp[-1].minor.yy174,yymsp[0].minor.yy172,yymsp[-4].minor.yy46);}
-#line 2512 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2569 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 163:
-#line 593 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 161:
+#line 583 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);}
-#line 2517 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2574 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 164:
-#line 594 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 162:
+#line 584 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[0].minor.yy172,&yymsp[-2].minor.yy410);}
-#line 2522 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2579 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 165:
-#line 600 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 163:
+#line 590 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Insert(pParse, yymsp[-5].minor.yy373, yymsp[-1].minor.yy174, 0, yymsp[-4].minor.yy432, yymsp[-7].minor.yy46);}
-#line 2527 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2584 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 166:
-#line 602 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 164:
+#line 592 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Insert(pParse, yymsp[-2].minor.yy373, 0, yymsp[0].minor.yy219, yymsp[-1].minor.yy432, yymsp[-4].minor.yy46);}
-#line 2532 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2589 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 169:
+ case 165:
+#line 594 "ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Insert(pParse, yymsp[-3].minor.yy373, 0, 0, yymsp[-2].minor.yy432, yymsp[-5].minor.yy46);}
+#line 2594 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 168:
case 229:
-#line 612 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 604 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-2].minor.yy174,yymsp[0].minor.yy172,0);}
-#line 2538 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2600 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 170:
+ case 169:
case 230:
-#line 613 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 605 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy174 = sqlite3ExprListAppend(0,yymsp[0].minor.yy172,0);}
-#line 2544 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2606 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 173:
-#line 622 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 172:
+#line 614 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy432 = sqlite3IdListAppend(yymsp[-2].minor.yy432,&yymsp[0].minor.yy410);}
-#line 2549 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2611 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 174:
-#line 623 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 173:
+#line 615 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy432 = sqlite3IdListAppend(0,&yymsp[0].minor.yy410);}
-#line 2554 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2616 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 176:
-#line 634 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 175:
+#line 626 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy172 = yymsp[-1].minor.yy172; sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); }
-#line 2559 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2621 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 177:
+ case 176:
+ case 181:
case 182:
- case 183:
-#line 635 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 627 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy172 = sqlite3Expr(yymsp[0].major, 0, 0, &yymsp[0].minor.yy0);}
-#line 2566 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2628 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
+ case 177:
case 178:
- case 179:
-#line 636 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 628 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy172 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy0);}
-#line 2572 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2634 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 180:
-#line 638 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 179:
+#line 630 "ext/pdo_sqlite/sqlite/src/parse.y"
{
Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy410);
Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[0].minor.yy410);
yygotominor.yy172 = sqlite3Expr(TK_DOT, temp1, temp2, 0);
}
-#line 2581 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2643 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 181:
-#line 643 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 180:
+#line 635 "ext/pdo_sqlite/sqlite/src/parse.y"
{
Expr *temp1 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-4].minor.yy410);
Expr *temp2 = sqlite3Expr(TK_ID, 0, 0, &yymsp[-2].minor.yy410);
@@ -2586,32 +2648,39 @@ static void yy_reduce(
Expr *temp4 = sqlite3Expr(TK_DOT, temp2, temp3, 0);
yygotominor.yy172 = sqlite3Expr(TK_DOT, temp1, temp4, 0);
}
-#line 2592 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2654 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 184:
-#line 652 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 183:
+#line 644 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy172 = sqlite3RegisterExpr(pParse, &yymsp[0].minor.yy0);}
-#line 2597 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2659 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 185:
-#line 653 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 184:
+#line 645 "ext/pdo_sqlite/sqlite/src/parse.y"
{
Token *pToken = &yymsp[0].minor.yy0;
Expr *pExpr = yygotominor.yy172 = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
sqlite3ExprAssignVarNumber(pParse, pExpr);
}
-#line 2606 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2668 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 185:
+#line 650 "ext/pdo_sqlite/sqlite/src/parse.y"
+{
+ yygotominor.yy172 = sqlite3ExprSetColl(pParse, yymsp[-2].minor.yy172, &yymsp[0].minor.yy410);
+}
+#line 2675 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 186:
-#line 659 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 654 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_CAST, yymsp[-3].minor.yy172, 0, &yymsp[-1].minor.yy410);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);
}
-#line 2614 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2683 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 187:
-#line 664 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 659 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3ExprFunction(yymsp[-1].minor.yy174, &yymsp[-4].minor.yy0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);
@@ -2619,25 +2688,28 @@ static void yy_reduce(
yygotominor.yy172->flags |= EP_Distinct;
}
}
-#line 2625 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2694 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 188:
-#line 671 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 666 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3ExprFunction(0, &yymsp[-3].minor.yy0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
}
-#line 2633 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2702 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 189:
-#line 675 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 670 "ext/pdo_sqlite/sqlite/src/parse.y"
{
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
** treated as functions that return constants */
yygotominor.yy172 = sqlite3ExprFunction(0,&yymsp[0].minor.yy0);
- if( yygotominor.yy172 ) yygotominor.yy172->op = TK_CONST_FUNC;
+ if( yygotominor.yy172 ){
+ yygotominor.yy172->op = TK_CONST_FUNC;
+ yygotominor.yy172->span = yymsp[0].minor.yy0;
+ }
}
-#line 2643 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2715 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 190:
case 191:
@@ -2647,24 +2719,24 @@ static void yy_reduce(
case 195:
case 196:
case 197:
-#line 681 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 679 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy172 = sqlite3Expr(yymsp[-1].major, yymsp[-2].minor.yy172, yymsp[0].minor.yy172, 0);}
-#line 2655 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2727 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 198:
case 200:
-#line 691 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 689 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy72.eOperator = yymsp[0].minor.yy0; yygotominor.yy72.not = 0;}
-#line 2661 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2733 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 199:
case 201:
-#line 692 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 690 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy72.eOperator = yymsp[0].minor.yy0; yygotominor.yy72.not = 1;}
-#line 2667 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2739 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 204:
-#line 699 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 697 "ext/pdo_sqlite/sqlite/src/parse.y"
{
ExprList *pList;
pList = sqlite3ExprListAppend(0, yymsp[-1].minor.yy172, 0);
@@ -2677,66 +2749,66 @@ static void yy_reduce(
sqlite3ExprSpan(yygotominor.yy172, &yymsp[-3].minor.yy172->span, &yymsp[-1].minor.yy172->span);
if( yygotominor.yy172 ) yygotominor.yy172->flags |= EP_InfixFunc;
}
-#line 2683 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2755 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 205:
-#line 712 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 710 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(yymsp[0].major, yymsp[-1].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2691 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2763 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 206:
-#line 716 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 714 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_ISNULL, yymsp[-2].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2699 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2771 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 207:
-#line 720 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 718 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_NOTNULL, yymsp[-2].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2707 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2779 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 208:
-#line 724 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 722 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_NOTNULL, yymsp[-3].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2715 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2787 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 209:
-#line 728 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 726 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(yymsp[-1].major, yymsp[0].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span);
}
-#line 2723 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2795 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 210:
-#line 732 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 730 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_UMINUS, yymsp[0].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span);
}
-#line 2731 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2803 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 211:
-#line 736 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 734 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_UPLUS, yymsp[0].minor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy172->span);
}
-#line 2739 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2811 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 214:
-#line 743 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 741 "ext/pdo_sqlite/sqlite/src/parse.y"
{
ExprList *pList = sqlite3ExprListAppend(0, yymsp[-2].minor.yy172, 0);
pList = sqlite3ExprListAppend(pList, yymsp[0].minor.yy172, 0);
@@ -2749,10 +2821,10 @@ static void yy_reduce(
if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy172->span);
}
-#line 2755 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2827 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 217:
-#line 759 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 757 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy172, 0, 0);
if( yygotominor.yy172 ){
@@ -2763,10 +2835,10 @@ static void yy_reduce(
if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2769 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2841 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 218:
-#line 769 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 767 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_SELECT, 0, 0, 0);
if( yygotominor.yy172 ){
@@ -2776,10 +2848,10 @@ static void yy_reduce(
}
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0);
}
-#line 2782 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2854 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 219:
-#line 778 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 776 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-4].minor.yy172, 0, 0);
if( yygotominor.yy172 ){
@@ -2790,10 +2862,10 @@ static void yy_reduce(
if( yymsp[-3].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-4].minor.yy172->span,&yymsp[0].minor.yy0);
}
-#line 2796 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2868 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 220:
-#line 788 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 786 "ext/pdo_sqlite/sqlite/src/parse.y"
{
SrcList *pSrc = sqlite3SrcListAppend(0,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410);
yygotominor.yy172 = sqlite3Expr(TK_IN, yymsp[-3].minor.yy172, 0, 0);
@@ -2805,10 +2877,10 @@ static void yy_reduce(
if( yymsp[-2].minor.yy46 ) yygotominor.yy172 = sqlite3Expr(TK_NOT, yygotominor.yy172, 0, 0);
sqlite3ExprSpan(yygotominor.yy172,&yymsp[-3].minor.yy172->span,yymsp[0].minor.yy410.z?&yymsp[0].minor.yy410:&yymsp[-1].minor.yy410);
}
-#line 2811 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2883 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 221:
-#line 799 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 797 "ext/pdo_sqlite/sqlite/src/parse.y"
{
Expr *p = yygotominor.yy172 = sqlite3Expr(TK_EXISTS, 0, 0, 0);
if( p ){
@@ -2818,10 +2890,10 @@ static void yy_reduce(
sqlite3SelectDelete(yymsp[-1].minor.yy219);
}
}
-#line 2824 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2896 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 222:
-#line 811 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 809 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_CASE, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, 0);
if( yygotominor.yy172 ){
@@ -2831,45 +2903,45 @@ static void yy_reduce(
}
sqlite3ExprSpan(yygotominor.yy172, &yymsp[-4].minor.yy0, &yymsp[0].minor.yy0);
}
-#line 2837 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2909 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 223:
-#line 822 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 820 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174, yymsp[-2].minor.yy172, 0);
yygotominor.yy174 = sqlite3ExprListAppend(yygotominor.yy174, yymsp[0].minor.yy172, 0);
}
-#line 2845 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2917 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 224:
-#line 826 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 824 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy174 = sqlite3ExprListAppend(0, yymsp[-2].minor.yy172, 0);
yygotominor.yy174 = sqlite3ExprListAppend(yygotominor.yy174, yymsp[0].minor.yy172, 0);
}
-#line 2853 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2925 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 233:
-#line 853 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 851 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3CreateIndex(pParse, &yymsp[-6].minor.yy410, &yymsp[-5].minor.yy410, sqlite3SrcListAppend(0,&yymsp[-3].minor.yy410,0), yymsp[-1].minor.yy174, yymsp[-9].minor.yy46,
&yymsp[-10].minor.yy0, &yymsp[0].minor.yy0, SQLITE_SO_ASC, yymsp[-7].minor.yy46);
}
-#line 2861 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2933 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 234:
- case 279:
-#line 859 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 281:
+#line 857 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Abort;}
-#line 2867 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2939 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 235:
-#line 860 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 858 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_None;}
-#line 2872 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2944 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 238:
-#line 870 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 868 "ext/pdo_sqlite/sqlite/src/parse.y"
{
Expr *p = 0;
if( yymsp[-1].minor.yy410.n>0 ){
@@ -2879,10 +2951,10 @@ static void yy_reduce(
yygotominor.yy174 = sqlite3ExprListAppend(yymsp[-4].minor.yy174, p, &yymsp[-2].minor.yy410);
if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46;
}
-#line 2885 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2957 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 239:
-#line 879 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 877 "ext/pdo_sqlite/sqlite/src/parse.y"
{
Expr *p = 0;
if( yymsp[-1].minor.yy410.n>0 ){
@@ -2892,115 +2964,108 @@ static void yy_reduce(
yygotominor.yy174 = sqlite3ExprListAppend(0, p, &yymsp[-2].minor.yy410);
if( yygotominor.yy174 ) yygotominor.yy174->a[yygotominor.yy174->nExpr-1].sortOrder = yymsp[0].minor.yy46;
}
-#line 2898 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2970 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 241:
-#line 893 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3DropIndex(pParse, yymsp[0].minor.yy373, yymsp[-1].minor.yy46);}
-#line 2903 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 889 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy410.z = 0; yygotominor.yy410.n = 0;}
+#line 2975 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 242:
case 243:
-#line 897 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Vacuum(pParse);}
-#line 2909 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 895 "ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3DropIndex(pParse, yymsp[0].minor.yy373, yymsp[-1].minor.yy46);}
+#line 2980 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 244:
+ case 245:
+#line 901 "ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Vacuum(pParse);}
+#line 2986 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
case 246:
-#line 903 "ext/pdo_sqlite/sqlite/src/parse.y"
+#line 909 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy410,0);}
-#line 2915 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2991 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 245:
-#line 904 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 247:
+#line 910 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy0,0);}
-#line 2920 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 2996 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 247:
-#line 906 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 248:
+#line 911 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3Pragma(pParse,&yymsp[-3].minor.yy410,&yymsp[-2].minor.yy410,&yymsp[0].minor.yy410,1);
}
-#line 2927 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3003 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 248:
-#line 909 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 249:
+#line 914 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy410,&yymsp[-3].minor.yy410,&yymsp[-1].minor.yy410,0);}
-#line 2932 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3008 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 249:
-#line 910 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 250:
+#line 915 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy410,&yymsp[0].minor.yy410,0,0);}
-#line 2937 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3013 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 255:
-#line 922 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 258:
+#line 929 "ext/pdo_sqlite/sqlite/src/parse.y"
{
Token all;
all.z = yymsp[-3].minor.yy410.z;
all.n = (yymsp[0].minor.yy0.z - yymsp[-3].minor.yy410.z) + yymsp[0].minor.yy0.n;
sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy243, &all);
}
-#line 2947 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3023 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 256:
-#line 931 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 259:
+#line 938 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy410, &yymsp[-6].minor.yy410, yymsp[-5].minor.yy46, yymsp[-4].minor.yy370.a, yymsp[-4].minor.yy370.b, yymsp[-2].minor.yy373, yymsp[-1].minor.yy46, yymsp[0].minor.yy172, yymsp[-9].minor.yy46);
+ sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy410, &yymsp[-6].minor.yy410, yymsp[-5].minor.yy46, yymsp[-4].minor.yy370.a, yymsp[-4].minor.yy370.b, yymsp[-2].minor.yy373, yymsp[0].minor.yy172, yymsp[-10].minor.yy46, yymsp[-8].minor.yy46);
yygotominor.yy410 = (yymsp[-6].minor.yy410.n==0?yymsp[-7].minor.yy410:yymsp[-6].minor.yy410);
}
-#line 2955 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3031 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 257:
case 260:
-#line 937 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 263:
+#line 944 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = TK_BEFORE; }
-#line 2961 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3037 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 258:
-#line 938 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 261:
+#line 945 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy46 = TK_AFTER; }
-#line 2966 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 259:
-#line 939 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy46 = TK_INSTEAD;}
-#line 2971 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3042 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 261:
case 262:
-#line 944 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy370.a = yymsp[0].major; yygotominor.yy370.b = 0;}
-#line 2977 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 263:
#line 946 "ext/pdo_sqlite/sqlite/src/parse.y"
-{yygotominor.yy370.a = TK_UPDATE; yygotominor.yy370.b = yymsp[0].minor.yy432;}
-#line 2982 "ext/pdo_sqlite/sqlite/src/parse.c"
+{ yygotominor.yy46 = TK_INSTEAD;}
+#line 3047 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 264:
case 265:
-#line 949 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy46 = TK_ROW; }
-#line 2988 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 951 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy370.a = yymsp[0].major; yygotominor.yy370.b = 0;}
+#line 3053 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 266:
-#line 951 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy46 = TK_STATEMENT; }
-#line 2993 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 953 "ext/pdo_sqlite/sqlite/src/parse.y"
+{yygotominor.yy370.a = TK_UPDATE; yygotominor.yy370.b = yymsp[0].minor.yy432;}
+#line 3058 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 267:
-#line 955 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 269:
+#line 960 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy172 = 0; }
-#line 2998 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3063 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 268:
-#line 956 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 270:
+#line 961 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy172 = yymsp[0].minor.yy172; }
-#line 3003 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3068 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 269:
-#line 960 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 271:
+#line 965 "ext/pdo_sqlite/sqlite/src/parse.y"
{
if( yymsp[-2].minor.yy243 ){
yymsp[-2].minor.yy243->pLast->pNext = yymsp[-1].minor.yy243;
@@ -3010,40 +3075,40 @@ static void yy_reduce(
yymsp[-2].minor.yy243->pLast = yymsp[-1].minor.yy243;
yygotominor.yy243 = yymsp[-2].minor.yy243;
}
-#line 3016 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3081 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 270:
-#line 969 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 272:
+#line 974 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy243 = 0; }
-#line 3021 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3086 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 271:
-#line 975 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 273:
+#line 980 "ext/pdo_sqlite/sqlite/src/parse.y"
{ yygotominor.yy243 = sqlite3TriggerUpdateStep(&yymsp[-3].minor.yy410, yymsp[-1].minor.yy174, yymsp[0].minor.yy172, yymsp[-4].minor.yy46); }
-#line 3026 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3091 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 272:
-#line 980 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 274:
+#line 985 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy243 = sqlite3TriggerInsertStep(&yymsp[-5].minor.yy410, yymsp[-4].minor.yy432, yymsp[-1].minor.yy174, 0, yymsp[-7].minor.yy46);}
-#line 3031 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3096 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 273:
-#line 983 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 275:
+#line 988 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy243 = sqlite3TriggerInsertStep(&yymsp[-2].minor.yy410, yymsp[-1].minor.yy432, 0, yymsp[0].minor.yy219, yymsp[-4].minor.yy46);}
-#line 3036 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3101 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 274:
-#line 987 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 276:
+#line 992 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy243 = sqlite3TriggerDeleteStep(&yymsp[-1].minor.yy410, yymsp[0].minor.yy172);}
-#line 3041 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3106 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 275:
-#line 990 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 277:
+#line 995 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy243 = sqlite3TriggerSelectStep(yymsp[0].minor.yy219); }
-#line 3046 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3111 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 276:
-#line 993 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 278:
+#line 998 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_RAISE, 0, 0, 0);
if( yygotominor.yy172 ){
@@ -3051,10 +3116,10 @@ static void yy_reduce(
sqlite3ExprSpan(yygotominor.yy172, &yymsp[-3].minor.yy0, &yymsp[0].minor.yy0);
}
}
-#line 3057 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3122 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 277:
-#line 1000 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 279:
+#line 1005 "ext/pdo_sqlite/sqlite/src/parse.y"
{
yygotominor.yy172 = sqlite3Expr(TK_RAISE, 0, 0, &yymsp[-1].minor.yy410);
if( yygotominor.yy172 ) {
@@ -3062,119 +3127,119 @@ static void yy_reduce(
sqlite3ExprSpan(yygotominor.yy172, &yymsp[-5].minor.yy0, &yymsp[0].minor.yy0);
}
}
-#line 3068 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3133 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 278:
-#line 1010 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 280:
+#line 1015 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Rollback;}
-#line 3073 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3138 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 280:
-#line 1012 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 282:
+#line 1017 "ext/pdo_sqlite/sqlite/src/parse.y"
{yygotominor.yy46 = OE_Fail;}
-#line 3078 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3143 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 281:
-#line 1017 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 283:
+#line 1022 "ext/pdo_sqlite/sqlite/src/parse.y"
{
- sqlite3DropTrigger(pParse,yymsp[0].minor.yy373);
+ sqlite3DropTrigger(pParse,yymsp[0].minor.yy373,yymsp[-1].minor.yy46);
}
-#line 3085 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3150 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 282:
-#line 1023 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 284:
+#line 1029 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3Attach(pParse, yymsp[-3].minor.yy172, yymsp[-1].minor.yy172, yymsp[0].minor.yy386);
}
-#line 3092 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 283:
-#line 1028 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy386 = 0; }
-#line 3097 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3157 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 284:
-#line 1029 "ext/pdo_sqlite/sqlite/src/parse.y"
-{ yygotominor.yy386 = yymsp[0].minor.yy172; }
-#line 3102 "ext/pdo_sqlite/sqlite/src/parse.c"
- break;
- case 287:
-#line 1035 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 285:
+#line 1032 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3Detach(pParse, yymsp[0].minor.yy172);
}
-#line 3109 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3164 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 288:
-#line 1041 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Reindex(pParse, 0, 0);}
-#line 3114 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 286:
+#line 1038 "ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy386 = 0; }
+#line 3169 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 289:
-#line 1042 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Reindex(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);}
-#line 3119 "ext/pdo_sqlite/sqlite/src/parse.c"
+ case 287:
+#line 1039 "ext/pdo_sqlite/sqlite/src/parse.y"
+{ yygotominor.yy386 = yymsp[0].minor.yy172; }
+#line 3174 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 290:
#line 1047 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Analyze(pParse, 0, 0);}
-#line 3124 "ext/pdo_sqlite/sqlite/src/parse.c"
+{sqlite3Reindex(pParse, 0, 0);}
+#line 3179 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 291:
#line 1048 "ext/pdo_sqlite/sqlite/src/parse.y"
-{sqlite3Analyze(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);}
-#line 3129 "ext/pdo_sqlite/sqlite/src/parse.c"
+{sqlite3Reindex(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);}
+#line 3184 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
case 292:
#line 1053 "ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Analyze(pParse, 0, 0);}
+#line 3189 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 293:
+#line 1054 "ext/pdo_sqlite/sqlite/src/parse.y"
+{sqlite3Analyze(pParse, &yymsp[-1].minor.yy410, &yymsp[0].minor.yy410);}
+#line 3194 "ext/pdo_sqlite/sqlite/src/parse.c"
+ break;
+ case 294:
+#line 1059 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy373,&yymsp[0].minor.yy410);
}
-#line 3136 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3201 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 293:
-#line 1056 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 295:
+#line 1062 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3AlterFinishAddColumn(pParse, &yymsp[0].minor.yy410);
}
-#line 3143 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3208 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 294:
-#line 1059 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 296:
+#line 1065 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy373);
}
-#line 3150 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3215 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 297:
-#line 1068 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 299:
+#line 1074 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3VtabFinishParse(pParse,0);}
-#line 3155 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3220 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 298:
-#line 1069 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 300:
+#line 1075 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
-#line 3160 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3225 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 299:
-#line 1070 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 301:
+#line 1076 "ext/pdo_sqlite/sqlite/src/parse.y"
{
sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy410, &yymsp[-2].minor.yy410, &yymsp[0].minor.yy410);
}
-#line 3167 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3232 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 302:
-#line 1075 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 304:
+#line 1081 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3VtabArgInit(pParse);}
-#line 3172 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3237 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
- case 304:
- case 305:
case 306:
+ case 307:
case 308:
-#line 1077 "ext/pdo_sqlite/sqlite/src/parse.y"
+ case 310:
+#line 1083 "ext/pdo_sqlite/sqlite/src/parse.y"
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
-#line 3180 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3245 "ext/pdo_sqlite/sqlite/src/parse.c"
break;
};
yygoto = yyRuleInfo[yyruleno].lhs;
@@ -3241,7 +3306,7 @@ static void yy_syntax_error(
}
pParse->parseError = 1;
}
-#line 3248 "ext/pdo_sqlite/sqlite/src/parse.c"
+#line 3313 "ext/pdo_sqlite/sqlite/src/parse.c"
sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
@@ -3297,7 +3362,13 @@ void sqlite3Parser(
/* (re)initialize the parser, if necessary */
yypParser = (yyParser*)yyp;
if( yypParser->yyidx<0 ){
- /* if( yymajor==0 ) return; // not sure why this was here... */
+#if YYSTACKDEPTH<=0
+ if( yypParser->yystksz <=0 ){
+ memset(&yyminorunion, 0, sizeof(yyminorunion));
+ yyStackOverflow(yypParser, &yyminorunion);
+ return;
+ }
+#endif
yypParser->yyidx = 0;
yypParser->yyerrcnt = -1;
yypParser->yystack[0].stateno = 0;
diff --git a/ext/pdo_sqlite/sqlite/src/parse.h b/ext/pdo_sqlite/sqlite/src/parse.h
index 65c9a5ce9..ed848ec5c 100644
--- a/ext/pdo_sqlite/sqlite/src/parse.h
+++ b/ext/pdo_sqlite/sqlite/src/parse.h
@@ -49,39 +49,39 @@
#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_VIRTUAL 56
-#define TK_REINDEX 57
-#define TK_RENAME 58
-#define TK_CTIME_KW 59
-#define TK_ANY 60
-#define TK_OR 61
-#define TK_AND 62
-#define TK_IS 63
-#define TK_BETWEEN 64
-#define TK_IN 65
-#define TK_ISNULL 66
-#define TK_NOTNULL 67
-#define TK_NE 68
-#define TK_EQ 69
-#define TK_GT 70
-#define TK_LE 71
-#define TK_LT 72
-#define TK_GE 73
-#define TK_ESCAPE 74
-#define TK_BITAND 75
-#define TK_BITOR 76
-#define TK_LSHIFT 77
-#define TK_RSHIFT 78
-#define TK_PLUS 79
-#define TK_MINUS 80
-#define TK_STAR 81
-#define TK_SLASH 82
-#define TK_REM 83
-#define TK_CONCAT 84
+#define TK_TRIGGER 52
+#define TK_VACUUM 53
+#define TK_VIEW 54
+#define TK_VIRTUAL 55
+#define TK_REINDEX 56
+#define TK_RENAME 57
+#define TK_CTIME_KW 58
+#define TK_ANY 59
+#define TK_OR 60
+#define TK_AND 61
+#define TK_IS 62
+#define TK_BETWEEN 63
+#define TK_IN 64
+#define TK_ISNULL 65
+#define TK_NOTNULL 66
+#define TK_NE 67
+#define TK_EQ 68
+#define TK_GT 69
+#define TK_LE 70
+#define TK_LT 71
+#define TK_GE 72
+#define TK_ESCAPE 73
+#define TK_BITAND 74
+#define TK_BITOR 75
+#define TK_LSHIFT 76
+#define TK_RSHIFT 77
+#define TK_PLUS 78
+#define TK_MINUS 79
+#define TK_STAR 80
+#define TK_SLASH 81
+#define TK_REM 82
+#define TK_CONCAT 83
+#define TK_COLLATE 84
#define TK_UMINUS 85
#define TK_UPLUS 86
#define TK_BITNOT 87
@@ -94,60 +94,59 @@
#define TK_UNIQUE 94
#define TK_CHECK 95
#define TK_REFERENCES 96
-#define TK_COLLATE 97
-#define TK_AUTOINCR 98
-#define TK_ON 99
-#define TK_DELETE 100
-#define TK_UPDATE 101
-#define TK_INSERT 102
-#define TK_SET 103
-#define TK_DEFERRABLE 104
-#define TK_FOREIGN 105
-#define TK_DROP 106
-#define TK_UNION 107
-#define TK_ALL 108
-#define TK_EXCEPT 109
-#define TK_INTERSECT 110
-#define TK_SELECT 111
-#define TK_DISTINCT 112
-#define TK_DOT 113
-#define TK_FROM 114
-#define TK_JOIN 115
-#define TK_USING 116
-#define TK_ORDER 117
-#define TK_BY 118
-#define TK_GROUP 119
-#define TK_HAVING 120
-#define TK_LIMIT 121
-#define TK_WHERE 122
-#define TK_INTO 123
-#define TK_VALUES 124
-#define TK_INTEGER 125
-#define TK_FLOAT 126
-#define TK_BLOB 127
-#define TK_REGISTER 128
-#define TK_VARIABLE 129
-#define TK_CASE 130
-#define TK_WHEN 131
-#define TK_THEN 132
-#define TK_ELSE 133
-#define TK_INDEX 134
-#define TK_ALTER 135
-#define TK_TO 136
-#define TK_ADD 137
-#define TK_COLUMNKW 138
-#define TK_TO_TEXT 139
-#define TK_TO_BLOB 140
-#define TK_TO_NUMERIC 141
-#define TK_TO_INT 142
-#define TK_TO_REAL 143
-#define TK_END_OF_FILE 144
-#define TK_ILLEGAL 145
-#define TK_SPACE 146
-#define TK_UNCLOSED_STRING 147
-#define TK_COMMENT 148
-#define TK_FUNCTION 149
-#define TK_COLUMN 150
-#define TK_AGG_FUNCTION 151
-#define TK_AGG_COLUMN 152
-#define TK_CONST_FUNC 153
+#define TK_AUTOINCR 97
+#define TK_ON 98
+#define TK_DELETE 99
+#define TK_UPDATE 100
+#define TK_INSERT 101
+#define TK_SET 102
+#define TK_DEFERRABLE 103
+#define TK_FOREIGN 104
+#define TK_DROP 105
+#define TK_UNION 106
+#define TK_ALL 107
+#define TK_EXCEPT 108
+#define TK_INTERSECT 109
+#define TK_SELECT 110
+#define TK_DISTINCT 111
+#define TK_DOT 112
+#define TK_FROM 113
+#define TK_JOIN 114
+#define TK_USING 115
+#define TK_ORDER 116
+#define TK_BY 117
+#define TK_GROUP 118
+#define TK_HAVING 119
+#define TK_LIMIT 120
+#define TK_WHERE 121
+#define TK_INTO 122
+#define TK_VALUES 123
+#define TK_INTEGER 124
+#define TK_FLOAT 125
+#define TK_BLOB 126
+#define TK_REGISTER 127
+#define TK_VARIABLE 128
+#define TK_CASE 129
+#define TK_WHEN 130
+#define TK_THEN 131
+#define TK_ELSE 132
+#define TK_INDEX 133
+#define TK_ALTER 134
+#define TK_TO 135
+#define TK_ADD 136
+#define TK_COLUMNKW 137
+#define TK_TO_TEXT 138
+#define TK_TO_BLOB 139
+#define TK_TO_NUMERIC 140
+#define TK_TO_INT 141
+#define TK_TO_REAL 142
+#define TK_END_OF_FILE 143
+#define TK_ILLEGAL 144
+#define TK_SPACE 145
+#define TK_UNCLOSED_STRING 146
+#define TK_COMMENT 147
+#define TK_FUNCTION 148
+#define TK_COLUMN 149
+#define TK_AGG_FUNCTION 150
+#define TK_AGG_COLUMN 151
+#define TK_CONST_FUNC 152
diff --git a/ext/pdo_sqlite/sqlite/src/parse.y b/ext/pdo_sqlite/sqlite/src/parse.y
index 301eb9b8e..332ddebe0 100644
--- a/ext/pdo_sqlite/sqlite/src/parse.y
+++ b/ext/pdo_sqlite/sqlite/src/parse.y
@@ -104,7 +104,7 @@ explain ::= . { sqlite3BeginParse(pParse, 0); }
%ifndef SQLITE_OMIT_EXPLAIN
explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
explain ::= EXPLAIN QUERY PLAN. { sqlite3BeginParse(pParse, 2); }
-%endif
+%endif SQLITE_OMIT_EXPLAIN
///////////////////// Begin and end transactions. ////////////////////////////
//
@@ -134,7 +134,7 @@ ifnotexists(A) ::= IF NOT EXISTS. {A = 1;}
%type temp {int}
%ifndef SQLITE_OMIT_TEMPDB
temp(A) ::= TEMP. {A = 1;}
-%endif
+%endif SQLITE_OMIT_TEMPDB
temp(A) ::= . {A = 0;}
create_table_args ::= LP columnlist conslist_opt(X) RP(Y). {
sqlite3EndTable(pParse,&X,&Y,0);
@@ -175,11 +175,11 @@ id(A) ::= ID(X). {A = X;}
ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH PLAN QUERY KEY
- OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
+ OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW
TEMP TRIGGER VACUUM VIEW VIRTUAL
%ifdef SQLITE_OMIT_COMPOUND_SELECT
EXCEPT INTERSECT UNION
-%endif
+%endif SQLITE_OMIT_COMPOUND_SELECT
REINDEX RENAME CTIME_KW IF
.
%wildcard ANY.
@@ -205,6 +205,7 @@ id(A) ::= ID(X). {A = X;}
%left PLUS MINUS.
%left STAR SLASH REM.
%left CONCAT.
+%left COLLATE.
%right UMINUS UPLUS BITNOT.
// And "ids" is an identifer-or-string.
@@ -238,9 +239,8 @@ typetoken(A) ::= typename(X) LP signed COMMA signed RP(Y). {
%type typename {Token}
typename(A) ::= ids(X). {A = X;}
typename(A) ::= typename(X) ids(Y). {A.z=X.z; A.n=Y.n+(Y.z-X.z);}
-%type signed {int}
-signed(A) ::= plus_num(X). { A = atoi((char*)X.z); }
-signed(A) ::= minus_num(X). { A = -atoi((char*)X.z); }
+signed ::= plus_num.
+signed ::= minus_num.
// "carglist" is a list of additional constraints that come after the
// column name and column type in a CREATE TABLE statement.
@@ -249,14 +249,14 @@ carglist ::= carglist carg.
carglist ::= .
carg ::= CONSTRAINT nm ccons.
carg ::= ccons.
-carg ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
-carg ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,X);}
-carg ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
-carg ::= DEFAULT MINUS term(X). {
+ccons ::= DEFAULT term(X). {sqlite3AddDefaultValue(pParse,X);}
+ccons ::= DEFAULT LP expr(X) RP. {sqlite3AddDefaultValue(pParse,X);}
+ccons ::= DEFAULT PLUS term(X). {sqlite3AddDefaultValue(pParse,X);}
+ccons ::= DEFAULT MINUS term(X). {
Expr *p = sqlite3Expr(TK_UMINUS, X, 0, 0);
sqlite3AddDefaultValue(pParse,p);
}
-carg ::= DEFAULT id(X). {
+ccons ::= DEFAULT id(X). {
Expr *p = sqlite3Expr(TK_STRING, 0, 0, &X);
sqlite3AddDefaultValue(pParse,p);
}
@@ -355,13 +355,13 @@ ifexists(A) ::= . {A = 0;}
///////////////////// The CREATE VIEW statement /////////////////////////////
//
%ifndef SQLITE_OMIT_VIEW
-cmd ::= CREATE(X) temp(T) VIEW nm(Y) dbnm(Z) AS select(S). {
- sqlite3CreateView(pParse, &X, &Y, &Z, S, T);
+cmd ::= CREATE(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z) AS select(S). {
+ sqlite3CreateView(pParse, &X, &Y, &Z, S, T, E);
}
cmd ::= DROP VIEW ifexists(E) fullname(X). {
sqlite3DropTable(pParse, X, 1, E);
}
-%endif // SQLITE_OMIT_VIEW
+%endif SQLITE_OMIT_VIEW
//////////////////////// The SELECT statement /////////////////////////////////
//
@@ -388,7 +388,7 @@ select(A) ::= select(X) multiselect_op(Y) oneselect(Z). {
multiselect_op(A) ::= UNION(OP). {A = @OP;}
multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;}
-%endif // SQLITE_OMIT_COMPOUND_SELECT
+%endif SQLITE_OMIT_COMPOUND_SELECT
oneselect(A) ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y)
groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
A = sqlite3SelectNew(W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
@@ -444,7 +444,10 @@ as(X) ::= . {X.n = 0;}
// A complete FROM clause.
//
from(A) ::= . {A = sqliteMalloc(sizeof(*A));}
-from(A) ::= FROM seltablist(X). {A = X;}
+from(A) ::= FROM seltablist(X). {
+ A = X;
+ sqlite3SrcListShiftJoinType(A);
+}
// "seltablist" is a "Select Table List" - the content of the FROM clause
// in a SELECT statement. "stl_prefix" is a prefix of this list.
@@ -455,31 +458,12 @@ stl_prefix(A) ::= seltablist(X) joinop(Y). {
}
stl_prefix(A) ::= . {A = 0;}
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
- A = sqlite3SrcListAppend(X,&Y,&D);
- if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
- if( N ){
- if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
- else { sqlite3ExprDelete(N); }
- }
- if( U ){
- if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
- else { sqlite3IdListDelete(U); }
- }
+ A = sqlite3SrcListAppendFromTerm(X,&Y,&D,&Z,0,N,U);
}
%ifndef SQLITE_OMIT_SUBQUERY
seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
as(Z) on_opt(N) using_opt(U). {
- A = sqlite3SrcListAppend(X,0,0);
- if( A && A->nSrc>0 ) A->a[A->nSrc-1].pSelect = S;
- if( Z.n ) sqlite3SrcListAddAlias(A,&Z);
- if( N ){
- if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pOn = N; }
- else { sqlite3ExprDelete(N); }
- }
- if( U ){
- if( A && A->nSrc>1 ){ A->a[A->nSrc-2].pUsing = U; }
- else { sqlite3IdListDelete(U); }
- }
+ A = sqlite3SrcListAppendFromTerm(X,0,0,&Z,S,N,U);
}
// A seltablist_paren nonterminal represents anything in a FROM that
@@ -490,9 +474,10 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
%destructor seltablist_paren {sqlite3SelectDelete($$);}
seltablist_paren(A) ::= select(S). {A = S;}
seltablist_paren(A) ::= seltablist(F). {
+ sqlite3SrcListShiftJoinType(F);
A = sqlite3SelectNew(0,F,0,0,0,0,0,0,0);
}
-%endif // SQLITE_OMIT_SUBQUERY
+%endif SQLITE_OMIT_SUBQUERY
%type dbnm {Token}
dbnm(A) ::= . {A.z=0; A.n=0;}
@@ -530,24 +515,21 @@ using_opt(U) ::= . {U = 0;}
orderby_opt(A) ::= . {A = 0;}
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
-sortlist(A) ::= sortlist(X) COMMA sortitem(Y) collate(C) sortorder(Z). {
- A = sqlite3ExprListAppend(X,Y,C.n>0?&C:0);
+sortlist(A) ::= sortlist(X) COMMA sortitem(Y) sortorder(Z). {
+ A = sqlite3ExprListAppend(X,Y,0);
if( A ) A->a[A->nExpr-1].sortOrder = Z;
}
-sortlist(A) ::= sortitem(Y) collate(C) sortorder(Z). {
- A = sqlite3ExprListAppend(0,Y,C.n>0?&C:0);
+sortlist(A) ::= sortitem(Y) sortorder(Z). {
+ A = sqlite3ExprListAppend(0,Y,0);
if( A && A->a ) A->a[0].sortOrder = Z;
}
sortitem(A) ::= expr(X). {A = X;}
%type sortorder {int}
-%type collate {Token}
sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;}
sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;}
sortorder(A) ::= . {A = SQLITE_SO_ASC;}
-collate(C) ::= . {C.z = 0; C.n = 0;}
-collate(C) ::= COLLATE id(X). {C = X;}
%type groupby_opt {ExprList*}
%destructor groupby_opt {sqlite3ExprListDelete($$);}
@@ -560,10 +542,18 @@ having_opt(A) ::= . {A = 0;}
having_opt(A) ::= HAVING expr(X). {A = X;}
%type limit_opt {struct LimitVal}
-%destructor limit_opt {
- sqlite3ExprDelete($$.pLimit);
- sqlite3ExprDelete($$.pOffset);
-}
+
+// The destructor for limit_opt will never fire in the current grammar.
+// The limit_opt non-terminal only occurs at the end of a single production
+// rule for SELECT statements. As soon as the rule that create the
+// limit_opt non-terminal reduces, the SELECT statement rule will also
+// reduce. So there is never a limit_opt non-terminal on the stack
+// except as a transient. So there is never anything to destroy.
+//
+//%destructor limit_opt {
+// sqlite3ExprDelete($$.pLimit);
+// sqlite3ExprDelete($$.pOffset);
+//}
limit_opt(A) ::= . {A.pLimit = 0; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X). {A.pLimit = X; A.pOffset = 0;}
limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y).
@@ -600,6 +590,8 @@ cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F)
{sqlite3Insert(pParse, X, Y, 0, F, R);}
cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) select(S).
{sqlite3Insert(pParse, X, 0, S, F, R);}
+cmd ::= insert_cmd(R) INTO fullname(X) inscollist_opt(F) DEFAULT VALUES.
+ {sqlite3Insert(pParse, X, 0, 0, F, R);}
%type insert_cmd {int}
insert_cmd(A) ::= INSERT orconf(R). {A = R;}
@@ -655,12 +647,15 @@ expr(A) ::= VARIABLE(X). {
Expr *pExpr = A = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
sqlite3ExprAssignVarNumber(pParse, pExpr);
}
+expr(A) ::= expr(E) COLLATE id(C). {
+ A = sqlite3ExprSetColl(pParse, E, &C);
+}
%ifndef SQLITE_OMIT_CAST
expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
A = sqlite3Expr(TK_CAST, E, 0, &T);
sqlite3ExprSpan(A,&X,&Y);
}
-%endif // SQLITE_OMIT_CAST
+%endif SQLITE_OMIT_CAST
expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
A = sqlite3ExprFunction(Y, &X);
sqlite3ExprSpan(A,&X,&E);
@@ -676,7 +671,10 @@ term(A) ::= CTIME_KW(OP). {
/* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
** treated as functions that return constants */
A = sqlite3ExprFunction(0,&OP);
- if( A ) A->op = TK_CONST_FUNC;
+ if( A ){
+ A->op = TK_CONST_FUNC;
+ A->span = OP;
+ }
}
expr(A) ::= expr(X) AND(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
expr(A) ::= expr(X) OR(OP) expr(Y). {A = sqlite3Expr(@OP, X, Y, 0);}
@@ -805,7 +803,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
sqlite3SelectDelete(Y);
}
}
-%endif // SQLITE_OMIT_SUBQUERY
+%endif SQLITE_OMIT_SUBQUERY
/* CASE expressions */
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
@@ -887,6 +885,10 @@ idxlist(A) ::= idxitem(Y) collate(C) sortorder(Z). {
}
idxitem(A) ::= nm(X). {A = X;}
+%type collate {Token}
+collate(C) ::= . {C.z = 0; C.n = 0;}
+collate(C) ::= COLLATE id(X). {C = X;}
+
///////////////////////////// The DROP INDEX command /////////////////////////
//
@@ -894,21 +896,26 @@ cmd ::= DROP INDEX ifexists(E) fullname(X). {sqlite3DropIndex(pParse, X, E);}
///////////////////////////// The VACUUM command /////////////////////////////
//
+%ifndef SQLITE_OMIT_VACUUM
+%ifndef SQLITE_OMIT_ATTACH
cmd ::= VACUUM. {sqlite3Vacuum(pParse);}
cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
+%endif SQLITE_OMIT_ATTACH
+%endif SQLITE_OMIT_VACUUM
///////////////////////////// The PRAGMA command /////////////////////////////
//
%ifndef SQLITE_OMIT_PRAGMA
-cmd ::= PRAGMA nm(X) dbnm(Z) EQ nm(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
+cmd ::= PRAGMA nm(X) dbnm(Z) EQ nmnum(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ ON(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
-cmd ::= PRAGMA nm(X) dbnm(Z) EQ plus_num(Y). {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y). {
sqlite3Pragma(pParse,&X,&Z,&Y,1);
}
-cmd ::= PRAGMA nm(X) dbnm(Z) LP nm(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
+cmd ::= PRAGMA nm(X) dbnm(Z) LP nmnum(Y) RP. {sqlite3Pragma(pParse,&X,&Z,&Y,0);}
cmd ::= PRAGMA nm(X) dbnm(Z). {sqlite3Pragma(pParse,&X,&Z,0,0);}
-%endif // SQLITE_OMIT_PRAGMA
+nmnum(A) ::= plus_num(X). {A = X;}
+nmnum(A) ::= nm(X). {A = X;}
+%endif SQLITE_OMIT_PRAGMA
plus_num(A) ::= plus_opt number(X). {A = X;}
minus_num(A) ::= MINUS number(X). {A = X;}
number(A) ::= INTEGER|FLOAT(X). {A = X;}
@@ -926,10 +933,10 @@ cmd ::= CREATE trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
sqlite3FinishTrigger(pParse, S, &all);
}
-trigger_decl(A) ::= temp(T) TRIGGER nm(B) dbnm(Z) trigger_time(C)
- trigger_event(D)
- ON fullname(E) foreach_clause(F) when_clause(G). {
- sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, F, G, T);
+trigger_decl(A) ::= temp(T) TRIGGER ifnotexists(NOERR) nm(B) dbnm(Z)
+ trigger_time(C) trigger_event(D)
+ ON fullname(E) foreach_clause when_clause(G). {
+ sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, G, T, NOERR);
A = (Z.n==0?B:Z);
}
@@ -945,10 +952,8 @@ trigger_event(A) ::= DELETE|INSERT(OP). {A.a = @OP; A.b = 0;}
trigger_event(A) ::= UPDATE(OP). {A.a = @OP; A.b = 0;}
trigger_event(A) ::= UPDATE OF inscollist(X). {A.a = TK_UPDATE; A.b = X;}
-%type foreach_clause {int}
-foreach_clause(A) ::= . { A = TK_ROW; }
-foreach_clause(A) ::= FOR EACH ROW. { A = TK_ROW; }
-foreach_clause(A) ::= FOR EACH STATEMENT. { A = TK_STATEMENT; }
+foreach_clause ::= .
+foreach_clause ::= FOR EACH ROW.
%type when_clause {Expr*}
%destructor when_clause {sqlite3ExprDelete($$);}
@@ -1004,7 +1009,7 @@ expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
sqlite3ExprSpan(A, &X, &Y);
}
}
-%endif // !SQLITE_OMIT_TRIGGER
+%endif !SQLITE_OMIT_TRIGGER
%type raisetype {int}
raisetype(A) ::= ROLLBACK. {A = OE_Rollback;}
@@ -1014,15 +1019,20 @@ raisetype(A) ::= FAIL. {A = OE_Fail;}
//////////////////////// DROP TRIGGER statement //////////////////////////////
%ifndef SQLITE_OMIT_TRIGGER
-cmd ::= DROP TRIGGER fullname(X). {
- sqlite3DropTrigger(pParse,X);
+cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
+ sqlite3DropTrigger(pParse,X,NOERR);
}
-%endif // !SQLITE_OMIT_TRIGGER
+%endif !SQLITE_OMIT_TRIGGER
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
+%ifndef SQLITE_OMIT_ATTACH
cmd ::= ATTACH database_kw_opt expr(F) AS expr(D) key_opt(K). {
sqlite3Attach(pParse, F, D, K);
}
+cmd ::= DETACH database_kw_opt expr(D). {
+ sqlite3Detach(pParse, D);
+}
+
%type key_opt {Expr *}
%destructor key_opt {sqlite3ExprDelete($$);}
key_opt(A) ::= . { A = 0; }
@@ -1030,17 +1040,13 @@ key_opt(A) ::= KEY expr(X). { A = X; }
database_kw_opt ::= DATABASE.
database_kw_opt ::= .
-
-//////////////////////// DETACH DATABASE name /////////////////////////////////
-cmd ::= DETACH database_kw_opt expr(D). {
- sqlite3Detach(pParse, D);
-}
+%endif SQLITE_OMIT_ATTACH
////////////////////////// REINDEX collation //////////////////////////////////
%ifndef SQLITE_OMIT_REINDEX
cmd ::= REINDEX. {sqlite3Reindex(pParse, 0, 0);}
cmd ::= REINDEX nm(X) dbnm(Y). {sqlite3Reindex(pParse, &X, &Y);}
-%endif
+%endif SQLITE_OMIT_REINDEX
/////////////////////////////////// ANALYZE ///////////////////////////////////
%ifndef SQLITE_OMIT_ANALYZE
@@ -1061,7 +1067,7 @@ add_column_fullname ::= fullname(X). {
}
kwcolumn_opt ::= .
kwcolumn_opt ::= COLUMNKW.
-%endif
+%endif SQLITE_OMIT_ALTERTABLE
//////////////////////// CREATE VIRTUAL TABLE ... /////////////////////////////
%ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -1079,4 +1085,4 @@ vtabargtoken ::= lp anylist RP(X). {sqlite3VtabArgExtend(pParse,&X);}
lp ::= LP(X). {sqlite3VtabArgExtend(pParse,&X);}
anylist ::= .
anylist ::= anylist ANY(X). {sqlite3VtabArgExtend(pParse,&X);}
-%endif
+%endif SQLITE_OMIT_VIRTUALTABLE
diff --git a/ext/pdo_sqlite/sqlite/src/pragma.c b/ext/pdo_sqlite/sqlite/src/pragma.c
index fbcc1adc0..831aac57b 100644
--- a/ext/pdo_sqlite/sqlite/src/pragma.c
+++ b/ext/pdo_sqlite/sqlite/src/pragma.c
@@ -62,6 +62,17 @@ static int getBoolean(const char *z){
return getSafetyLevel(z)&1;
}
+/*
+** Interpret the given string as a locking mode value.
+*/
+static int getLockingMode(const char *z){
+ if( z ){
+ if( 0==sqlite3StrICmp(z, "exclusive") ) return PAGER_LOCKINGMODE_EXCLUSIVE;
+ if( 0==sqlite3StrICmp(z, "normal") ) return PAGER_LOCKINGMODE_NORMAL;
+ }
+ return PAGER_LOCKINGMODE_QUERY;
+}
+
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
/*
** Interpret the given string as a temp db location. Return 1 for file
@@ -89,7 +100,7 @@ static int getTempStore(const char *z){
static int invalidateTempStorage(Parse *pParse){
sqlite3 *db = pParse->db;
if( db->aDb[1].pBt!=0 ){
- if( db->flags & SQLITE_InTrans ){
+ if( !db->autoCommit ){
sqlite3ErrorMsg(pParse, "temporary storage cannot be changed "
"from within a transaction");
return SQLITE_ERROR;
@@ -157,7 +168,7 @@ static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
{ "ignore_check_constraints", SQLITE_IgnoreChecks },
#endif
/* The following is VERY experimental */
- { "writable_schema", SQLITE_WriteSchema },
+ { "writable_schema", SQLITE_WriteSchema|SQLITE_RecoveryMode },
{ "omit_readlock", SQLITE_NoReadlock },
/* TODO: Maybe it shouldn't be possible to change the ReadUncommitted
@@ -315,6 +326,53 @@ void sqlite3Pragma(
sqlite3BtreeSetPageSize(pBt, atoi(zRight), -1);
}
}else
+
+ /*
+ ** PRAGMA [database.]locking_mode
+ ** PRAGMA [database.]locking_mode = (normal|exclusive)
+ */
+ if( sqlite3StrICmp(zLeft,"locking_mode")==0 ){
+ const char *zRet = "normal";
+ int eMode = getLockingMode(zRight);
+
+ if( pId2->n==0 && eMode==PAGER_LOCKINGMODE_QUERY ){
+ /* Simple "PRAGMA locking_mode;" statement. This is a query for
+ ** the current default locking mode (which may be different to
+ ** the locking-mode of the main database).
+ */
+ eMode = db->dfltLockMode;
+ }else{
+ Pager *pPager;
+ if( pId2->n==0 ){
+ /* This indicates that no database name was specified as part
+ ** of the PRAGMA command. In this case the locking-mode must be
+ ** set on all attached databases, as well as the main db file.
+ **
+ ** Also, the sqlite3.dfltLockMode variable is set so that
+ ** any subsequently attached databases also use the specified
+ ** locking mode.
+ */
+ int ii;
+ assert(pDb==&db->aDb[0]);
+ for(ii=2; ii<db->nDb; ii++){
+ pPager = sqlite3BtreePager(db->aDb[ii].pBt);
+ sqlite3PagerLockingMode(pPager, eMode);
+ }
+ db->dfltLockMode = eMode;
+ }
+ pPager = sqlite3BtreePager(pDb->pBt);
+ eMode = sqlite3PagerLockingMode(pPager, eMode);
+ }
+
+ assert(eMode==PAGER_LOCKINGMODE_NORMAL||eMode==PAGER_LOCKINGMODE_EXCLUSIVE);
+ if( eMode==PAGER_LOCKINGMODE_EXCLUSIVE ){
+ zRet = "exclusive";
+ }
+ sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "locking_mode", P3_STATIC);
+ sqlite3VdbeOp3(v, OP_String8, 0, 0, zRet, 0);
+ sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
+ }else
#endif /* SQLITE_OMIT_PAGER_PRAGMAS */
/*
@@ -482,12 +540,17 @@ void sqlite3Pragma(
sqlite3VdbeSetColName(v, 5, COLNAME_NAME, "pk", P3_STATIC);
sqlite3ViewGetColumnNames(pParse, pTab);
for(i=0, pCol=pTab->aCol; i<pTab->nCol; i++, pCol++){
+ const Token *pDflt;
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, pCol->zName, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
pCol->zType ? pCol->zType : "", 0);
sqlite3VdbeAddOp(v, OP_Integer, pCol->notNull, 0);
- sqlite3ExprCode(pParse, pCol->pDflt);
+ if( pCol->pDflt && (pDflt = &pCol->pDflt->span)->z ){
+ sqlite3VdbeOp3(v, OP_String8, 0, 0, (char*)pDflt->z, pDflt->n);
+ }else{
+ sqlite3VdbeAddOp(v, OP_Null, 0, 0);
+ }
sqlite3VdbeAddOp(v, OP_Integer, pCol->isPrimKey, 0);
sqlite3VdbeAddOp(v, OP_Callback, 6, 0);
}
@@ -635,9 +698,13 @@ void sqlite3Pragma(
}
}else
+#ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX
+# define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100
+#endif
+
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
- int i, j, addr;
+ int i, j, addr, mxErr;
/* Code that appears at the end of the integrity check. If no error
** messages have been generated, output OK. Otherwise output the
@@ -655,7 +722,16 @@ void sqlite3Pragma(
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "integrity_check", P3_STATIC);
- sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */
+
+ /* Set the maximum error count */
+ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
+ if( zRight ){
+ mxErr = atoi(zRight);
+ if( mxErr<=0 ){
+ mxErr = SQLITE_INTEGRITY_CHECK_ERROR_MAX;
+ }
+ }
+ sqlite3VdbeAddOp(v, OP_MemInt, mxErr, 0);
/* Do an integrity check on each database file */
for(i=0; i<db->nDb; i++){
@@ -666,6 +742,9 @@ void sqlite3Pragma(
if( OMIT_TEMPDB && i==1 ) continue;
sqlite3CodeVerifySchema(pParse, i);
+ addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
+ sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
+ sqlite3VdbeJumpHere(v, addr);
/* Do an integrity check of the B-Tree
*/
@@ -680,28 +759,28 @@ void sqlite3Pragma(
cnt++;
}
}
- 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+7);
+ if( cnt==0 ) continue;
+ sqlite3VdbeAddOp(v, OP_IntegrityCk, 0, i);
+ addr = sqlite3VdbeAddOp(v, OP_IsNull, -1, 0);
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_Concat, 0, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
- sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
+ sqlite3VdbeJumpHere(v, addr);
/* Make sure all the indices are constructed correctly.
*/
- sqlite3CodeVerifySchema(pParse, i);
for(x=sqliteHashFirst(pTbls); x; x=sqliteHashNext(x)){
Table *pTab = sqliteHashData(x);
Index *pIdx;
int loopTop;
if( pTab->pIndex==0 ) continue;
+ addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
+ sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
+ sqlite3VdbeJumpHere(v, addr);
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
@@ -709,7 +788,7 @@ void sqlite3Pragma(
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int jmp2;
static const VdbeOpList idxErr[] = {
- { OP_MemIncr, 1, 0, 0},
+ { OP_MemIncr, -1, 0, 0},
{ OP_String8, 0, 0, "rowid "},
{ OP_Rowid, 1, 0, 0},
{ OP_String8, 0, 0, " missing from index "},
@@ -734,13 +813,16 @@ void sqlite3Pragma(
{ OP_MemLoad, 1, 0, 0},
{ OP_MemLoad, 2, 0, 0},
{ OP_Eq, 0, 0, 0}, /* 6 */
- { OP_MemIncr, 1, 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},
};
if( pIdx->tnum==0 ) continue;
+ addr = sqlite3VdbeAddOp(v, OP_IfMemPos, 0, 0);
+ sqlite3VdbeAddOp(v, OP_Halt, 0, 0);
+ sqlite3VdbeJumpHere(v, addr);
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
sqlite3VdbeChangeP1(v, addr+1, j+2);
sqlite3VdbeChangeP2(v, addr+1, addr+4);
@@ -752,6 +834,7 @@ void sqlite3Pragma(
}
}
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
+ sqlite3VdbeChangeP1(v, addr+1, mxErr);
sqlite3VdbeJumpHere(v, addr+2);
}else
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
@@ -889,8 +972,9 @@ void sqlite3Pragma(
sqlite3VdbeChangeP1(v, addr, iDb);
sqlite3VdbeChangeP2(v, addr, iCookie);
sqlite3VdbeSetNumCols(v, 1);
+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, zLeft, P3_TRANSIENT);
}
- }
+ }else
#endif /* SQLITE_OMIT_SCHEMA_VERSION_PRAGMAS */
#if defined(SQLITE_DEBUG) || defined(SQLITE_TEST)
@@ -915,7 +999,7 @@ void sqlite3Pragma(
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
sqlite3VdbeOp3(v, OP_String8, 0, 0, "closed", P3_STATIC);
}else{
- int j = sqlite3pager_lockstate(pPager);
+ int j = sqlite3PagerLockstate(pPager);
sqlite3VdbeOp3(v, OP_String8, 0, 0,
(j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
}
@@ -940,6 +1024,22 @@ void sqlite3Pragma(
sqlite3_key(db, zRight, strlen(zRight));
}else
#endif
+#if SQLITE_HAS_CODEC || defined(SQLITE_ENABLE_CEROD)
+ if( sqlite3StrICmp(zLeft, "activate_extensions")==0 ){
+#if SQLITE_HAS_CODEC
+ if( sqlite3StrNICmp(zRight, "see-", 4)==0 ){
+ extern void sqlite3_activate_see(const char*);
+ sqlite3_activate_see(&zRight[4]);
+ }
+#endif
+#ifdef SQLITE_ENABLE_CEROD
+ if( sqlite3StrNICmp(zRight, "cerod-", 6)==0 ){
+ extern void sqlite3_activate_cerod(const char*);
+ sqlite3_activate_cerod(&zRight[6]);
+ }
+#endif
+ }
+#endif
{}
diff --git a/ext/pdo_sqlite/sqlite/src/prepare.c b/ext/pdo_sqlite/sqlite/src/prepare.c
index 2191a9242..6e2bee34c 100644
--- a/ext/pdo_sqlite/sqlite/src/prepare.c
+++ b/ext/pdo_sqlite/sqlite/src/prepare.c
@@ -13,7 +13,7 @@
** interface, and routines that contribute to loading the database schema
** from disk.
**
-** $Id: prepare.c,v 1.1.2.2.2.1 2006/08/14 16:15:29 iliaa Exp $
+** $Id: prepare.c,v 1.1.2.2.2.3 2007/04/09 16:35:11 iliaa Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -41,28 +41,26 @@ static void corruptSchema(InitData *pData, const char *zExtra){
** argv[0] = name of thing being created
** argv[1] = root page number for table or index. 0 for trigger or view.
** argv[2] = SQL text for the CREATE statement.
-** argv[3] = "1" for temporary files, "0" for main database, "2" or more
-** for auxiliary database files.
**
*/
int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
InitData *pData = (InitData*)pInit;
sqlite3 *db = pData->db;
- int iDb;
+ int iDb = pData->iDb;
pData->rc = SQLITE_OK;
+ DbClearProperty(db, iDb, DB_Empty);
if( sqlite3MallocFailed() ){
corruptSchema(pData, 0);
return SQLITE_NOMEM;
}
- assert( argc==4 );
+ assert( argc==3 );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
- if( argv[1]==0 || argv[3]==0 ){
+ if( argv[1]==0 ){
corruptSchema(pData, 0);
return 1;
}
- iDb = atoi(argv[3]);
assert( iDb>=0 && iDb<db->nDb );
if( argv[2] && argv[2][0] ){
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
@@ -125,8 +123,7 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
int size;
Table *pTab;
Db *pDb;
- char const *azArg[5];
- char zDbNum[30];
+ char const *azArg[4];
int meta[10];
InitData initData;
char const *zMasterSchema;
@@ -177,12 +174,11 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
azArg[0] = zMasterName;
azArg[1] = "1";
azArg[2] = zMasterSchema;
- sprintf(zDbNum, "%d", iDb);
- azArg[3] = zDbNum;
- azArg[4] = 0;
+ azArg[3] = 0;
initData.db = db;
+ initData.iDb = iDb;
initData.pzErrMsg = pzErrMsg;
- rc = sqlite3InitCallback(&initData, 4, (char **)azArg, 0);
+ rc = sqlite3InitCallback(&initData, 3, (char **)azArg, 0);
if( rc ){
sqlite3SafetyOn(db);
return initData.rc;
@@ -295,8 +291,8 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
}else{
char *zSql;
zSql = sqlite3MPrintf(
- "SELECT name, rootpage, sql, '%s' FROM '%q'.%s",
- zDbNum, db->aDb[iDb].zName, zMasterName);
+ "SELECT name, rootpage, sql FROM '%q'.%s",
+ db->aDb[iDb].zName, zMasterName);
sqlite3SafetyOff(db);
rc = sqlite3_exec(db, zSql, sqlite3InitCallback, &initData, 0);
if( rc==SQLITE_ABORT ) rc = initData.rc;
@@ -314,10 +310,17 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
rc = SQLITE_NOMEM;
sqlite3ResetInternalSchema(db, 0);
}
- if( rc==SQLITE_OK ){
+ if( rc==SQLITE_OK || (db->flags&SQLITE_RecoveryMode)){
+ /* Black magic: If the SQLITE_RecoveryMode flag is set, then consider
+ ** the schema loaded, even if errors occured. In this situation the
+ ** current sqlite3_prepare() operation will fail, but the following one
+ ** will attempt to compile the supplied statement against whatever subset
+ ** of the schema was loaded before the error occured. The primary
+ ** purpose of this is to allow access to the sqlite_master table
+ ** even when it's contents have been corrupted.
+ */
DbSetProperty(db, iDb, DB_SchemaLoaded);
- }else{
- sqlite3ResetInternalSchema(db, iDb);
+ rc = SQLITE_OK;
}
return rc;
}
@@ -449,12 +452,13 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
/*
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
*/
-int sqlite3_prepare(
+int sqlite3Prepare(
sqlite3 *db, /* Database handle. */
const char *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
+ int saveSqlFlag, /* True to copy SQL text into the sqlite3_stmt */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
- const char** pzTail /* OUT: End of parsed string */
+ const char **pzTail /* OUT: End of parsed string */
){
Parse sParse;
char *zErrMsg = 0;
@@ -507,7 +511,9 @@ int sqlite3_prepare(
if( sqlite3MallocFailed() ){
sParse.rc = SQLITE_NOMEM;
}
- if( pzTail ) *pzTail = sParse.zTail;
+ if( pzTail ){
+ *pzTail = sParse.zTail;
+ }
rc = sParse.rc;
#ifndef SQLITE_OMIT_EXPLAIN
@@ -525,13 +531,16 @@ int sqlite3_prepare(
sqlite3VdbeSetColName(sParse.pVdbe, 3, COLNAME_NAME, "p2", P3_STATIC);
sqlite3VdbeSetColName(sParse.pVdbe, 4, COLNAME_NAME, "p3", P3_STATIC);
}
- }
+ }
#endif
if( sqlite3SafetyOff(db) ){
rc = SQLITE_MISUSE;
}
if( rc==SQLITE_OK ){
+ if( saveSqlFlag ){
+ sqlite3VdbeSetSql(sParse.pVdbe, zSql, sParse.zTail - zSql);
+ }
*ppStmt = (sqlite3_stmt*)sParse.pVdbe;
}else if( sParse.pVdbe ){
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
@@ -546,17 +555,78 @@ int sqlite3_prepare(
rc = sqlite3ApiExit(db, rc);
sqlite3ReleaseThreadData();
+ assert( (rc&db->errMask)==rc );
return rc;
}
+/*
+** Rerun the compilation of a statement after a schema change.
+** Return true if the statement was recompiled successfully.
+** Return false if there is an error of some kind.
+*/
+int sqlite3Reprepare(Vdbe *p){
+ int rc;
+ sqlite3_stmt *pNew;
+ const char *zSql;
+ sqlite3 *db;
+
+ zSql = sqlite3VdbeGetSql(p);
+ if( zSql==0 ){
+ return 0;
+ }
+ db = sqlite3VdbeDb(p);
+ rc = sqlite3Prepare(db, zSql, -1, 0, &pNew, 0);
+ if( rc ){
+ assert( pNew==0 );
+ return 0;
+ }else{
+ assert( pNew!=0 );
+ }
+ sqlite3VdbeSwap((Vdbe*)pNew, p);
+ sqlite3_transfer_bindings(pNew, (sqlite3_stmt*)p);
+ sqlite3VdbeResetStepResult((Vdbe*)pNew);
+ sqlite3VdbeFinalize((Vdbe*)pNew);
+ return 1;
+}
+
+
+/*
+** Two versions of the official API. Legacy and new use. In the legacy
+** version, the original SQL text is not saved in the prepared statement
+** and so if a schema change occurs, SQLITE_SCHEMA is returned by
+** sqlite3_step(). In the new version, the original SQL text is retained
+** and the statement is automatically recompiled if an schema change
+** occurs.
+*/
+int sqlite3_prepare(
+ sqlite3 *db, /* Database handle. */
+ const char *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const char **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3Prepare(db,zSql,nBytes,0,ppStmt,pzTail);
+}
+int sqlite3_prepare_v2(
+ sqlite3 *db, /* Database handle. */
+ const char *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const char **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3Prepare(db,zSql,nBytes,1,ppStmt,pzTail);
+}
+
+
#ifndef SQLITE_OMIT_UTF16
/*
** Compile the UTF-16 encoded SQL statement zSql into a statement handle.
*/
-int sqlite3_prepare16(
+static int sqlite3Prepare16(
sqlite3 *db, /* Database handle. */
const void *zSql, /* UTF-8 encoded SQL statement. */
int nBytes, /* Length of zSql in bytes. */
+ int saveSqlFlag, /* True to save SQL text into the sqlite3_stmt */
sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
const void **pzTail /* OUT: End of parsed string */
){
@@ -573,7 +643,7 @@ int sqlite3_prepare16(
}
zSql8 = sqlite3utf16to8(zSql, nBytes);
if( zSql8 ){
- rc = sqlite3_prepare(db, zSql8, -1, ppStmt, &zTail8);
+ rc = sqlite3Prepare(db, zSql8, -1, saveSqlFlag, ppStmt, &zTail8);
}
if( zTail8 && pzTail ){
@@ -588,4 +658,32 @@ int sqlite3_prepare16(
sqliteFree(zSql8);
return sqlite3ApiExit(db, rc);
}
+
+/*
+** Two versions of the official API. Legacy and new use. In the legacy
+** version, the original SQL text is not saved in the prepared statement
+** and so if a schema change occurs, SQLITE_SCHEMA is returned by
+** sqlite3_step(). In the new version, the original SQL text is retained
+** and the statement is automatically recompiled if an schema change
+** occurs.
+*/
+int sqlite3_prepare16(
+ sqlite3 *db, /* Database handle. */
+ const void *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const void **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3Prepare16(db,zSql,nBytes,0,ppStmt,pzTail);
+}
+int sqlite3_prepare16_v2(
+ sqlite3 *db, /* Database handle. */
+ const void *zSql, /* UTF-8 encoded SQL statement. */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: A pointer to the prepared statement */
+ const void **pzTail /* OUT: End of parsed string */
+){
+ return sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
+}
+
#endif /* SQLITE_OMIT_UTF16 */
diff --git a/ext/pdo_sqlite/sqlite/src/printf.c b/ext/pdo_sqlite/sqlite/src/printf.c
index b4c37fb61..17809b11e 100644
--- a/ext/pdo_sqlite/sqlite/src/printf.c
+++ b/ext/pdo_sqlite/sqlite/src/printf.c
@@ -821,9 +821,8 @@ char *sqlite3_vmprintf(const char *zFormat, va_list ap){
char *sqlite3_mprintf(const char *zFormat, ...){
va_list ap;
char *z;
- char zBase[SQLITE_PRINT_BUF_SIZE];
va_start(ap, zFormat);
- z = base_vprintf(sqlite3_realloc, 0, zBase, sizeof(zBase), zFormat, ap);
+ z = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
return z;
}
@@ -857,7 +856,7 @@ void sqlite3DebugPrintf(const char *zFormat, ...){
va_start(ap, zFormat);
base_vprintf(0, 0, zBuf, sizeof(zBuf), zFormat, ap);
va_end(ap);
- fprintf(stdout,"%d: %s", getpid(), zBuf);
+ fprintf(stdout,"%s", zBuf);
fflush(stdout);
}
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/random.c b/ext/pdo_sqlite/sqlite/src/random.c
index 51d5d72e7..5adc84aaf 100644
--- a/ext/pdo_sqlite/sqlite/src/random.c
+++ b/ext/pdo_sqlite/sqlite/src/random.c
@@ -37,7 +37,7 @@
** (Later): Actually, OP_NewRowid does not depend on a good source of
** randomness any more. But we will leave this code in all the same.
*/
-static int randomByte(){
+static int randomByte(void){
unsigned char t;
/* All threads share a single random number generator.
diff --git a/ext/pdo_sqlite/sqlite/src/select.c b/ext/pdo_sqlite/sqlite/src/select.c
index 57b415bf5..120470b56 100644
--- a/ext/pdo_sqlite/sqlite/src/select.c
+++ b/ext/pdo_sqlite/sqlite/src/select.c
@@ -66,6 +66,7 @@ Select *sqlite3SelectNew(
pNew->pOrderBy = pOrderBy;
pNew->isDistinct = isDistinct;
pNew->op = TK_SELECT;
+ assert( pOffset==0 || pLimit!=0 );
pNew->pLimit = pLimit;
pNew->pOffset = pOffset;
pNew->iLimit = -1;
@@ -299,8 +300,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
/* When the NATURAL keyword is present, add WHERE clause terms for
** every column that the two tables have in common.
*/
- if( pLeft->jointype & JT_NATURAL ){
- if( pLeft->pOn || pLeft->pUsing ){
+ if( pRight->jointype & JT_NATURAL ){
+ if( pRight->pOn || pRight->pUsing ){
sqlite3ErrorMsg(pParse, "a NATURAL join may not have "
"an ON or USING clause", 0);
return 1;
@@ -318,7 +319,7 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
/* Disallow both ON and USING clauses in the same join
*/
- if( pLeft->pOn && pLeft->pUsing ){
+ if( pRight->pOn && pRight->pUsing ){
sqlite3ErrorMsg(pParse, "cannot have both ON and USING "
"clauses in the same join");
return 1;
@@ -327,10 +328,10 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
/* Add the ON clause to the end of the WHERE clause, connected by
** an AND operator.
*/
- if( pLeft->pOn ){
- setJoinExpr(pLeft->pOn, pRight->iCursor);
- p->pWhere = sqlite3ExprAnd(p->pWhere, pLeft->pOn);
- pLeft->pOn = 0;
+ if( pRight->pOn ){
+ setJoinExpr(pRight->pOn, pRight->iCursor);
+ p->pWhere = sqlite3ExprAnd(p->pWhere, pRight->pOn);
+ pRight->pOn = 0;
}
/* Create extra terms on the WHERE clause for each column named
@@ -340,8 +341,8 @@ static int sqliteProcessJoin(Parse *pParse, Select *p){
** Report an error if any column mentioned in the USING clause is
** not contained in both tables to be joined.
*/
- if( pLeft->pUsing ){
- IdList *pList = pLeft->pUsing;
+ if( pRight->pUsing ){
+ IdList *pList = pRight->pUsing;
for(j=0; j<pList->nId; j++){
char *zName = pList->a[j].zName;
if( columnIndex(pLeftTab, zName)<0 || columnIndex(pRightTab, zName)<0 ){
@@ -532,7 +533,7 @@ static int selectInnerLoop(
}else{
sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- sqlite3VdbeAddOp(v, OP_Insert, iParm, 0);
+ sqlite3VdbeAddOp(v, OP_Insert, iParm, OPFLAG_APPEND);
}
break;
}
@@ -550,6 +551,7 @@ static int selectInnerLoop(
sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3);
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
+ p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr,(iParm>>16)&0xff);
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
@@ -557,9 +559,7 @@ static int selectInnerLoop(
** case the order does matter */
pushOntoSorter(pParse, pOrderBy, p);
}else{
- char affinity = (iParm>>16)&0xFF;
- affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, affinity);
- sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &affinity, 1);
+ sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &p->affinity, 1);
sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
}
sqlite3VdbeJumpHere(v, addr2);
@@ -691,7 +691,7 @@ static void generateSortTail(
int cont = sqlite3VdbeMakeLabel(v);
int addr;
int iTab;
- int pseudoTab;
+ int pseudoTab = 0;
ExprList *pOrderBy = p->pOrderBy;
iTab = pOrderBy->iECursor;
@@ -711,7 +711,7 @@ static void generateSortTail(
case SRT_EphemTab: {
sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0);
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
- sqlite3VdbeAddOp(v, OP_Insert, iParm, 0);
+ sqlite3VdbeAddOp(v, OP_Insert, iParm, OPFLAG_APPEND);
break;
}
#ifndef SQLITE_OMIT_SUBQUERY
@@ -720,7 +720,7 @@ static void generateSortTail(
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, "c", P3_STATIC);
+ sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &p->affinity, 1);
sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0);
break;
}
@@ -1069,7 +1069,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
Expr *p, *pR;
char *zType;
char *zName;
- char *zBasename;
+ int nName;
CollSeq *pColl;
int cnt;
NameContext sNC;
@@ -1095,24 +1095,22 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
sqlite3Dequote(zName);
if( sqlite3MallocFailed() ){
sqliteFree(zName);
- sqlite3DeleteTable(0, pTab);
+ sqlite3DeleteTable(pTab);
return 0;
}
/* Make sure the column name is unique. If the name is not unique,
** append a integer to the name so that it becomes unique.
*/
- zBasename = zName;
+ nName = strlen(zName);
for(j=cnt=0; j<i; j++){
if( sqlite3StrICmp(aCol[j].zName, zName)==0 ){
- zName = sqlite3MPrintf("%s:%d", zBasename, ++cnt);
+ zName[nName] = 0;
+ zName = sqlite3MPrintf("%z:%d", zName, ++cnt);
j = -1;
if( zName==0 ) break;
}
}
- if( zBasename!=zName ){
- sqliteFree(zBasename);
- }
pCol->zName = zName;
/* Get the typename, type affinity, and collating sequence for the
@@ -1309,13 +1307,13 @@ static int prepSelectStmt(Parse *pParse, Select *p){
if( i>0 ){
struct SrcList_item *pLeft = &pTabList->a[i-1];
- if( (pLeft->jointype & JT_NATURAL)!=0 &&
+ if( (pLeft[1].jointype & JT_NATURAL)!=0 &&
columnIndex(pLeft->pTab, zName)>=0 ){
/* In a NATURAL join, omit the join columns from the
** table on the right */
continue;
}
- if( sqlite3IdListIndex(pLeft->pUsing, zName)>=0 ){
+ if( sqlite3IdListIndex(pLeft[1].pUsing, zName)>=0 ){
/* In a join with a USING clause, omit columns in the
** using clause from the table on the right. */
continue;
@@ -1401,8 +1399,11 @@ static int matchOrderbyToColumn(
}
pEList = pSelect->pEList;
for(i=0; i<pOrderBy->nExpr; i++){
+ struct ExprList_item *pItem;
Expr *pE = pOrderBy->a[i].pExpr;
int iCol = -1;
+ char *zLabel;
+
if( pOrderBy->a[i].done ) continue;
if( sqlite3ExprIsInteger(pE, &iCol) ){
if( iCol<=0 || iCol>pEList->nExpr ){
@@ -1415,20 +1416,23 @@ static int matchOrderbyToColumn(
if( !mustComplete ) continue;
iCol--;
}
- for(j=0; iCol<0 && j<pEList->nExpr; j++){
- if( pEList->a[j].zName && (pE->op==TK_ID || pE->op==TK_STRING) ){
- char *zName, *zLabel;
- zName = pEList->a[j].zName;
- zLabel = sqlite3NameFromToken(&pE->token);
- assert( zLabel!=0 );
- if( sqlite3StrICmp(zName, zLabel)==0 ){
+ if( iCol<0 && (zLabel = sqlite3NameFromToken(&pE->token))!=0 ){
+ for(j=0, pItem=pEList->a; j<pEList->nExpr; j++, pItem++){
+ char *zName;
+ int isMatch;
+ if( pItem->zName ){
+ zName = sqlite3StrDup(pItem->zName);
+ }else{
+ zName = sqlite3NameFromToken(&pItem->pExpr->token);
+ }
+ isMatch = zName && sqlite3StrICmp(zName, zLabel)==0;
+ sqliteFree(zName);
+ if( isMatch ){
iCol = j;
+ break;
}
- sqliteFree(zLabel);
- }
- if( iCol<0 && sqlite3ExprCompare(pE, pEList->a[j].pExpr) ){
- iCol = j;
}
+ sqliteFree(zLabel);
}
if( iCol>=0 ){
pE->op = TK_COLUMN;
@@ -1436,8 +1440,7 @@ static int matchOrderbyToColumn(
pE->iTable = iTable;
pE->iAgg = -1;
pOrderBy->a[i].done = 1;
- }
- if( iCol<0 && mustComplete ){
+ }else if( mustComplete ){
sqlite3ErrorMsg(pParse,
"ORDER BY term number %d does not match any result column", i+1);
nErr++;
@@ -1936,6 +1939,7 @@ static int multiSelect(
}
sqlite3VdbeChangeP2(v, addr, nCol);
sqlite3VdbeChangeP3(v, addr, (char*)pKeyInfo, P3_KEYINFO);
+ pLoop->addrOpenEphm[i] = -1;
}
}
@@ -1951,10 +1955,9 @@ static int multiSelect(
apColl = pKeyInfo->aColl;
for(i=0; i<nOrderByExpr; i++, pOTerm++, apColl++, pSortOrder++){
Expr *pExpr = pOTerm->pExpr;
- char *zName = pOTerm->zName;
- assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol );
- if( zName ){
- *apColl = sqlite3LocateCollSeq(pParse, zName, -1);
+ if( (pExpr->flags & EP_ExpCollate) ){
+ assert( pExpr->pColl!=0 );
+ *apColl = pExpr->pColl;
}else{
*apColl = aCopy[pExpr->iColumn];
}
@@ -2175,7 +2178,7 @@ static int flattenSubquery(
**
** which is not at all the same thing.
*/
- if( pSubSrc->nSrc>1 && iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0 ){
+ if( pSubSrc->nSrc>1 && (pSubitem->jointype & JT_OUTER)!=0 ){
return 0;
}
@@ -2192,8 +2195,7 @@ static int flattenSubquery(
** But the t2.x>0 test will always fail on a NULL row of t2, which
** effectively converts the OUTER JOIN into an INNER JOIN.
*/
- if( iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0
- && pSub->pWhere!=0 ){
+ if( (pSubitem->jointype & JT_OUTER)!=0 && pSub->pWhere!=0 ){
return 0;
}
@@ -2214,7 +2216,7 @@ static int flattenSubquery(
int nSubSrc = pSubSrc->nSrc;
int jointype = pSubitem->jointype;
- sqlite3DeleteTable(0, pSubitem->pTab);
+ sqlite3DeleteTable(pSubitem->pTab);
sqliteFree(pSubitem->zDatabase);
sqliteFree(pSubitem->zName);
sqliteFree(pSubitem->zAlias);
@@ -2232,7 +2234,7 @@ static int flattenSubquery(
pSrc->a[i+iFrom] = pSubSrc->a[i];
memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
}
- pSrc->a[iFrom+nSubSrc-1].jointype = jointype;
+ pSrc->a[iFrom].jointype = jointype;
}
/* Now begin substituting subquery result set expressions for
@@ -2367,6 +2369,8 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
iCol = pExpr->iColumn;
pTab = pSrc->a[0].pTab;
+ /* This optimization cannot be used with virtual tables. */
+ if( IsVirtual(pTab) ) return 0;
/* 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
@@ -2478,8 +2482,14 @@ static int processOrderGroupBy(
Expr *pE = pOrderBy->a[i].pExpr;
if( sqlite3ExprIsInteger(pE, &iCol) ){
if( iCol>0 && iCol<=pEList->nExpr ){
+ CollSeq *pColl = pE->pColl;
+ int flags = pE->flags & EP_ExpCollate;
sqlite3ExprDelete(pE);
pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr);
+ if( pColl && flags ){
+ pE->pColl = pColl;
+ pE->flags |= flags;
+ }
}else{
sqlite3ErrorMsg(pParse,
"%s BY column number %d out of range - should be "
@@ -2584,12 +2594,15 @@ int sqlite3SelectResolve(
*/
sNC.pEList = p->pEList;
if( sqlite3ExprResolveNames(&sNC, p->pWhere) ||
- sqlite3ExprResolveNames(&sNC, p->pHaving) ||
- processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") ||
- processOrderGroupBy(&sNC, pGroupBy, "GROUP")
- ){
+ sqlite3ExprResolveNames(&sNC, p->pHaving) ){
return SQLITE_ERROR;
}
+ if( p->pPrior==0 ){
+ if( processOrderGroupBy(&sNC, p->pOrderBy, "ORDER") ||
+ processOrderGroupBy(&sNC, pGroupBy, "GROUP") ){
+ return SQLITE_ERROR;
+ }
+ }
/* Make sure the GROUP BY clause does not contain aggregate functions.
*/
@@ -2605,7 +2618,14 @@ int sqlite3SelectResolve(
}
}
- return SQLITE_OK;
+ /* If this is one SELECT of a compound, be sure to resolve names
+ ** in the other SELECTs.
+ */
+ if( p->pPrior ){
+ return sqlite3SelectResolve(pParse, p->pPrior, pOuterNC);
+ }else{
+ return SQLITE_OK;
+ }
}
/*
@@ -2907,23 +2927,15 @@ int sqlite3Select(
}
#endif
- /* If there is an ORDER BY clause, resolve any collation sequences
- ** names that have been explicitly specified and create a sorting index.
- **
- ** This sorting index might end up being unused if the data can be
+ /* If there is an ORDER BY clause, then this sorting
+ ** index might end up being unused if the data can be
** extracted in pre-sorted order. If that is the case, then the
** OP_OpenEphemeral instruction will be changed to an OP_Noop once
** we figure out that the sorting index is not needed. The addrSortIndex
** variable is used to facilitate that change.
*/
if( pOrderBy ){
- struct ExprList_item *pTerm;
KeyInfo *pKeyInfo;
- for(i=0, pTerm=pOrderBy->a; i<pOrderBy->nExpr; i++, pTerm++){
- if( pTerm->zName ){
- pTerm->pExpr->pColl = sqlite3LocateCollSeq(pParse, pTerm->zName, -1);
- }
- }
if( pParse->nErr ){
goto select_end;
}
@@ -3140,11 +3152,7 @@ int sqlite3Select(
for(i=0; i<sAggInfo.nColumn; i++){
struct AggInfo_col *pCol = &sAggInfo.aCol[i];
if( pCol->iSorterColumn<j ) continue;
- if( pCol->iColumn<0 ){
- sqlite3VdbeAddOp(v, OP_Rowid, pCol->iTable, 0);
- }else{
- sqlite3VdbeAddOp(v, OP_Column, pCol->iTable, pCol->iColumn);
- }
+ sqlite3ExprCodeGetColumn(v, pCol->pTab, pCol->iColumn, pCol->iTable);
j++;
}
sqlite3VdbeAddOp(v, OP_MakeRecord, j, 0);
@@ -3293,3 +3301,99 @@ select_end:
sqliteFree(sAggInfo.aFunc);
return rc;
}
+
+#if defined(SQLITE_DEBUG)
+/*
+*******************************************************************************
+** The following code is used for testing and debugging only. The code
+** that follows does not appear in normal builds.
+**
+** These routines are used to print out the content of all or part of a
+** parse structures such as Select or Expr. Such printouts are useful
+** for helping to understand what is happening inside the code generator
+** during the execution of complex SELECT statements.
+**
+** These routine are not called anywhere from within the normal
+** code base. Then are intended to be called from within the debugger
+** or from temporary "printf" statements inserted for debugging.
+*/
+void sqlite3PrintExpr(Expr *p){
+ if( p->token.z && p->token.n>0 ){
+ sqlite3DebugPrintf("(%.*s", p->token.n, p->token.z);
+ }else{
+ sqlite3DebugPrintf("(%d", p->op);
+ }
+ if( p->pLeft ){
+ sqlite3DebugPrintf(" ");
+ sqlite3PrintExpr(p->pLeft);
+ }
+ if( p->pRight ){
+ sqlite3DebugPrintf(" ");
+ sqlite3PrintExpr(p->pRight);
+ }
+ sqlite3DebugPrintf(")");
+}
+void sqlite3PrintExprList(ExprList *pList){
+ int i;
+ for(i=0; i<pList->nExpr; i++){
+ sqlite3PrintExpr(pList->a[i].pExpr);
+ if( i<pList->nExpr-1 ){
+ sqlite3DebugPrintf(", ");
+ }
+ }
+}
+void sqlite3PrintSelect(Select *p, int indent){
+ sqlite3DebugPrintf("%*sSELECT(%p) ", indent, "", p);
+ sqlite3PrintExprList(p->pEList);
+ sqlite3DebugPrintf("\n");
+ if( p->pSrc ){
+ char *zPrefix;
+ int i;
+ zPrefix = "FROM";
+ for(i=0; i<p->pSrc->nSrc; i++){
+ struct SrcList_item *pItem = &p->pSrc->a[i];
+ sqlite3DebugPrintf("%*s ", indent+6, zPrefix);
+ zPrefix = "";
+ if( pItem->pSelect ){
+ sqlite3DebugPrintf("(\n");
+ sqlite3PrintSelect(pItem->pSelect, indent+10);
+ sqlite3DebugPrintf("%*s)", indent+8, "");
+ }else if( pItem->zName ){
+ sqlite3DebugPrintf("%s", pItem->zName);
+ }
+ if( pItem->pTab ){
+ sqlite3DebugPrintf("(table: %s)", pItem->pTab->zName);
+ }
+ if( pItem->zAlias ){
+ sqlite3DebugPrintf(" AS %s", pItem->zAlias);
+ }
+ if( i<p->pSrc->nSrc-1 ){
+ sqlite3DebugPrintf(",");
+ }
+ sqlite3DebugPrintf("\n");
+ }
+ }
+ if( p->pWhere ){
+ sqlite3DebugPrintf("%*s WHERE ", indent, "");
+ sqlite3PrintExpr(p->pWhere);
+ sqlite3DebugPrintf("\n");
+ }
+ if( p->pGroupBy ){
+ sqlite3DebugPrintf("%*s GROUP BY ", indent, "");
+ sqlite3PrintExprList(p->pGroupBy);
+ sqlite3DebugPrintf("\n");
+ }
+ if( p->pHaving ){
+ sqlite3DebugPrintf("%*s HAVING ", indent, "");
+ sqlite3PrintExpr(p->pHaving);
+ sqlite3DebugPrintf("\n");
+ }
+ if( p->pOrderBy ){
+ sqlite3DebugPrintf("%*s ORDER BY ", indent, "");
+ sqlite3PrintExprList(p->pOrderBy);
+ sqlite3DebugPrintf("\n");
+ }
+}
+/* End of the structure debug printing code
+*****************************************************************************/
+#endif /* defined(SQLITE_TEST) || defined(SQLITE_DEBUG) */
diff --git a/ext/pdo_sqlite/sqlite/src/shell.c b/ext/pdo_sqlite/sqlite/src/shell.c
index 6058bc195..0e4cc4e23 100644
--- a/ext/pdo_sqlite/sqlite/src/shell.c
+++ b/ext/pdo_sqlite/sqlite/src/shell.c
@@ -20,6 +20,7 @@
#include <assert.h>
#include "sqlite3.h"
#include <ctype.h>
+#include <stdarg.h>
#if !defined(_WIN32) && !defined(WIN32) && !defined(__MACOS__) && !defined(__OS2__)
# include <signal.h>
@@ -52,9 +53,25 @@
# define stifle_history(X)
#endif
+#if defined(_WIN32) || defined(WIN32)
+# include <io.h>
+#else
/* Make sure isatty() has a prototype.
*/
extern int isatty();
+#endif
+
+/*
+** If the following flag is set, then command execution stops
+** at an error if we are not interactive.
+*/
+static int bail_on_error = 0;
+
+/*
+** Threat stdin as an interactive input if the following variable
+** is true. Otherwise, assume stdin is connected to a file or pipe.
+*/
+static int stdin_is_interactive = 1;
/*
** The following is the open SQLite database. We make a pointer
@@ -81,6 +98,28 @@ static char *Argv0;
static char mainPrompt[20]; /* First line prompt. default: "sqlite> "*/
static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */
+/*
+** Write I/O traces to the following stream.
+*/
+static FILE *iotrace = 0;
+
+/*
+** This routine works like printf in that its first argument is a
+** format string and subsequent arguments are values to be substituted
+** in place of % fields. The result of formatting this string
+** is written to iotrace.
+*/
+static void iotracePrintf(const char *zFormat, ...){
+ va_list ap;
+ char *z;
+ if( iotrace==0 ) return;
+ va_start(ap, zFormat);
+ z = sqlite3_vmprintf(zFormat, ap);
+ va_end(ap);
+ fprintf(iotrace, "%s", z);
+ sqlite3_free(z);
+}
+
/*
** Determines if a string is a number of not.
@@ -180,10 +219,7 @@ static char *local_getline(char *zPrompt, FILE *in){
}
/*
-** Retrieve a single line of input text. "isatty" is true if text
-** is coming from a terminal. In that case, we issue a prompt and
-** attempt to use "readline" for command-line editing. If "isatty"
-** is false, use "local_getline" instead of "readline" and issue no prompt.
+** Retrieve a single line of input text.
**
** zPrior is a string of prior text retrieved. If not the empty
** string, then issue a continuation prompt.
@@ -212,6 +248,7 @@ struct previous_mode_data {
int showHeader;
int colWidth[100];
};
+
/*
** An pointer to an instance of this structure is passed from
** the main program to the callback. This is used to communicate
@@ -223,6 +260,7 @@ struct callback_data {
int cnt; /* Number of records displayed so far */
FILE *out; /* Write results here */
int mode; /* An output mode setting */
+ int writableSchema; /* True if PRAGMA writable_schema=ON */
int showHeader; /* True to show column names in List or Column mode */
char *zDestTable; /* Name of destination table when MODE_Insert */
char separator[20]; /* Separator character for MODE_List */
@@ -235,7 +273,6 @@ struct callback_data {
** .explain ON */
char outfile[FILENAME_MAX]; /* Filename for *out */
const char *zDbFilename; /* name of the database file */
- char *zKey; /* Encryption key */
};
/*
@@ -348,18 +385,56 @@ static void output_html_string(FILE *out, const char *z){
}
/*
+** If a field contains any character identified by a 1 in the following
+** array, then the string must be quoted for CSV.
+*/
+static const char needCsvQuote[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+};
+
+/*
** Output a single term of CSV. Actually, p->separator is used for
** the separator, which may or may not be a comma. p->nullvalue is
** the null value. Strings are quoted using ANSI-C rules. Numbers
** appear outside of quotes.
*/
static void output_csv(struct callback_data *p, const char *z, int bSep){
+ FILE *out = p->out;
if( z==0 ){
- fprintf(p->out,"%s",p->nullvalue);
- }else if( isNumber(z, 0) ){
- fprintf(p->out,"%s",z);
+ fprintf(out,"%s",p->nullvalue);
}else{
- output_c_string(p->out, z);
+ int i;
+ for(i=0; z[i]; i++){
+ if( needCsvQuote[((unsigned char*)z)[i]] ){
+ i = 0;
+ break;
+ }
+ }
+ if( i==0 ){
+ putc('"', out);
+ for(i=0; z[i]; i++){
+ if( z[i]=='"' ) putc('"', out);
+ putc(z[i], out);
+ }
+ putc('"', out);
+ }else{
+ fprintf(out, "%s", z);
+ }
}
if( bSep ){
fprintf(p->out, p->separator);
@@ -584,7 +659,7 @@ static void set_table_name(struct callback_data *p, const char *zName){
** If the third argument, quote, is not '\0', then it is used as a
** quote character for zAppend.
*/
-static char * appendText(char *zIn, char const *zAppend, char quote){
+static char *appendText(char *zIn, char const *zAppend, char quote){
int len;
int i;
int nAppend = strlen(zAppend);
@@ -625,6 +700,9 @@ static char * appendText(char *zIn, char const *zAppend, char quote){
/*
** Execute a query statement that has a single result column. Print
** that result column on a line by itself with a semicolon terminator.
+**
+** This is used, for example, to show the schema of the database by
+** querying the SQLITE_MASTER table.
*/
static int run_table_dump_query(FILE *out, sqlite3 *db, const char *zSelect){
sqlite3_stmt *pSelect;
@@ -666,6 +744,19 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
fprintf(p->out, "ANALYZE sqlite_master;\n");
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
return 0;
+ }else if( strncmp(zSql, "CREATE VIRTUAL TABLE", 20)==0 ){
+ char *zIns;
+ if( !p->writableSchema ){
+ fprintf(p->out, "PRAGMA writable_schema=ON;\n");
+ p->writableSchema = 1;
+ }
+ zIns = sqlite3_mprintf(
+ "INSERT INTO sqlite_master(type,name,tbl_name,rootpage,sql)"
+ "VALUES('table','%q','%q',0,'%q');",
+ zTable, zTable, zSql);
+ fprintf(p->out, "%s\n", zIns);
+ sqlite3_free(zIns);
+ return 0;
}else{
fprintf(p->out, "%s;\n", zSql);
}
@@ -699,7 +790,7 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
zSelect = appendText(zSelect, zText, '"');
rc = sqlite3_step(pTableInfo);
if( rc==SQLITE_ROW ){
- zSelect = appendText(zSelect, ") || ', ' || ", 0);
+ zSelect = appendText(zSelect, ") || ',' || ", 0);
}else{
zSelect = appendText(zSelect, ") ", 0);
}
@@ -718,15 +809,14 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
rc = run_table_dump_query(p->out, p->db, zSelect);
}
if( zSelect ) free(zSelect);
- if( rc!=SQLITE_OK ){
- return 1;
- }
}
return 0;
}
/*
-** Run zQuery. Update dump_callback() as the callback routine.
+** Run zQuery. Use dump_callback() as the callback routine so that
+** the contents of the query are output as SQL statements.
+**
** If we get a SQLITE_CORRUPT error, rerun the query after appending
** "ORDER BY rowid DESC" to the end.
*/
@@ -754,6 +844,7 @@ static int run_schema_dump_query(
** Text of a help message
*/
static char zHelp[] =
+ ".bail ON|OFF Stop after hitting an error. Default OFF\n"
".databases List names and files of attached databases\n"
".dump ?TABLE? ... Dump the database in an SQL text format\n"
".echo ON|OFF Turn command echo on or off\n"
@@ -790,7 +881,7 @@ static char zHelp[] =
;
/* Forward reference */
-static void process_input(struct callback_data *p, FILE *in);
+static int process_input(struct callback_data *p, FILE *in);
/*
** Make sure the database is open. If it is not, then open it. If
@@ -851,10 +942,27 @@ static void resolve_backslashes(char *z){
}
/*
+** Interpret zArg as a boolean value. Return either 0 or 1.
+*/
+static int booleanValue(char *zArg){
+ int val = atoi(zArg);
+ int j;
+ for(j=0; zArg[j]; j++){
+ zArg[j] = tolower(zArg[j]);
+ }
+ if( strcmp(zArg,"on")==0 ){
+ val = 1;
+ }else if( strcmp(zArg,"yes")==0 ){
+ val = 1;
+ }
+ return val;
+}
+
+/*
** If an input line begins with "." then invoke this routine to
** process that line.
**
-** Return 1 to exit and 0 to continue.
+** Return 1 on error, 2 to exit, and 0 otherwise.
*/
static int do_meta_command(char *zLine, struct callback_data *p){
int i = 1;
@@ -889,6 +997,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( nArg==0 ) return rc;
n = strlen(azArg[0]);
c = azArg[0][0];
+ if( c=='b' && n>1 && strncmp(azArg[0], "bail", n)==0 && nArg>1 ){
+ bail_on_error = booleanValue(azArg[1]);
+ }else
+
if( c=='d' && n>1 && strncmp(azArg[0], "databases", n)==0 ){
struct callback_data data;
char *zErrMsg = 0;
@@ -911,14 +1023,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){
char *zErrMsg = 0;
open_db(p);
fprintf(p->out, "BEGIN TRANSACTION;\n");
+ p->writableSchema = 0;
if( nArg==1 ){
run_schema_dump_query(p,
"SELECT name, type, sql FROM sqlite_master "
"WHERE sql NOT NULL AND type=='table'", 0
);
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE sql NOT NULL AND type!='table' AND type!='meta'", 0
+ run_table_dump_query(p->out, p->db,
+ "SELECT sql FROM sqlite_master "
+ "WHERE sql NOT NULL AND type IN ('index','trigger','view')"
);
}else{
int i;
@@ -928,13 +1041,19 @@ static int do_meta_command(char *zLine, struct callback_data *p){
"SELECT name, type, sql FROM sqlite_master "
"WHERE tbl_name LIKE shellstatic() AND type=='table'"
" AND sql NOT NULL", 0);
- run_schema_dump_query(p,
- "SELECT name, type, sql FROM sqlite_master "
- "WHERE tbl_name LIKE shellstatic() AND type!='table'"
- " AND type!='meta' AND sql NOT NULL", 0);
+ run_table_dump_query(p->out, p->db,
+ "SELECT sql FROM sqlite_master "
+ "WHERE sql NOT NULL"
+ " AND type IN ('index','trigger','view')"
+ " AND tbl_name LIKE shellstatic()"
+ );
zShellStatic = 0;
}
}
+ if( p->writableSchema ){
+ fprintf(p->out, "PRAGMA writable_schema=OFF;\n");
+ p->writableSchema = 0;
+ }
if( zErrMsg ){
fprintf(stderr,"Error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
@@ -944,37 +1063,15 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}else
if( c=='e' && strncmp(azArg[0], "echo", n)==0 && nArg>1 ){
- int j;
- char *z = azArg[1];
- int val = atoi(azArg[1]);
- for(j=0; z[j]; j++){
- z[j] = tolower((unsigned char)z[j]);
- }
- if( strcmp(z,"on")==0 ){
- val = 1;
- }else if( strcmp(z,"yes")==0 ){
- val = 1;
- }
- p->echoOn = val;
+ p->echoOn = booleanValue(azArg[1]);
}else
if( c=='e' && strncmp(azArg[0], "exit", n)==0 ){
- rc = 1;
+ rc = 2;
}else
if( c=='e' && strncmp(azArg[0], "explain", n)==0 ){
- int j;
- static char zOne[] = "1";
- char *z = nArg>=2 ? azArg[1] : zOne;
- int val = atoi(z);
- for(j=0; z[j]; j++){
- z[j] = tolower((unsigned char)z[j]);
- }
- if( strcmp(z,"on")==0 ){
- val = 1;
- }else if( strcmp(z,"yes")==0 ){
- val = 1;
- }
+ int val = nArg>=2 ? booleanValue(azArg[1]) : 1;
if(val == 1) {
if(!p->explainPrev.valid) {
p->explainPrev.valid = 1;
@@ -1005,21 +1102,9 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
}else
- if( c=='h' && (strncmp(azArg[0], "header", n)==0
- ||
+ if( c=='h' && (strncmp(azArg[0], "header", n)==0 ||
strncmp(azArg[0], "headers", n)==0 )&& nArg>1 ){
- int j;
- char *z = azArg[1];
- int val = atoi(azArg[1]);
- for(j=0; z[j]; j++){
- z[j] = tolower((unsigned char)z[j]);
- }
- if( strcmp(z,"on")==0 ){
- val = 1;
- }else if( strcmp(z,"yes")==0 ){
- val = 1;
- }
- p->showHeader = val;
+ p->showHeader = booleanValue(azArg[1]);
}else
if( c=='h' && strncmp(azArg[0], "help", n)==0 ){
@@ -1056,6 +1141,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc ){
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
nCol = 0;
+ rc = 1;
}else{
nCol = sqlite3_column_count(pStmt);
}
@@ -1076,7 +1162,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc ){
fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db));
sqlite3_finalize(pStmt);
- return 0;
+ return 1;
}
in = fopen(zFile, "rb");
if( in==0 ){
@@ -1122,6 +1208,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc!=SQLITE_OK ){
fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db));
zCommit = "ROLLBACK";
+ rc = 1;
break;
}
}
@@ -1155,6 +1242,26 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
}else
+ if( c=='i' && strncmp(azArg[0], "iotrace", n)==0 ){
+ extern void (*sqlite3_io_trace)(const char*, ...);
+ if( iotrace && iotrace!=stdout ) fclose(iotrace);
+ iotrace = 0;
+ if( nArg<2 ){
+ sqlite3_io_trace = 0;
+ }else if( strcmp(azArg[1], "-")==0 ){
+ sqlite3_io_trace = iotracePrintf;
+ iotrace = stdout;
+ }else{
+ iotrace = fopen(azArg[1], "w");
+ if( iotrace==0 ){
+ fprintf(stderr, "cannot open \"%s\"\n", azArg[1]);
+ sqlite3_io_trace = 0;
+ }else{
+ sqlite3_io_trace = iotracePrintf;
+ }
+ }
+ }else
+
#ifndef SQLITE_OMIT_LOAD_EXTENSION
if( c=='l' && strncmp(azArg[0], "load", n)==0 && nArg>=2 ){
const char *zFile, *zProc;
@@ -1167,6 +1274,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
if( rc!=SQLITE_OK ){
fprintf(stderr, "%s\n", zErrMsg);
sqlite3_free(zErrMsg);
+ rc = 1;
}
}else
#endif
@@ -1201,7 +1309,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
set_table_name(p, "table");
}
}else {
- fprintf(stderr,"mode should be on of: "
+ fprintf(stderr,"mode should be one of: "
"column csv html insert line list tabs tcl\n");
}
}else
@@ -1238,7 +1346,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}else
if( c=='q' && strncmp(azArg[0], "quit", n)==0 ){
- rc = 1;
+ rc = 2;
}else
if( c=='r' && strncmp(azArg[0], "read", n)==0 && nArg==2 ){
@@ -1390,6 +1498,8 @@ static int do_meta_command(char *zLine, struct callback_data *p){
}
printf("\n");
}
+ }else{
+ rc = 1;
}
sqlite3_free_table(azResult);
}else
@@ -1469,24 +1579,40 @@ static int _is_command_terminator(const char *zLine){
** is coming from a file or device. A prompt is issued and history
** is saved only if input is interactive. An interrupt signal will
** cause this routine to exit immediately, unless input is interactive.
+**
+** Return the number of errors.
*/
-static void process_input(struct callback_data *p, FILE *in){
+static int process_input(struct callback_data *p, FILE *in){
char *zLine;
char *zSql = 0;
int nSql = 0;
char *zErrMsg;
int rc;
- while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){
+ int errCnt = 0;
+ int lineno = 0;
+ int startline = 0;
+
+ while( errCnt==0 || !bail_on_error || (in==0 && stdin_is_interactive) ){
+ fflush(p->out);
+ zLine = one_input_line(zSql, in);
+ if( zLine==0 ){
+ break; /* We have reached EOF */
+ }
if( seenInterrupt ){
if( in!=0 ) break;
seenInterrupt = 0;
}
+ lineno++;
if( p->echoOn ) printf("%s\n", zLine);
if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue;
if( zLine && zLine[0]=='.' && nSql==0 ){
- int rc = do_meta_command(zLine, p);
+ rc = do_meta_command(zLine, p);
free(zLine);
- if( rc ) break;
+ if( rc==2 ){
+ break;
+ }else if( rc ){
+ errCnt++;
+ }
continue;
}
if( _is_command_terminator(zLine) ){
@@ -1503,6 +1629,7 @@ static void process_input(struct callback_data *p, FILE *in){
exit(1);
}
strcpy(zSql, zLine);
+ startline = lineno;
}
}else{
int len = strlen(zLine);
@@ -1521,14 +1648,20 @@ static void process_input(struct callback_data *p, FILE *in){
open_db(p);
rc = sqlite3_exec(p->db, zSql, callback, p, &zErrMsg);
if( rc || zErrMsg ){
- /* if( in!=0 && !p->echoOn ) printf("%s\n",zSql); */
+ char zPrefix[100];
+ if( in!=0 || !stdin_is_interactive ){
+ sprintf(zPrefix, "SQL error near line %d:", startline);
+ }else{
+ sprintf(zPrefix, "SQL error:");
+ }
if( zErrMsg!=0 ){
- printf("SQL error: %s\n", zErrMsg);
+ printf("%s %s\n", zPrefix, zErrMsg);
sqlite3_free(zErrMsg);
zErrMsg = 0;
}else{
- printf("SQL error: %s\n", sqlite3_errmsg(p->db));
+ printf("%s %s\n", zPrefix, sqlite3_errmsg(p->db));
}
+ errCnt++;
}
free(zSql);
zSql = 0;
@@ -1539,6 +1672,7 @@ static void process_input(struct callback_data *p, FILE *in){
if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql);
free(zSql);
}
+ return errCnt;
}
/*
@@ -1563,16 +1697,30 @@ static char *find_home_dir(void){
home_dir = getcwd(home_path, _MAX_PATH);
#endif
+#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
+ if (!home_dir) {
+ home_dir = getenv("USERPROFILE");
+ }
+#endif
+
if (!home_dir) {
home_dir = getenv("HOME");
- if (!home_dir) {
- home_dir = getenv("HOMEPATH"); /* Windows? */
- }
}
#if defined(_WIN32) || defined(WIN32) || defined(__OS2__)
if (!home_dir) {
- home_dir = "c:";
+ char *zDrive, *zPath;
+ int n;
+ zDrive = getenv("HOMEDRIVE");
+ zPath = getenv("HOMEPATH");
+ if( zDrive && zPath ){
+ n = strlen(zDrive) + strlen(zPath) + 1;
+ home_dir = malloc( n );
+ if( home_dir==0 ) return 0;
+ sqlite3_snprintf(n, home_dir, "%s%s", zDrive, zPath);
+ return home_dir;
+ }
+ home_dir = "c:\\";
}
#endif
@@ -1615,7 +1763,7 @@ static void process_sqliterc(
}
in = fopen(sqliterc,"rb");
if( in ){
- if( isatty(fileno(stdout)) ){
+ if( stdin_is_interactive ){
printf("Loading resources from %s\n",sqliterc);
}
process_input(p,in);
@@ -1632,19 +1780,25 @@ static const char zOptions[] =
" -init filename read/process named file\n"
" -echo print commands before execution\n"
" -[no]header turn headers on or off\n"
+ " -bail stop after hitting an error\n"
+ " -interactive force interactive I/O\n"
+ " -batch force batch I/O\n"
" -column set output mode to 'column'\n"
+ " -csv set output mode to 'csv'\n"
" -html set output mode to HTML\n"
" -line set output mode to 'line'\n"
" -list set output mode to 'list'\n"
" -separator 'x' set output field separator (|)\n"
" -nullvalue 'text' set text string for NULL values\n"
" -version show SQLite version\n"
- " -help show this text, also show dot-commands\n"
;
static void usage(int showDetail){
- fprintf(stderr, "Usage: %s [OPTIONS] FILENAME [SQL]\n", Argv0);
+ fprintf(stderr,
+ "Usage: %s [OPTIONS] FILENAME [SQL]\n"
+ "FILENAME is the name of an SQLite database. A new database is created\n"
+ "if the file does not previously exist.\n", Argv0);
if( showDetail ){
- fprintf(stderr, "Options are:\n%s", zOptions);
+ fprintf(stderr, "OPTIONS include:\n%s", zOptions);
}else{
fprintf(stderr, "Use the -help option for additional information\n");
}
@@ -1669,6 +1823,7 @@ int main(int argc, char **argv){
const char *zInitFile = 0;
char *zFirstCmd = 0;
int i;
+ int rc = 0;
#ifdef __MACOS__
argc = ccommand(&argv);
@@ -1676,6 +1831,7 @@ int main(int argc, char **argv){
Argv0 = argv[0];
main_init(&data);
+ stdin_is_interactive = isatty(0);
/* Make sure we have a valid signal handler early, before anything
** else is done.
@@ -1689,15 +1845,15 @@ int main(int argc, char **argv){
** and the first command to execute.
*/
for(i=1; i<argc-1; i++){
+ char *z;
if( argv[i][0]!='-' ) break;
+ z = argv[i];
+ if( z[0]=='-' && z[1]=='-' ) z++;
if( strcmp(argv[i],"-separator")==0 || strcmp(argv[i],"-nullvalue")==0 ){
i++;
}else if( strcmp(argv[i],"-init")==0 ){
i++;
zInitFile = argv[i];
- }else if( strcmp(argv[i],"-key")==0 ){
- i++;
- data.zKey = sqlite3_mprintf("%s",argv[i]);
}
}
if( i<argc ){
@@ -1743,7 +1899,8 @@ int main(int argc, char **argv){
*/
for(i=1; i<argc && argv[i][0]=='-'; i++){
char *z = argv[i];
- if( strcmp(z,"-init")==0 || strcmp(z,"-key")==0 ){
+ if( z[1]=='-' ){ z++; }
+ if( strcmp(z,"-init")==0 ){
i++;
}else if( strcmp(z,"-html")==0 ){
data.mode = MODE_Html;
@@ -1753,6 +1910,9 @@ int main(int argc, char **argv){
data.mode = MODE_Line;
}else if( strcmp(z,"-column")==0 ){
data.mode = MODE_Column;
+ }else if( strcmp(z,"-csv")==0 ){
+ data.mode = MODE_Csv;
+ strcpy(data.separator,",");
}else if( strcmp(z,"-separator")==0 ){
i++;
sprintf(data.separator,"%.*s",(int)sizeof(data.separator)-1,argv[i]);
@@ -1765,10 +1925,16 @@ int main(int argc, char **argv){
data.showHeader = 0;
}else if( strcmp(z,"-echo")==0 ){
data.echoOn = 1;
+ }else if( strcmp(z,"-bail")==0 ){
+ bail_on_error = 1;
}else if( strcmp(z,"-version")==0 ){
printf("%s\n", sqlite3_libversion());
return 0;
- }else if( strcmp(z,"-help")==0 ){
+ }else if( strcmp(z,"-interactive")==0 ){
+ stdin_is_interactive = 1;
+ }else if( strcmp(z,"-batch")==0 ){
+ stdin_is_interactive = 0;
+ }else if( strcmp(z,"-help")==0 || strcmp(z, "--help")==0 ){
usage(1);
}else{
fprintf(stderr,"%s: unknown option: %s\n", Argv0, z);
@@ -1795,7 +1961,7 @@ int main(int argc, char **argv){
}else{
/* Run commands received from standard input
*/
- if( isatty(fileno(stdout)) && isatty(fileno(stdin)) ){
+ if( stdin_is_interactive ){
char *zHome;
char *zHistory = 0;
printf(
@@ -1810,7 +1976,7 @@ int main(int argc, char **argv){
#if defined(HAVE_READLINE) && HAVE_READLINE==1
if( zHistory ) read_history(zHistory);
#endif
- process_input(&data, 0);
+ rc = process_input(&data, 0);
if( zHistory ){
stifle_history(100);
write_history(zHistory);
@@ -1818,7 +1984,7 @@ int main(int argc, char **argv){
}
free(zHome);
}else{
- process_input(&data, stdin);
+ rc = process_input(&data, stdin);
}
}
set_table_name(&data, 0);
@@ -1827,5 +1993,5 @@ int main(int argc, char **argv){
fprintf(stderr,"error closing database: %s\n", sqlite3_errmsg(db));
}
}
- return 0;
+ return rc;
}
diff --git a/ext/pdo_sqlite/sqlite/src/sqlite.h.in b/ext/pdo_sqlite/sqlite/src/sqlite.h.in
index a1b4759f8..8478cc27a 100644
--- a/ext/pdo_sqlite/sqlite/src/sqlite.h.in
+++ b/ext/pdo_sqlite/sqlite/src/sqlite.h.in
@@ -125,7 +125,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** value then the query is aborted, all subsequent SQL statements
** are skipped and the sqlite3_exec() function returns the SQLITE_ABORT.
**
-** The 4th parameter is an arbitrary pointer that is passed
+** The 1st parameter is an arbitrary pointer that is passed
** to the callback function as its first parameter.
**
** The 2nd parameter to the callback function is the number of
@@ -182,7 +182,7 @@ int sqlite3_exec(
#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
#define SQLITE_FULL 13 /* Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
-#define SQLITE_PROTOCOL 15 /* Database lock protocol error */
+#define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */
#define SQLITE_EMPTY 16 /* Database is empty */
#define SQLITE_SCHEMA 17 /* The database schema changed */
#define SQLITE_TOOBIG 18 /* NOT USED. Too much data for one row */
@@ -199,27 +199,70 @@ int sqlite3_exec(
/* end-of-error-codes */
/*
+** Using the sqlite3_extended_result_codes() API, you can cause
+** SQLite to return result codes with additional information in
+** their upper bits. The lower 8 bits will be the same as the
+** primary result codes above. But the upper bits might contain
+** more specific error information.
+**
+** To extract the primary result code from an extended result code,
+** simply mask off the lower 8 bits.
+**
+** primary = extended & 0xff;
+**
+** New result error codes may be added from time to time. Software
+** that uses the extended result codes should plan accordingly and be
+** sure to always handle new unknown codes gracefully.
+**
+** The SQLITE_OK result code will never be extended. It will always
+** be exactly zero.
+**
+** The extended result codes always have the primary result code
+** as a prefix. Primary result codes only contain a single "_"
+** character. Extended result codes contain two or more "_" characters.
+*/
+#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
+#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
+#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
+#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8))
+#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8))
+#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8))
+#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8))
+#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8))
+#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8))
+#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8))
+
+/*
+** Enable or disable the extended result codes.
+*/
+int sqlite3_extended_result_codes(sqlite3*, int onoff);
+
+/*
** Each entry in an SQLite table has a unique integer key. (The key is
** the value of the INTEGER PRIMARY KEY column if there is such a column,
-** otherwise the key is generated at random. The unique key is always
+** otherwise the key is generated automatically. The unique key is always
** available as the ROWID, OID, or _ROWID_ column.) The following routine
** returns the integer key of the most recent insert in the database.
-**
-** This function is similar to the mysql_insert_id() function from MySQL.
*/
sqlite_int64 sqlite3_last_insert_rowid(sqlite3*);
/*
** This function returns the number of database rows that were changed
-** (or inserted or deleted) by the most recent called sqlite3_exec().
+** (or inserted or deleted) by the most recent SQL statement. Only
+** changes that are directly specified by the INSERT, UPDATE, or
+** DELETE statement are counted. Auxiliary changes caused by
+** triggers are not counted. Within the body of a trigger, however,
+** the sqlite3_changes() API can be called to find the number of
+** changes in the most recently completed INSERT, UPDATE, or DELETE
+** statement within the body of the trigger.
**
** All changes are counted, even if they were later undone by a
** ROLLBACK or ABORT. Except, changes associated with creating and
** dropping tables are not counted.
**
-** If a callback invokes sqlite3_exec() recursively, then the changes
-** in the inner, recursive call are counted together with the changes
-** in the outer call.
+** If a callback invokes sqlite3_exec() or sqlite3_step() recursively,
+** then the changes in the inner, recursive call are counted together
+** with the changes in the outer call.
**
** SQLite implements the command "DELETE FROM table" without a WHERE clause
** by dropping and recreating the table. (This is much faster than going
@@ -254,6 +297,9 @@ int sqlite3_total_changes(sqlite3*);
** called in response to a user action such as pressing "Cancel"
** or Ctrl-C where the user wants a long query operation to halt
** immediately.
+**
+** It is safe to call this routine from a different thread that the
+** thread that is currently running the database operation.
*/
void sqlite3_interrupt(sqlite3*);
@@ -264,9 +310,13 @@ void sqlite3_interrupt(sqlite3*);
** sqlite3_complete16(), a nul-terminated machine byte order UTF-16 string
** is required.
**
-** The algorithm is simple. If the last token other than spaces
-** and comments is a semicolon, then return true. otherwise return
-** false.
+** This routine is useful for command-line input to see of the user has
+** entered a complete statement of SQL or if the current statement needs
+** to be continued on the next line. The algorithm is simple. If the
+** last token other than spaces and comments is a semicolon, then return
+** true. Actually, the algorithm is a little more complicated than that
+** in order to deal with triggers, but the basic idea is the same: the
+** statement is not complete unless it ends in a semicolon.
*/
int sqlite3_complete(const char *sql);
int sqlite3_complete16(const void *sql);
@@ -277,13 +327,30 @@ int sqlite3_complete16(const void *sql);
** currently locked by another process or thread. If the busy callback
** is NULL, then sqlite3_exec() returns SQLITE_BUSY immediately if
** it finds a locked table. If the busy callback is not NULL, then
-** sqlite3_exec() invokes the callback with three arguments. The
-** second argument is the name of the locked table and the third
-** argument is the number of times the table has been busy. If the
+** sqlite3_exec() invokes the callback with two arguments. The
+** first argument to the handler is a copy of the void* pointer which
+** is the third argument to this routine. The second argument to
+** the handler is the number of times that the busy handler has
+** been invoked for this locking event. If the
** busy callback returns 0, then sqlite3_exec() immediately returns
** SQLITE_BUSY. If the callback returns non-zero, then sqlite3_exec()
** tries to open the table again and the cycle repeats.
**
+** The presence of a busy handler does not guarantee that
+** it will be invoked when there is lock contention.
+** If SQLite determines that invoking the busy handler could result in
+** a deadlock, it will return SQLITE_BUSY instead.
+** Consider a scenario where one process is holding a read lock that
+** it is trying to promote to a reserved lock and
+** a second process is holding a reserved lock that it is trying
+** to promote to an exclusive lock. The first process cannot proceed
+** because it is blocked by the second and the second process cannot
+** proceed because it is blocked by the first. If both processes
+** invoke the busy handlers, neither will make any progress. Therefore,
+** SQLite returns SQLITE_BUSY for the first process, hoping that this
+** will induce the first process to release its read lock and allow
+** the second process to proceed.
+**
** The default busy callback is NULL.
**
** Sqlite is re-entrant, so the busy handler may start a new query.
@@ -478,6 +545,7 @@ int sqlite3_set_authorizer(
#define SQLITE_ANALYZE 28 /* Table Name NULL */
#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */
#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */
+#define SQLITE_FUNCTION 31 /* Function Name NULL */
/*
** The return value of the authorization function should be one of the
@@ -654,6 +722,31 @@ int sqlite3_prepare16(
);
/*
+** Newer versions of the prepare API work just like the legacy versions
+** but with one exception: The a copy of the SQL text is saved in the
+** sqlite3_stmt structure that is returned. If this copy exists, it
+** modifieds the behavior of sqlite3_step() slightly. First, sqlite3_step()
+** will no longer return an SQLITE_SCHEMA error but will instead automatically
+** rerun the compiler to rebuild the prepared statement. Secondly,
+** sqlite3_step() now turns a full result code - the result code that
+** use used to have to call sqlite3_reset() to get.
+*/
+int sqlite3_prepare_v2(
+ sqlite3 *db, /* Database handle */
+ const char *zSql, /* SQL statement, UTF-8 encoded */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
+ const char **pzTail /* OUT: Pointer to unused portion of zSql */
+);
+int sqlite3_prepare16_v2(
+ sqlite3 *db, /* Database handle */
+ const void *zSql, /* SQL statement, UTF-16 encoded */
+ int nBytes, /* Length of zSql in bytes. */
+ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
+ const void **pzTail /* OUT: Pointer to unused portion of zSql */
+);
+
+/*
** Pointers to the following two opaque structures are used to communicate
** with the implementations of user-defined functions.
*/
@@ -662,31 +755,32 @@ typedef struct Mem sqlite3_value;
/*
** In the SQL strings input to sqlite3_prepare() and sqlite3_prepare16(),
-** one or more literals can be replace by parameters "?" or ":AAA" or
-** "$VVV" where AAA is an identifer and VVV is a variable name according
-** to the syntax rules of the TCL programming language.
-** The value of these parameters (also called "host parameter names") can
-** be set using the routines listed below.
-**
-** In every case, the first parameter is a pointer to the sqlite3_stmt
-** structure returned from sqlite3_prepare(). The second parameter is the
-** index of the parameter. The first parameter as an index of 1. For
-** named parameters (":AAA" or "$VVV") you can use
+** one or more literals can be replace by parameters "?" or "?NNN" or
+** ":AAA" or "@AAA" or "$VVV" where NNN is a integer, AAA is an identifer,
+** and VVV is a variable name according to the syntax rules of the
+** TCL programming language. The value of these parameters (also called
+** "host parameter names") can be set using the routines listed below.
+**
+** In every case, the first argument is a pointer to the sqlite3_stmt
+** structure returned from sqlite3_prepare(). The second argument is the
+** index of the host parameter name. The first host parameter as an index
+** of 1. For named host parameters (":AAA" or "$VVV") you can use
** sqlite3_bind_parameter_index() to get the correct index value given
-** the parameters name. If the same named parameter occurs more than
+** the parameter name. If the same named parameter occurs more than
** once, it is assigned the same index each time.
**
-** The fifth parameter to sqlite3_bind_blob(), sqlite3_bind_text(), and
+** The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
** text after SQLite has finished with it. If the fifth argument is the
** special value SQLITE_STATIC, then the library assumes that the information
** is in static, unmanaged space and does not need to be freed. If the
** fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its
-** own private copy of the data.
+** own private copy of the data before the sqlite3_bind_* routine returns.
**
-** The sqlite3_bind_* routine must be called before sqlite3_step() after
-** an sqlite3_prepare() or sqlite3_reset(). Unbound parameterss are
-** interpreted as NULL.
+** The sqlite3_bind_* routine must be called before sqlite3_step() and after
+** an sqlite3_prepare() or sqlite3_reset(). Bindings persist across
+** multiple calls to sqlite3_reset() and sqlite3_step(). Unbound parameters
+** are interpreted as NULL.
*/
int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
int sqlite3_bind_double(sqlite3_stmt*, int, double);
@@ -698,13 +792,13 @@ int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
/*
-** Return the number of parameters in a compiled SQL statement. This
+** Return the number of host parameters in a compiled SQL statement. This
** routine was added to support DBD::SQLite.
*/
int sqlite3_bind_parameter_count(sqlite3_stmt*);
/*
-** Return the name of the i-th parameter. Ordinary parameters "?" are
+** Return the name of the i-th name parameter. Ordinary parameters "?" are
** nameless and a NULL is returned. For parameters of the form :AAA or
** $VVV the complete text of the parameter name is returned, including
** the initial ":" or "$". NULL is returned if the index is out of range.
@@ -740,7 +834,7 @@ const char *sqlite3_column_name(sqlite3_stmt*,int);
const void *sqlite3_column_name16(sqlite3_stmt*,int);
/*
-** The first parameter to the following calls is a compiled SQL statement.
+** The first argument to the following calls is a compiled SQL statement.
** These functions return information about the Nth column returned by
** the statement, where N is the second function argument.
**
@@ -1104,9 +1198,13 @@ void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
** SQLITE_TRANSIENT value means that the content will likely change in
** the near future and that SQLite should make its own private copy of
** the content before returning.
+**
+** The typedef is necessary to work around problems in certain
+** C++ compilers. See ticket #2191.
*/
-#define SQLITE_STATIC ((void(*)(void *))0)
-#define SQLITE_TRANSIENT ((void(*)(void *))-1)
+typedef void (*sqlite3_destructor_type)(void*);
+#define SQLITE_STATIC ((sqlite3_destructor_type)0)
+#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1)
/*
** User-defined functions invoke the following routines in order to
@@ -1520,6 +1618,42 @@ int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
/*
****** EXPERIMENTAL - subject to change without notice **************
**
+** Register an extension entry point that is automatically invoked
+** whenever a new database connection is opened.
+**
+** This API can be invoked at program startup in order to register
+** one or more statically linked extensions that will be available
+** to all new database connections.
+**
+** Duplicate extensions are detected so calling this routine multiple
+** times with the same extension is harmless.
+**
+** This routine stores a pointer to the extension in an array
+** that is obtained from malloc(). If you run a memory leak
+** checker on your program and it reports a leak because of this
+** array, then invoke sqlite3_automatic_extension_reset() prior
+** to shutdown to free the memory.
+**
+** Automatic extensions apply across all threads.
+*/
+int sqlite3_auto_extension(void *xEntryPoint);
+
+
+/*
+****** EXPERIMENTAL - subject to change without notice **************
+**
+** Disable all previously registered automatic extensions. This
+** routine undoes the effect of all prior sqlite3_automatic_extension()
+** calls.
+**
+** This call disabled automatic extensions in all threads.
+*/
+void sqlite3_reset_auto_extension(void);
+
+
+/*
+****** EXPERIMENTAL - subject to change without notice **************
+**
** The interface to the virtual-table mechanism is currently considered
** to be experimental. The interface might change in incompatible ways.
** If this is a problem for you, do not use the interface at this time.
@@ -1544,11 +1678,11 @@ typedef struct sqlite3_module sqlite3_module;
struct sqlite3_module {
int iVersion;
int (*xCreate)(sqlite3*, void *pAux,
- int argc, char **argv,
- sqlite3_vtab **ppVTab);
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVTab, char**);
int (*xConnect)(sqlite3*, void *pAux,
- int argc, char **argv,
- sqlite3_vtab **ppVTab);
+ int argc, const char *const*argv,
+ sqlite3_vtab **ppVTab, char**);
int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
int (*xDisconnect)(sqlite3_vtab *pVTab);
int (*xDestroy)(sqlite3_vtab *pVTab);
@@ -1668,10 +1802,21 @@ int sqlite3_create_module(
** be taylored to the specific needs of the module implementation. The
** purpose of this superclass is to define certain fields that are common
** to all module implementations.
+**
+** Virtual tables methods can set an error message by assigning a
+** string obtained from sqlite3_mprintf() to zErrMsg. The method should
+** take care that any prior string is freed by a call to sqlite3_free()
+** prior to assigning a new string to zErrMsg. After the error message
+** is delivered up to the client application, the string will be automatically
+** freed by sqlite3_free() and the zErrMsg field will be zeroed. Note
+** that sqlite3_mprintf() and sqlite3_free() are used on the zErrMsg field
+** since virtual tables are commonly implemented in loadable extensions which
+** do not have access to sqlite3MPrintf() or sqlite3Free().
*/
struct sqlite3_vtab {
const sqlite3_module *pModule; /* The module for this virtual table */
int nRef; /* Used internally */
+ char *zErrMsg; /* Error message from sqlite3_mprintf() */
/* Virtual table implementations will typically add additional fields */
};
@@ -1697,6 +1842,24 @@ struct sqlite3_vtab_cursor {
int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable);
/*
+** Virtual tables can provide alternative implementations of functions
+** using the xFindFunction method. But global versions of those functions
+** must exist in order to be overloaded.
+**
+** This API makes sure a global version of a function with a particular
+** name and number of parameters exists. If no such function exists
+** before this API is called, a new function is created. The implementation
+** of the new function always causes an exception to be thrown. So
+** the new function is not good for anything by itself. Its only
+** purpose is to be a place-holder function that can be overloaded
+** by virtual tables.
+**
+** This API should be considered part of the virtual table interface,
+** which is experimental and subject to change.
+*/
+int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
+
+/*
** The interface to the virtual-table mechanism defined above (back up
** to a comment remarkably similar to this one) is currently considered
** to be experimental. The interface might change in incompatible ways.
diff --git a/ext/pdo_sqlite/sqlite/src/sqlite3ext.h b/ext/pdo_sqlite/sqlite/src/sqlite3ext.h
index 948206066..145b084db 100644
--- a/ext/pdo_sqlite/sqlite/src/sqlite3ext.h
+++ b/ext/pdo_sqlite/sqlite/src/sqlite3ext.h
@@ -15,11 +15,11 @@
** as extensions by SQLite should #include this file instead of
** sqlite3.h.
**
-** @(#) $Id: sqlite3ext.h,v 1.1.2.1 2006/08/14 16:15:29 iliaa Exp $
+** @(#) $Id: sqlite3ext.h,v 1.1.2.3 2007/04/09 16:35:11 iliaa Exp $
*/
#ifndef _SQLITE3EXT_H_
#define _SQLITE3EXT_H_
-#include <sqlite3.h>
+#include "sqlite3.h"
typedef struct sqlite3_api_routines sqlite3_api_routines;
@@ -92,7 +92,7 @@ struct sqlite3_api_routines {
void * (*get_auxdata)(sqlite3_context*,int);
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
int (*global_recover)(void);
- void (*interrupt)(sqlite3*);
+ void (*interruptx)(sqlite3*);
sqlite_int64 (*last_insert_rowid)(sqlite3*);
const char * (*libversion)(void);
int (*libversion_number)(void);
@@ -142,7 +142,11 @@ struct sqlite3_api_routines {
const void * (*value_text16be)(sqlite3_value*);
const void * (*value_text16le)(sqlite3_value*);
int (*value_type)(sqlite3_value*);
- char * (*vmprintf)(const char*,va_list);
+ char *(*vmprintf)(const char*,va_list);
+ int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
+ int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
+ int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
+ int (*clear_bindings)(sqlite3_stmt*);
};
/*
@@ -221,7 +225,7 @@ struct sqlite3_api_routines {
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
#define sqlite3_get_table sqlite3_api->get_table
#define sqlite3_global_recover sqlite3_api->global_recover
-#define sqlite3_interrupt sqlite3_api->interrupt
+#define sqlite3_interrupt sqlite3_api->interruptx
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
#define sqlite3_libversion sqlite3_api->libversion
#define sqlite3_libversion_number sqlite3_api->libversion_number
@@ -231,6 +235,8 @@ struct sqlite3_api_routines {
#define sqlite3_open16 sqlite3_api->open16
#define sqlite3_prepare sqlite3_api->prepare
#define sqlite3_prepare16 sqlite3_api->prepare16
+#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
+#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
#define sqlite3_profile sqlite3_api->profile
#define sqlite3_progress_handler sqlite3_api->progress_handler
#define sqlite3_realloc sqlite3_api->realloc
@@ -272,6 +278,10 @@ struct sqlite3_api_routines {
#define sqlite3_value_text16le sqlite3_api->value_text16le
#define sqlite3_value_type sqlite3_api->value_type
#define sqlite3_vmprintf sqlite3_api->vmprintf
+#define sqlite3_overload_function sqlite3_api->overload_function
+#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
+#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
+#define sqlite3_clear_bindings sqlite3_api->clear_bindings
#endif /* SQLITE_CORE */
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api;
diff --git a/ext/pdo_sqlite/sqlite/src/sqliteInt.h b/ext/pdo_sqlite/sqlite/src/sqliteInt.h
index 58e21c4f3..15a27efb3 100644
--- a/ext/pdo_sqlite/sqlite/src/sqliteInt.h
+++ b/ext/pdo_sqlite/sqlite/src/sqliteInt.h
@@ -16,11 +16,8 @@
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
-/*
-** Extra interface definitions for those who need them
-*/
-#ifdef SQLITE_EXTRA
-# include "sqliteExtra.h"
+#if defined(SQLITE_TCL) || defined(TCLSH)
+# include <tcl.h>
#endif
/*
@@ -215,8 +212,15 @@ typedef UINT8_TYPE i8; /* 1-byte signed integer */
** evaluated at runtime.
*/
extern const int sqlite3one;
-#define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
-#define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
+#if defined(i386) || defined(__i386__) || defined(_M_IX86)
+# define SQLITE_BIGENDIAN 0
+# define SQLITE_LITTLEENDIAN 1
+# define SQLITE_UTF16NATIVE SQLITE_UTF16LE
+#else
+# define SQLITE_BIGENDIAN (*(char *)(&sqlite3one)==0)
+# define SQLITE_LITTLEENDIAN (*(char *)(&sqlite3one)==1)
+# define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
+#endif
/*
** An instance of the following structure is used to store the busy-handler
@@ -377,6 +381,14 @@ struct Db {
/*
** An instance of the following structure stores a database schema.
+**
+** If there are no virtual tables configured in this schema, the
+** Schema.db variable is set to NULL. After the first virtual table
+** has been added, it is set to point to the database connection
+** used to create the connection. Once a virtual table has been
+** added to the Schema structure and the Schema.db variable populated,
+** only that database connection may use the Schema to prepare
+** statements.
*/
struct Schema {
int schema_cookie; /* Database schema version number for this file */
@@ -389,6 +401,9 @@ struct Schema {
u8 enc; /* Text encoding used by this database */
u16 flags; /* Flags associated with this schema */
int cache_size; /* Number of pages to use in the cache */
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ sqlite3 *db; /* "Owner" connection. See comment above */
+#endif
};
/*
@@ -414,7 +429,6 @@ struct Schema {
#define DB_UnresetViews 0x0002 /* Some views have defined column names */
#define DB_Empty 0x0004 /* The file is empty (length 0 bytes) */
-#define SQLITE_UTF16NATIVE (SQLITE_BIGENDIAN?SQLITE_UTF16BE:SQLITE_UTF16LE)
/*
** Each database is an instance of the following structure.
@@ -447,6 +461,7 @@ struct sqlite3 {
Db *aDb; /* All backends */
int flags; /* Miscellanous flags. See below */
int errCode; /* Most recent error code (SQLITE_*) */
+ int errMask; /* & result codes with this before returning */
u8 autoCommit; /* The auto-commit flag. */
u8 temp_store; /* 1: file 2: memory 0: default */
int nTable; /* Number of tables in the database */
@@ -462,7 +477,7 @@ struct sqlite3 {
u8 busy; /* TRUE if currently initializing */
} init;
int nExtension; /* Number of loaded extensions */
- void *aExtension; /* Array of shared libraray handles */
+ void **aExtension; /* Array of shared libraray handles */
struct Vdbe *pVdbe; /* List of active virtual machines */
int activeVdbeCnt; /* Number of vdbes currently executing */
void (*xTrace)(void*,const char*); /* Trace function */
@@ -509,6 +524,7 @@ struct sqlite3 {
#ifdef SQLITE_SSE
sqlite3_stmt *pFetch; /* Used by SSE to fetch stored statements */
#endif
+ u8 dfltLockMode; /* Default locking-mode for attached dbs */
};
/*
@@ -544,6 +560,8 @@ struct sqlite3 {
#define SQLITE_FullFSync 0x00010000 /* Use full fsync on the backend */
#define SQLITE_LoadExtension 0x00020000 /* Enable load_extension */
+#define SQLITE_RecoveryMode 0x00040000 /* Ignore schema errors */
+
/*
** Possible values for the sqlite.magic field.
** The numbers are obtained at random and have no special meaning, other
@@ -921,6 +939,7 @@ struct AggInfo {
ExprList *pGroupBy; /* The group by clause */
int nSortingColumn; /* Number of columns in the sorting index */
struct AggInfo_col { /* For each column used in source tables */
+ Table *pTab; /* Source table */
int iTable; /* Cursor number of the source table */
int iColumn; /* Column number within the source table */
int iSorterColumn; /* Column number in the sorting index */
@@ -1020,6 +1039,7 @@ struct Expr {
#define EP_VarSelect 0x20 /* pSelect is correlated, not constant */
#define EP_Dequoted 0x40 /* True if the string has been dequoted */
#define EP_InfixFunc 0x80 /* True for an infix function: LIKE, GLOB, etc */
+#define EP_ExpCollate 0x100 /* Collating sequence specified explicitly */
/*
** These macros can be used to test, set, or clear bits in the
@@ -1077,8 +1097,12 @@ struct IdList {
/*
** The bitmask datatype defined below is used for various optimizations.
+**
+** Changing this from a 64-bit to a 32-bit type limits the number of
+** tables in a join to 32 instead of 64. But it also reduces the size
+** of the library by 738 bytes on ix86.
*/
-typedef unsigned int Bitmask;
+typedef u64 Bitmask;
/*
** The following structure describes the FROM clause of a SELECT statement.
@@ -1090,6 +1114,11 @@ typedef unsigned int Bitmask;
** is modified by an INSERT, DELETE, or UPDATE statement. In standard SQL,
** such a table must be a simple name: ID. But in SQLite, the table can
** now be identified by a database name, a dot, then the table name: ID.ID.
+**
+** The jointype starts out showing the join type between the current table
+** and the next table on the list. The parser builds the list this way.
+** But sqlite3SrcListShiftJoinType() later shifts the jointypes so that each
+** jointype expresses the join between the table and the previous table.
*/
struct SrcList {
i16 nSrc; /* Number of tables or subqueries in the FROM clause */
@@ -1101,8 +1130,8 @@ struct SrcList {
Table *pTab; /* An SQL table corresponding to zName */
Select *pSelect; /* A SELECT statement used in place of a table name */
u8 isPopulated; /* Temporary table associated with SELECT is populated */
- u8 jointype; /* Type of join between this table and the next */
- i16 iCursor; /* The VDBE cursor number used to access this table */
+ u8 jointype; /* Type of join between this able and the previous */
+ int iCursor; /* The VDBE cursor number used to access this table */
Expr *pOn; /* The ON clause of a join */
IdList *pUsing; /* The USING clause of a join */
Bitmask colUsed; /* Bit N (1<<N) set if column N or pTab is used */
@@ -1148,12 +1177,16 @@ struct WhereLevel {
int iTabCur; /* The VDBE cursor used to access the table */
int iIdxCur; /* The VDBE cursor used to acesss pIdx */
int brk; /* Jump here to break out of the loop */
+ int nxt; /* Jump here to start the next IN combination */
int cont; /* Jump here to continue with the next loop cycle */
int top; /* First instruction of interior of the loop */
int op, p1, p2; /* Opcode used to terminate the loop */
int nEq; /* Number of == or IN constraints on this loop */
int nIn; /* Number of IN operators constraining this loop */
- int *aInLoop; /* Loop terminators for IN operators */
+ struct InLoop {
+ int iCur; /* The VDBE cursor used by this IN operator */
+ int topAddr; /* Top of the IN loop */
+ } *aInLoop; /* Information about each nested IN operator */
sqlite3_index_info *pBestIdx; /* Index information for this level */
/* The following field is really not part of the current level. But
@@ -1244,6 +1277,7 @@ struct Select {
u8 isAgg; /* True if this is an aggregate query */
u8 usesEphm; /* True if uses an OpenEphemeral opcode */
u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */
+ char affinity; /* MakeRecord with this affinity for SRT_Set */
SrcList *pSrc; /* The FROM clause */
Expr *pWhere; /* The WHERE clause */
ExprList *pGroupBy; /* The GROUP BY clause */
@@ -1360,6 +1394,7 @@ struct AuthContext {
#define OPFLAG_NCHANGE 1 /* Set to update db->nChange */
#define OPFLAG_LASTROWID 2 /* Set to update db->lastRowid */
#define OPFLAG_ISUPDATE 4 /* This OP_Insert is an sql UPDATE */
+#define OPFLAG_APPEND 8 /* This is likely to be an append */
/*
* Each trigger present in the database schema is stored as an instance of
@@ -1384,7 +1419,6 @@ struct Trigger {
Expr *pWhen; /* The WHEN clause of the expresion (may be NULL) */
IdList *pColumns; /* If this is an UPDATE OF <column-list> trigger,
the <column-list> is stored here */
- int foreach; /* One of TK_ROW or TK_STATEMENT */
Token nameToken; /* Token containing zName. Use during parsing only */
Schema *pSchema; /* Schema containing the trigger */
Schema *pTabSchema; /* Schema containing the table */
@@ -1512,6 +1546,7 @@ struct DbFixer {
*/
typedef struct {
sqlite3 *db; /* The database being initialized */
+ int iDb; /* 0 for main database. 1 for TEMP, 2.. for ATTACHed */
char **pzErrMsg; /* Error message stored here */
int rc; /* Result code stored here */
} InitData;
@@ -1554,7 +1589,7 @@ void *sqlite3Realloc(void*,int);
char *sqlite3StrDup(const char*);
char *sqlite3StrNDup(const char*, int);
# define sqlite3CheckMemory(a,b)
-void sqlite3ReallocOrFree(void**,int);
+void *sqlite3ReallocOrFree(void*,int);
void sqlite3FreeX(void*);
void *sqlite3MallocX(int);
int sqlite3AllocSize(void *);
@@ -1586,7 +1621,6 @@ int sqlite3InitCallback(void*, int, char**, char**);
void sqlite3Pragma(Parse*,Token*,Token*,Token*,int);
void sqlite3ResetInternalSchema(sqlite3*, int);
void sqlite3BeginParse(Parse*,int);
-void sqlite3RollbackInternalChanges(sqlite3*);
void sqlite3CommitInternalChanges(sqlite3*);
Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*);
void sqlite3OpenMasterTable(Parse *, int);
@@ -1600,7 +1634,7 @@ void sqlite3AddDefaultValue(Parse*,Expr*);
void sqlite3AddCollateType(Parse*, const char*, int);
void sqlite3EndTable(Parse*,Token*,Token*,Select*);
-void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
+void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int,int);
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE)
int sqlite3ViewGetColumnNames(Parse*,Table*);
@@ -1609,13 +1643,15 @@ void sqlite3CreateView(Parse*,Token*,Token*,Token*,Select*,int);
#endif
void sqlite3DropTable(Parse*, SrcList*, int, int);
-void sqlite3DeleteTable(sqlite3*, Table*);
+void sqlite3DeleteTable(Table*);
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
-int sqlite3ArrayAllocate(void**,int,int);
+void *sqlite3ArrayAllocate(void*,int,int,int*,int*,int*);
IdList *sqlite3IdListAppend(IdList*, Token*);
int sqlite3IdListIndex(IdList*,const char*);
SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*);
-void sqlite3SrcListAddAlias(SrcList*, Token*);
+SrcList *sqlite3SrcListAppendFromTerm(SrcList*, Token*, Token*, Token*,
+ Select*, Expr*, IdList*);
+void sqlite3SrcListShiftJoinType(SrcList*);
void sqlite3SrcListAssignCursors(Parse*, SrcList*);
void sqlite3IdListDelete(IdList*);
void sqlite3SrcListDelete(SrcList*);
@@ -1636,6 +1672,7 @@ void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, ExprList**);
void sqlite3WhereEnd(WhereInfo*);
+void sqlite3ExprCodeGetColumn(Vdbe*, Table*, int, int);
void sqlite3ExprCode(Parse*, Expr*);
void sqlite3ExprCodeAndCache(Parse*, Expr*);
int sqlite3ExprCodeExprList(Parse*, ExprList*);
@@ -1672,7 +1709,7 @@ void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int);
void sqlite3GenerateRowIndexDelete(Vdbe*, Table*, int, char*);
void sqlite3GenerateIndexKey(Vdbe*, Index*, int);
void sqlite3GenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
-void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int);
+void sqlite3CompleteInsertion(Parse*, Table*, int, char*, int, int, int, int);
void sqlite3OpenTableAndIndices(Parse*, Table*, int, int);
void sqlite3BeginWriteOperation(Parse*, int, int);
Expr *sqlite3ExprDup(Expr*);
@@ -1691,9 +1728,9 @@ void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
#ifndef SQLITE_OMIT_TRIGGER
void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
- int,Expr*,int);
+ Expr*,int, int);
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
- void sqlite3DropTrigger(Parse*, SrcList*);
+ void sqlite3DropTrigger(Parse*, SrcList*, int);
void sqlite3DropTriggerPtr(Parse*, Trigger*);
int sqlite3TriggersExist(Parse*, Table*, int, ExprList*);
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
@@ -1764,6 +1801,7 @@ int sqlite3ReadSchema(Parse *pParse);
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char *,int,int);
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName);
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
+Expr *sqlite3ExprSetColl(Parse *pParse, Expr *, Token *);
int sqlite3CheckCollSeq(Parse *, CollSeq *);
int sqlite3CheckIndexCollSeq(Parse *, Index *);
int sqlite3CheckObjectName(Parse *, const char *);
@@ -1821,8 +1859,10 @@ int sqlite3OpenTempDatabase(Parse *);
#ifndef SQLITE_OMIT_LOAD_EXTENSION
void sqlite3CloseExtensions(sqlite3*);
+ int sqlite3AutoLoadExtensions(sqlite3*);
#else
# define sqlite3CloseExtensions(X)
+# define sqlite3AutoLoadExtensions(X) SQLITE_OK
#endif
#ifndef SQLITE_OMIT_SHARED_CACHE
@@ -1860,6 +1900,8 @@ int sqlite3OpenTempDatabase(Parse *);
int sqlite3VtabRollback(sqlite3 *db);
int sqlite3VtabCommit(sqlite3 *db);
#endif
+void sqlite3VtabLock(sqlite3_vtab*);
+void sqlite3VtabUnlock(sqlite3*, sqlite3_vtab*);
void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*);
void sqlite3VtabFinishParse(Parse*, Token*);
void sqlite3VtabArgInit(Parse*);
@@ -1869,9 +1911,25 @@ int sqlite3VtabCallConnect(Parse*, Table*);
int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *);
FuncDef *sqlite3VtabOverloadFunction(FuncDef*, int nArg, Expr*);
+void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
+int sqlite3Reprepare(Vdbe*);
#ifdef SQLITE_SSE
#include "sseInt.h"
#endif
+/*
+** If the SQLITE_ENABLE IOTRACE exists then the global variable
+** sqlite3_io_trace is a pointer to a printf-like routine used to
+** print I/O tracing messages.
+*/
+#ifdef SQLITE_ENABLE_IOTRACE
+# define IOTRACE(A) if( sqlite3_io_trace ){ sqlite3_io_trace A; }
+ void sqlite3VdbeIOTraceSql(Vdbe*);
+#else
+# define IOTRACE(A)
+# define sqlite3VdbeIOTraceSql(X)
+#endif
+extern void (*sqlite3_io_trace)(const char*,...);
+
#endif
diff --git a/ext/pdo_sqlite/sqlite/src/table.c b/ext/pdo_sqlite/sqlite/src/table.c
index c4e228361..30c148489 100644
--- a/ext/pdo_sqlite/sqlite/src/table.c
+++ b/ext/pdo_sqlite/sqlite/src/table.c
@@ -146,7 +146,7 @@ int sqlite3_get_table(
assert( sizeof(res.azResult[0])>= sizeof(res.nData) );
res.azResult[0] = (char*)res.nData;
}
- if( rc==SQLITE_ABORT ){
+ if( (rc&0xff)==SQLITE_ABORT ){
sqlite3_free_table(&res.azResult[1]);
if( res.zErrMsg ){
if( pzErrMsg ){
@@ -156,12 +156,12 @@ int sqlite3_get_table(
sqliteFree(res.zErrMsg);
}
db->errCode = res.rc;
- return res.rc;
+ return res.rc & db->errMask;
}
sqliteFree(res.zErrMsg);
if( rc!=SQLITE_OK ){
sqlite3_free_table(&res.azResult[1]);
- return rc;
+ return rc & db->errMask;
}
if( res.nAlloc>res.nData ){
char **azNew;
@@ -176,7 +176,7 @@ int sqlite3_get_table(
*pazResult = &res.azResult[1];
if( pnColumn ) *pnColumn = res.nColumn;
if( pnRow ) *pnRow = res.nRow;
- return rc;
+ return rc & db->errMask;
}
/*
diff --git a/ext/pdo_sqlite/sqlite/src/tclsqlite.c b/ext/pdo_sqlite/sqlite/src/tclsqlite.c
index 8572b7cf6..4e30bd298 100644
--- a/ext/pdo_sqlite/sqlite/src/tclsqlite.c
+++ b/ext/pdo_sqlite/sqlite/src/tclsqlite.c
@@ -9,19 +9,25 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** A TCL Interface to SQLite
+** A TCL Interface to SQLite. Append this file to sqlite3.c and
+** compile the whole thing to build a TCL-enabled version of SQLite.
**
** $Id$
*/
-#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
-
-#include "sqliteInt.h"
-#include "hash.h"
#include "tcl.h"
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
+
+/*
+** Some additional include files are needed if this file is not
+** appended to the amalgamation.
+*/
+#ifndef SQLITE_AMALGAMATION
+# include "sqliteInt.h"
+# include "hash.h"
+# include <stdlib.h>
+# include <string.h>
+# include <assert.h>
+# include <ctype.h>
+#endif
/*
* Windows needs to know which symbols to export. Unix does not.
@@ -553,6 +559,7 @@ static int auth_callback(
case SQLITE_ANALYZE : zCode="SQLITE_ANALYZE"; break;
case SQLITE_CREATE_VTABLE : zCode="SQLITE_CREATE_VTABLE"; break;
case SQLITE_DROP_VTABLE : zCode="SQLITE_DROP_VTABLE"; break;
+ case SQLITE_FUNCTION : zCode="SQLITE_FUNCTION"; break;
default : zCode="????"; break;
}
Tcl_DStringInit(&str);
@@ -1035,7 +1042,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
nSep = strlen(zSep);
nNull = strlen(zNull);
if( nSep==0 ){
- Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0);
+ Tcl_AppendResult(interp,"Error: non-null separator required for copy",0);
return TCL_ERROR;
}
if(sqlite3StrICmp(zConflict, "rollback") != 0 &&
@@ -1054,7 +1061,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
return TCL_ERROR;
}
nByte = strlen(zSql);
- rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
+ rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
sqlite3_free(zSql);
if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
@@ -1080,7 +1087,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
zSql[j++] = ')';
zSql[j] = 0;
- rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
+ rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
free(zSql);
if( rc ){
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
@@ -1172,6 +1179,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
** default.
*/
case DB_ENABLE_LOAD_EXTENSION: {
+#ifndef SQLITE_OMIT_LOAD_EXTENSION
int onoff;
if( objc!=3 ){
Tcl_WrongNumArgs(interp, 2, objv, "BOOLEAN");
@@ -1182,6 +1190,11 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
sqlite3_enable_load_extension(pDb->db, onoff);
break;
+#else
+ Tcl_AppendResult(interp, "extension loading is turned off at compile-time",
+ 0);
+ return TCL_ERROR;
+#endif
}
/*
@@ -2001,6 +2014,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
const char *zArg;
char *zErrMsg;
const char *zFile;
+ Tcl_DString translatedFilename;
if( objc==2 ){
zArg = Tcl_GetStringFromObj(objv[1], 0);
if( strcmp(zArg,"-version")==0 ){
@@ -2049,9 +2063,11 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}
memset(p, 0, sizeof(*p));
zFile = Tcl_GetStringFromObj(objv[2], 0);
+ zFile = Tcl_TranslateFileName(interp, zFile, &translatedFilename);
sqlite3_open(zFile, &p->db);
+ Tcl_DStringFree(&translatedFilename);
if( SQLITE_OK!=sqlite3_errcode(p->db) ){
- zErrMsg = strdup(sqlite3_errmsg(p->db));
+ zErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(p->db));
sqlite3_close(p->db);
p->db = 0;
}
@@ -2061,10 +2077,11 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
if( p->db==0 ){
Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE);
Tcl_Free((char*)p);
- free(zErrMsg);
+ sqlite3_free(zErrMsg);
return TCL_ERROR;
}
p->maxStmt = NUM_PREPARED_STMTS;
+ p->interp = interp;
zArg = Tcl_GetStringFromObj(objv[1], 0);
Tcl_CreateObjCommand(interp, zArg, DbObjCmd, (char*)p, DbDeleteCmd);
@@ -2084,7 +2101,6 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
#endif
}
#endif
- p->interp = interp;
return TCL_OK;
}
@@ -2195,11 +2211,14 @@ int TCLSH_MAIN(int argc, char **argv){
extern int Sqlitetest6_Init(Tcl_Interp*);
extern int Sqlitetest7_Init(Tcl_Interp*);
extern int Sqlitetest8_Init(Tcl_Interp*);
+ extern int Sqlitetest9_Init(Tcl_Interp*);
extern int Md5_Init(Tcl_Interp*);
extern int Sqlitetestsse_Init(Tcl_Interp*);
extern int Sqlitetestasync_Init(Tcl_Interp*);
extern int Sqlitetesttclvar_Init(Tcl_Interp*);
extern int Sqlitetestschema_Init(Tcl_Interp*);
+ extern int Sqlitetest_autoext_Init(Tcl_Interp*);
+ extern int Sqlitetest_hexio_Init(Tcl_Interp*);
Sqlitetest1_Init(interp);
Sqlitetest2_Init(interp);
@@ -2209,9 +2228,12 @@ int TCLSH_MAIN(int argc, char **argv){
Sqlitetest6_Init(interp);
Sqlitetest7_Init(interp);
Sqlitetest8_Init(interp);
+ Sqlitetest9_Init(interp);
Sqlitetestasync_Init(interp);
Sqlitetesttclvar_Init(interp);
Sqlitetestschema_Init(interp);
+ Sqlitetest_autoext_Init(interp);
+ Sqlitetest_hexio_Init(interp);
Md5_Init(interp);
#ifdef SQLITE_SSE
Sqlitetestsse_Init(interp);
@@ -2220,6 +2242,9 @@ int TCLSH_MAIN(int argc, char **argv){
#endif
if( argc>=2 || TCLSH==2 ){
int i;
+ char zArgc[32];
+ sqlite3_snprintf(sizeof(zArgc), zArgc, "%d", argc-(3-TCLSH));
+ Tcl_SetVar(interp,"argc", zArgc, TCL_GLOBAL_ONLY);
Tcl_SetVar(interp,"argv0",argv[1],TCL_GLOBAL_ONLY);
Tcl_SetVar(interp,"argv", "", TCL_GLOBAL_ONLY);
for(i=3-TCLSH; i<argc; i++){
@@ -2239,5 +2264,3 @@ int TCLSH_MAIN(int argc, char **argv){
return 0;
}
#endif /* TCLSH */
-
-#endif /* !defined(NO_TCL) */
diff --git a/ext/pdo_sqlite/sqlite/src/test1.c b/ext/pdo_sqlite/sqlite/src/test1.c
index fd474b276..7448de0e6 100644
--- a/ext/pdo_sqlite/sqlite/src/test1.c
+++ b/ext/pdo_sqlite/sqlite/src/test1.c
@@ -63,9 +63,25 @@ static int get_sqlite_pointer(
return TCL_OK;
}
+/*
+** Decode a pointer to an sqlite3 object.
+*/
+static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
+ struct SqliteDb *p;
+ Tcl_CmdInfo cmdInfo;
+ if( Tcl_GetCommandInfo(interp, zA, &cmdInfo) ){
+ p = (struct SqliteDb*)cmdInfo.objClientData;
+ *ppDb = p->db;
+ }else{
+ *ppDb = (sqlite3*)sqlite3TextToPtr(zA);
+ }
+ return TCL_OK;
+}
+
+
const char *sqlite3TestErrorName(int rc){
const char *zName = 0;
- switch( rc ){
+ switch( rc & 0xff ){
case SQLITE_OK: zName = "SQLITE_OK"; break;
case SQLITE_ERROR: zName = "SQLITE_ERROR"; break;
case SQLITE_PERM: zName = "SQLITE_PERM"; break;
@@ -96,7 +112,7 @@ const char *sqlite3TestErrorName(int rc){
}
return zName;
}
-#define errorName sqlite3TestErrorName
+#define t1ErrorName sqlite3TestErrorName
/*
** Convert an sqlite3_stmt* into an sqlite3*. This depends on the
@@ -113,7 +129,7 @@ int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){
char zBuf[200];
int r2 = sqlite3_errcode(db);
sprintf(zBuf, "error code %s (%d) does not match sqlite3_errcode %s (%d)",
- errorName(rc), rc, errorName(r2), r2);
+ t1ErrorName(rc), rc, t1ErrorName(r2), r2);
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, zBuf, 0);
return 1;
@@ -122,14 +138,6 @@ int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){
}
/*
-** Decode a pointer to an sqlite3 object.
-*/
-static int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb){
- *ppDb = (sqlite3*)sqlite3TextToPtr(zA);
- return TCL_OK;
-}
-
-/*
** Decode a pointer to an sqlite3_stmt object.
*/
static int getStmtPointer(
@@ -190,6 +198,57 @@ static int exec_printf_cb(void *pArg, int argc, char **argv, char **name){
}
/*
+** The I/O tracing callback.
+*/
+static FILE *iotrace_file = 0;
+static void io_trace_callback(const char *zFormat, ...){
+ va_list ap;
+ va_start(ap, zFormat);
+ vfprintf(iotrace_file, zFormat, ap);
+ va_end(ap);
+ fflush(iotrace_file);
+}
+
+/*
+** Usage: io_trace FILENAME
+**
+** Turn I/O tracing on or off. If FILENAME is not an empty string,
+** I/O tracing begins going into FILENAME. If FILENAME is an empty
+** string, I/O tracing is turned off.
+*/
+static int test_io_trace(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " FILENAME\"", 0);
+ return TCL_ERROR;
+ }
+ if( iotrace_file ){
+ if( iotrace_file!=stdout && iotrace_file!=stderr ){
+ fclose(iotrace_file);
+ }
+ iotrace_file = 0;
+ sqlite3_io_trace = 0;
+ }
+ if( argv[1][0] ){
+ if( strcmp(argv[1],"stdout")==0 ){
+ iotrace_file = stdout;
+ }else if( strcmp(argv[1],"stderr")==0 ){
+ iotrace_file = stderr;
+ }else{
+ iotrace_file = fopen(argv[1], "w");
+ }
+ sqlite3_io_trace = io_trace_callback;
+ }
+ return SQLITE_OK;
+}
+
+
+/*
** Usage: sqlite3_exec_printf DB FORMAT STRING
**
** Invoke the sqlite3_exec_printf() interface using the open database
@@ -228,6 +287,65 @@ static int test_exec_printf(
}
/*
+** Usage: sqlite3_exec DB SQL
+**
+** Invoke the sqlite3_exec interface using the open database DB
+*/
+static int test_exec(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ sqlite3 *db;
+ Tcl_DString str;
+ int rc;
+ char *zErr = 0;
+ char zBuf[30];
+ if( argc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " DB SQL", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+ Tcl_DStringInit(&str);
+ rc = sqlite3_exec(db, argv[2], exec_printf_cb, &str, &zErr);
+ sprintf(zBuf, "%d", rc);
+ Tcl_AppendElement(interp, zBuf);
+ Tcl_AppendElement(interp, rc==SQLITE_OK ? Tcl_DStringValue(&str) : zErr);
+ Tcl_DStringFree(&str);
+ if( zErr ) sqlite3_free(zErr);
+ if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_exec_nr DB SQL
+**
+** Invoke the sqlite3_exec interface using the open database DB. Discard
+** all results
+*/
+static int test_exec_nr(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ sqlite3 *db;
+ int rc;
+ char *zErr = 0;
+ if( argc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " DB SQL", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+ rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
+ if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_mprintf_z_test SEPARATOR ARG0 ARG1 ...
**
** Test the %z format of sqliteMPrintf(). Use multiple mprintf() calls to
@@ -423,7 +541,7 @@ static int sqlite_test_close(
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_close(db);
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_OK;
}
@@ -431,7 +549,11 @@ static int sqlite_test_close(
** Implementation of the x_coalesce() function.
** Return the first argument non-NULL argument.
*/
-static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
+static void t1_ifnullFunc(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
int i;
for(i=0; i<argc; i++){
if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
@@ -443,6 +565,34 @@ static void ifnullFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
}
/*
+** These are test functions. hex8() interprets its argument as
+** UTF8 and returns a hex encoding. hex16le() interprets its argument
+** as UTF16le and returns a hex encoding.
+*/
+static void hex8Func(sqlite3_context *p, int argc, sqlite3_value **argv){
+ const unsigned char *z;
+ int i;
+ char zBuf[200];
+ z = sqlite3_value_text(argv[0]);
+ for(i=0; i<sizeof(zBuf)/2 - 2 && z[i]; i++){
+ sprintf(&zBuf[i*2], "%02x", z[i]&0xff);
+ }
+ zBuf[i*2] = 0;
+ sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
+}
+static void hex16Func(sqlite3_context *p, int argc, sqlite3_value **argv){
+ const unsigned short int *z;
+ int i;
+ char zBuf[400];
+ z = sqlite3_value_text16(argv[0]);
+ for(i=0; i<sizeof(zBuf)/4 - 4 && z[i]; i++){
+ sprintf(&zBuf[i*4], "%04x", z[i]&0xff);
+ }
+ zBuf[i*4] = 0;
+ sqlite3_result_text(p, (char*)zBuf, -1, SQLITE_TRANSIENT);
+}
+
+/*
** A structure into which to accumulate text.
*/
struct dstr {
@@ -516,6 +666,46 @@ static void sqlite3ExecFunc(
}
/*
+** Implementation of tkt2213func(), a scalar function that takes exactly
+** one argument. It has two interesting features:
+**
+** * It calls sqlite3_value_text() 3 times on the argument sqlite3_value*.
+** If the three pointers returned are not the same an SQL error is raised.
+**
+** * Otherwise it returns a copy of the text representation of it's
+** argument in such a way as the VDBE representation is a Mem* cell
+** with the MEM_Term flag clear.
+**
+** Ticket #2213 can therefore be tested by evaluating the following
+** SQL expression:
+**
+** tkt2213func(tkt2213func('a string'));
+*/
+static void tkt2213Function(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ int nText;
+ unsigned char const *zText1;
+ unsigned char const *zText2;
+ unsigned char const *zText3;
+
+ nText = sqlite3_value_bytes(argv[0]);
+ zText1 = sqlite3_value_text(argv[0]);
+ zText2 = sqlite3_value_text(argv[0]);
+ zText3 = sqlite3_value_text(argv[0]);
+
+ if( zText1!=zText2 || zText2!=zText3 ){
+ sqlite3_result_error(context, "tkt2213 is not fixed", -1);
+ }else{
+ char *zCopy = (char *)sqlite3_malloc(nText);
+ memcpy(zCopy, zText1, nText);
+ sqlite3_result_text(context, zCopy, nText, sqlite3_free);
+ }
+}
+
+/*
** Usage: sqlite_test_create_function DB
**
** Call the sqlite3_create_function API on the given database in order
@@ -547,7 +737,19 @@ static int test_create_function(
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, "x_coalesce", -1, SQLITE_ANY, 0,
- ifnullFunc, 0, 0);
+ t1_ifnullFunc, 0, 0);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "hex8", 1, SQLITE_ANY, 0,
+ hex8Func, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "hex16", 1, SQLITE_ANY, 0,
+ hex16Func, 0, 0);
+ }
+ if( rc==SQLITE_OK ){
+ rc = sqlite3_create_function(db, "tkt2213func", 1, SQLITE_ANY, 0,
+ tkt2213Function, 0, 0);
+ }
#ifndef SQLITE_OMIT_UTF16
/* Use the sqlite3_create_function16() API here. Mainly for fun, but also
@@ -569,7 +771,7 @@ static int test_create_function(
#endif
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
- Tcl_SetResult(interp, (char *)errorName(rc), 0);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
return TCL_OK;
}
@@ -584,12 +786,16 @@ static int test_create_function(
** is reported on the step function. If the total count is 42, then
** a UTF-8 error is reported on the finalize function.
*/
-typedef struct CountCtx CountCtx;
-struct CountCtx {
+typedef struct t1CountCtx t1CountCtx;
+struct t1CountCtx {
int n;
};
-static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
- CountCtx *p;
+static void t1CountStep(
+ sqlite3_context *context,
+ int argc,
+ sqlite3_value **argv
+){
+ t1CountCtx *p;
p = sqlite3_aggregate_context(context, sizeof(*p));
if( (argc==0 || SQLITE_NULL!=sqlite3_value_type(argv[0]) ) && p ){
p->n++;
@@ -606,8 +812,8 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
}
}
}
-static void countFinalize(sqlite3_context *context){
- CountCtx *p;
+static void t1CountFinalize(sqlite3_context *context){
+ t1CountCtx *p;
p = sqlite3_aggregate_context(context, sizeof(*p));
if( p ){
if( p->n==42 ){
@@ -647,16 +853,40 @@ static int test_create_aggregate(
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, "x_count", 0, SQLITE_UTF8, 0, 0,
- countStep,countFinalize);
+ t1CountStep,t1CountFinalize);
if( rc==SQLITE_OK ){
sqlite3_create_function(db, "x_count", 1, SQLITE_UTF8, 0, 0,
- countStep,countFinalize);
+ t1CountStep,t1CountFinalize);
}
if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
return TCL_OK;
}
+/*
+** Usage: printf TEXT
+**
+** Send output to printf. Use this rather than puts to merge the output
+** in the correct sequence with debugging printfs inserted into C code.
+** Puts uses a separate buffer and debugging statements will be out of
+** sequence if it is used.
+*/
+static int test_printf(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ if( argc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " TEXT\"", 0);
+ return TCL_ERROR;
+ }
+ printf("%s\n", argv[1]);
+ return TCL_OK;
+}
+
+
/*
** Usage: sqlite3_mprintf_int FORMAT INTEGER INTEGER INTEGER
@@ -756,6 +986,40 @@ static int sqlite3_mprintf_str(
}
/*
+** Usage: sqlite3_snprintf_str INTEGER FORMAT INTEGER INTEGER STRING
+**
+** Call mprintf with two integer arguments and one string argument
+*/
+static int sqlite3_snprintf_str(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ char **argv /* Text of each argument */
+){
+ int a[3], i;
+ int n;
+ char *z;
+ if( argc<5 || argc>6 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " INT FORMAT INT INT ?STRING?\"", 0);
+ return TCL_ERROR;
+ }
+ if( Tcl_GetInt(interp, argv[1], &n) ) return TCL_ERROR;
+ if( n<0 ){
+ Tcl_AppendResult(interp, "N must be non-negative", 0);
+ return TCL_ERROR;
+ }
+ for(i=3; i<5; i++){
+ if( Tcl_GetInt(interp, argv[i], &a[i-3]) ) return TCL_ERROR;
+ }
+ z = sqlite3_malloc( n+1 );
+ sqlite3_snprintf(n, z, argv[2], a[0], a[1], argc>4 ? argv[5] : NULL);
+ Tcl_AppendResult(interp, z, 0);
+ sqlite3_free(z);
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE
**
** Call mprintf with two integer arguments and one double argument
@@ -1026,6 +1290,29 @@ static int test_enable_shared(
#endif
/*
+** Usage: sqlite3_extended_result_codes DB BOOLEAN
+**
+*/
+static int test_extended_result_codes(
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ int enable;
+ sqlite3 *db;
+
+ if( objc!=3 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB BOOLEAN");
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ if( Tcl_GetBooleanFromObj(interp, objv[2], &enable) ) return TCL_ERROR;
+ sqlite3_extended_result_codes(db, enable);
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_libversion_number
**
*/
@@ -1289,7 +1576,7 @@ static int test_finalize(
){
sqlite3_stmt *pStmt;
int rc;
- sqlite3 *db;
+ sqlite3 *db = 0;
if( objc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
@@ -1303,7 +1590,7 @@ static int test_finalize(
db = StmtToDb(pStmt);
}
rc = sqlite3_finalize(pStmt);
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
if( db && sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
return TCL_OK;
}
@@ -1334,7 +1621,7 @@ static int test_reset(
if( pStmt && sqlite3TestErrCode(interp, StmtToDb(pStmt), rc) ){
return TCL_ERROR;
}
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
/*
if( rc ){
return TCL_ERROR;
@@ -1417,6 +1704,7 @@ static int test_changes(
** the FLAG option of sqlite3_bind is "static"
*/
static char *sqlite_static_bind_value = 0;
+static int sqlite_static_bind_nbyte = 0;
/*
** Usage: sqlite3_bind VM IDX VALUE FLAGS
@@ -1449,6 +1737,9 @@ static int test_bind(
rc = sqlite3_bind_null(pStmt, idx);
}else if( strcmp(argv[4],"static")==0 ){
rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value, -1, 0);
+ }else if( strcmp(argv[4],"static-nbytes")==0 ){
+ rc = sqlite3_bind_text(pStmt, idx, sqlite_static_bind_value,
+ sqlite_static_bind_nbyte, 0);
}else if( strcmp(argv[4],"normal")==0 ){
rc = sqlite3_bind_text(pStmt, idx, argv[3], -1, SQLITE_TRANSIENT);
}else if( strcmp(argv[4],"blob10")==0 ){
@@ -1854,7 +2145,7 @@ static int test_errstr(
zCode = Tcl_GetString(objv[1]);
for(i=0; i<200; i++){
- if( 0==strcmp(errorName(i), zCode) ) break;
+ if( 0==strcmp(t1ErrorName(i), zCode) ) break;
}
Tcl_SetResult(interp, (char *)sqlite3ErrStr(i), 0);
return TCL_OK;
@@ -2291,6 +2582,8 @@ static int test_errcode(
Tcl_Obj *CONST objv[]
){
sqlite3 *db;
+ int rc;
+ char zBuf[30];
if( objc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
@@ -2298,7 +2591,13 @@ static int test_errcode(
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
- Tcl_SetResult(interp, (char *)errorName(sqlite3_errcode(db)), 0);
+ rc = sqlite3_errcode(db);
+ if( (rc&0xff)==rc ){
+ zBuf[0] = 0;
+ }else{
+ sprintf(zBuf,"+%d", rc>>8);
+ }
+ Tcl_AppendResult(interp, (char *)t1ErrorName(rc), zBuf, 0);
return TCL_OK;
}
@@ -2418,7 +2717,60 @@ static int test_prepare(
}
/*
-** Usage: sqlite3_prepare DB sql bytes tailvar
+** Usage: sqlite3_prepare_v2 DB sql bytes tailvar
+**
+** Compile up to <bytes> bytes of the supplied SQL string <sql> using
+** database handle <DB>. The parameter <tailval> is the name of a global
+** variable that is set to the unused portion of <sql> (if any). A
+** STMT handle is returned.
+*/
+static int test_prepare_v2(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db;
+ const char *zSql;
+ int bytes;
+ const char *zTail = 0;
+ sqlite3_stmt *pStmt = 0;
+ char zBuf[50];
+ int rc;
+
+ if( objc!=5 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ zSql = Tcl_GetString(objv[2]);
+ if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
+
+ rc = sqlite3_prepare_v2(db, zSql, bytes, &pStmt, &zTail);
+ if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+ if( zTail ){
+ if( bytes>=0 ){
+ bytes = bytes - (zTail-zSql);
+ }
+ Tcl_ObjSetVar2(interp, objv[4], 0, Tcl_NewStringObj(zTail, bytes), 0);
+ }
+ if( rc!=SQLITE_OK ){
+ assert( pStmt==0 );
+ sprintf(zBuf, "(%d) ", rc);
+ Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0);
+ return TCL_ERROR;
+ }
+
+ if( pStmt ){
+ if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
+ Tcl_AppendResult(interp, zBuf, 0);
+ }
+ return TCL_OK;
+}
+
+/*
+** Usage: sqlite3_prepare16 DB sql bytes tailvar
**
** Compile up to <bytes> bytes of the supplied SQL string <sql> using
** database handle <DB>. The parameter <tailval> is the name of a global
@@ -2476,6 +2828,64 @@ static int test_prepare16(
}
/*
+** Usage: sqlite3_prepare16_v2 DB sql bytes tailvar
+**
+** Compile up to <bytes> bytes of the supplied SQL string <sql> using
+** database handle <DB>. The parameter <tailval> is the name of a global
+** variable that is set to the unused portion of <sql> (if any). A
+** STMT handle is returned.
+*/
+static int test_prepare16_v2(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+#ifndef SQLITE_OMIT_UTF16
+ sqlite3 *db;
+ const void *zSql;
+ const void *zTail = 0;
+ Tcl_Obj *pTail = 0;
+ sqlite3_stmt *pStmt = 0;
+ char zBuf[50];
+ int rc;
+ int bytes; /* The integer specified as arg 3 */
+ int objlen; /* The byte-array length of arg 2 */
+
+ if( objc!=5 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetString(objv[0]), " DB sql bytes tailvar", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ zSql = Tcl_GetByteArrayFromObj(objv[2], &objlen);
+ if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR;
+
+ rc = sqlite3_prepare16_v2(db, zSql, bytes, &pStmt, &zTail);
+ if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR;
+ if( rc ){
+ return TCL_ERROR;
+ }
+
+ if( zTail ){
+ objlen = objlen - ((u8 *)zTail-(u8 *)zSql);
+ }else{
+ objlen = 0;
+ }
+ pTail = Tcl_NewByteArrayObj((u8 *)zTail, objlen);
+ Tcl_IncrRefCount(pTail);
+ Tcl_ObjSetVar2(interp, objv[4], 0, pTail, 0);
+ Tcl_DecrRefCount(pTail);
+
+ if( pStmt ){
+ if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR;
+ }
+ Tcl_AppendResult(interp, zBuf, 0);
+#endif /* SQLITE_OMIT_UTF16 */
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_open filename ?options-list?
*/
static int test_open(
@@ -2583,7 +2993,7 @@ static int test_step(
rc = sqlite3_step(pStmt);
/* if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR; */
- Tcl_SetResult(interp, (char *)errorName(rc), 0);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), 0);
return TCL_OK;
}
@@ -2820,7 +3230,7 @@ static int test_global_recover(
return TCL_ERROR;
}
rc = sqlite3_global_recover();
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
#endif
return TCL_OK;
}
@@ -2918,7 +3328,7 @@ static int test_sqlite3OsOpenReadWrite(
rc = sqlite3OsOpenReadWrite(Tcl_GetString(objv[1]), &pFile, &dummy);
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
sqlite3TestMakePointerStr(interp, zBuf, pFile);
@@ -2949,7 +3359,7 @@ static int test_sqlite3OsClose(
}
rc = sqlite3OsClose(&pFile);
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
@@ -2997,7 +3407,7 @@ static int test_sqlite3OsLock(
}
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
@@ -3026,7 +3436,7 @@ static int test_sqlite3OsUnlock(
}
rc = sqlite3OsUnlock(pFile, NO_LOCK);
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
@@ -3046,7 +3456,7 @@ static int test_sqlite3OsTempFileName(
rc = sqlite3OsTempFileName(zFile);
if( rc!=SQLITE_OK ){
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
Tcl_AppendResult(interp, zFile, 0);
@@ -3175,7 +3585,7 @@ static int delete_function(
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_function(db, argv[2], -1, SQLITE_UTF8, 0, 0, 0, 0);
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_OK;
}
@@ -3201,7 +3611,7 @@ static int delete_collation(
}
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
rc = sqlite3_create_collation(db, argv[2], SQLITE_UTF8, 0, 0);
- Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
+ Tcl_SetResult(interp, (char *)t1ErrorName(rc), TCL_STATIC);
return TCL_OK;
}
@@ -3392,6 +3802,44 @@ static int test_thread_cleanup(
/*
+** Usage: sqlite3_pager_refcounts DB
+**
+** Return a list of numbers which are the PagerRefcount for all
+** pagers on each database connection.
+*/
+static int test_pager_refcounts(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ sqlite3 *db;
+ int i;
+ int v, *a;
+ Tcl_Obj *pResult;
+
+ if( objc!=2 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"",
+ Tcl_GetStringFromObj(objv[0], 0), " DB", 0);
+ return TCL_ERROR;
+ }
+ if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+ pResult = Tcl_NewObj();
+ for(i=0; i<db->nDb; i++){
+ if( db->aDb[i].pBt==0 ){
+ v = -1;
+ }else{
+ a = sqlite3PagerStats(sqlite3BtreePager(db->aDb[i].pBt));
+ v = a[0];
+ }
+ Tcl_ListObjAppendElement(0, pResult, Tcl_NewIntObj(v));
+ }
+ Tcl_SetObjResult(interp, pResult);
+ return TCL_OK;
+}
+
+
+/*
** This routine sets entries in the global ::sqlite_options() array variable
** according to the compile-time configuration of the database. Test
** procedures use this to determine when tests should be omitted.
@@ -3433,6 +3881,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "analyze", "1", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_OMIT_ATTACH
+ Tcl_SetVar2(interp, "sqlite_options", "attach", "0", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "attach", "1", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_AUTHORIZATION
Tcl_SetVar2(interp, "sqlite_options", "auth", "0", TCL_GLOBAL_ONLY);
#else
@@ -3540,6 +3994,18 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "foreignkey", "1", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_ENABLE_FTS1
+ Tcl_SetVar2(interp, "sqlite_options", "fts1", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "fts1", "0", TCL_GLOBAL_ONLY);
+#endif
+
+#ifdef SQLITE_ENABLE_FTS2
+ Tcl_SetVar2(interp, "sqlite_options", "fts2", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "fts2", "0", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_GLOBALRECOVER
Tcl_SetVar2(interp, "sqlite_options", "globalrecover", "0", TCL_GLOBAL_ONLY);
#else
@@ -3564,6 +4030,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "like_opt", "1", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_OMIT_LOAD_EXTENSION
+ Tcl_SetVar2(interp, "sqlite_options", "load_ext", "0", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "load_ext", "1", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_OMIT_MEMORYDB
Tcl_SetVar2(interp, "sqlite_options", "memorydb", "0", TCL_GLOBAL_ONLY);
#else
@@ -3679,7 +4151,7 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "utf16", "1", TCL_GLOBAL_ONLY);
#endif
-#ifdef SQLITE_OMIT_VACUUM
+#if defined(SQLITE_OMIT_VACUUM) || defined(SQLITE_OMIT_ATTACH)
Tcl_SetVar2(interp, "sqlite_options", "vacuum", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "vacuum", "1", TCL_GLOBAL_ONLY);
@@ -3696,8 +4168,56 @@ static void set_options(Tcl_Interp *interp){
#else
Tcl_SetVar2(interp, "sqlite_options", "vtab", "1", TCL_GLOBAL_ONLY);
#endif
+
+#ifdef SQLITE_DEFAULT_FILE_FORMAT
+ Tcl_ObjSetVar2(interp,
+ Tcl_NewStringObj("sqlite_default_file_format", -1), 0,
+ Tcl_NewIntObj(SQLITE_DEFAULT_FILE_FORMAT), TCL_GLOBAL_ONLY
+ );
+#endif
+#ifdef SQLITE_MAX_PAGE_SIZE
+ Tcl_ObjSetVar2(interp,
+ Tcl_NewStringObj("SQLITE_MAX_PAGE_SIZE", -1), 0,
+ Tcl_NewIntObj(SQLITE_MAX_PAGE_SIZE), TCL_GLOBAL_ONLY
+ );
+#endif
+#ifdef TEMP_STORE
+ Tcl_ObjSetVar2(interp,
+ Tcl_NewStringObj("TEMP_STORE", -1), 0,
+ Tcl_NewIntObj(TEMP_STORE), TCL_GLOBAL_ONLY
+ );
+#endif
+}
+
+/*
+** tclcmd: working_64bit_int
+**
+** Some TCL builds (ex: cygwin) do not support 64-bit integers. This
+** leads to a number of test failures. The present command checks the
+** TCL build to see whether or not it supports 64-bit integers. It
+** returns TRUE if it does and FALSE if not.
+**
+** This command is used to warn users that their TCL build is defective
+** and that the errors they are seeing in the test scripts might be
+** a result of their defective TCL rather than problems in SQLite.
+*/
+static int working_64bit_int(
+ ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int objc, /* Number of arguments */
+ Tcl_Obj *CONST objv[] /* Command arguments */
+){
+ Tcl_Obj *pTestObj;
+ int working = 0;
+
+ pTestObj = Tcl_NewWideIntObj(1000000*(i64)1234567890);
+ working = strcmp(Tcl_GetString(pTestObj), "1234567890000000")==0;
+ Tcl_DecrRefCount(pTestObj);
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(working));
+ return TCL_OK;
}
+
/*
** Register commands with the TCL interpreter.
*/
@@ -3714,6 +4234,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_mprintf_int", (Tcl_CmdProc*)sqlite3_mprintf_int },
{ "sqlite3_mprintf_int64", (Tcl_CmdProc*)sqlite3_mprintf_int64 },
{ "sqlite3_mprintf_str", (Tcl_CmdProc*)sqlite3_mprintf_str },
+ { "sqlite3_snprintf_str", (Tcl_CmdProc*)sqlite3_snprintf_str },
{ "sqlite3_mprintf_stronly", (Tcl_CmdProc*)sqlite3_mprintf_stronly},
{ "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double },
{ "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled },
@@ -3722,6 +4243,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_mprintf_n_test", (Tcl_CmdProc*)test_mprintf_n },
{ "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
{ "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf },
+ { "sqlite3_exec", (Tcl_CmdProc*)test_exec },
+ { "sqlite3_exec_nr", (Tcl_CmdProc*)test_exec_nr },
{ "sqlite3_get_table_printf", (Tcl_CmdProc*)test_get_table_printf },
{ "sqlite3_close", (Tcl_CmdProc*)sqlite_test_close },
{ "sqlite3_create_function", (Tcl_CmdProc*)test_create_function },
@@ -3743,6 +4266,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit },
{ "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used },
{ "sqlite3_busy_timeout", (Tcl_CmdProc*)test_busy_timeout },
+ { "printf", (Tcl_CmdProc*)test_printf },
+ { "sqlite3_io_trace", (Tcl_CmdProc*)test_io_trace },
};
static struct {
char *zName;
@@ -3771,6 +4296,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_prepare", test_prepare ,0 },
{ "sqlite3_prepare16", test_prepare16 ,0 },
+ { "sqlite3_prepare_v2", test_prepare_v2 ,0 },
+ { "sqlite3_prepare16_v2", test_prepare16_v2 ,0 },
{ "sqlite3_finalize", test_finalize ,0 },
{ "sqlite3_reset", test_reset ,0 },
{ "sqlite3_expired", test_expired ,0 },
@@ -3783,9 +4310,11 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_clear_tsd_memdebug", test_clear_tsd_memdebug, 0},
{ "sqlite3_tsd_release", test_tsd_release, 0},
{ "sqlite3_thread_cleanup", test_thread_cleanup, 0},
+ { "sqlite3_pager_refcounts", test_pager_refcounts, 0},
{ "sqlite3_load_extension", test_load_extension, 0},
{ "sqlite3_enable_load_extension", test_enable_load, 0},
+ { "sqlite3_extended_result_codes", test_extended_result_codes, 0},
/* sqlite3_column_*() API */
{ "sqlite3_column_count", test_column_count ,0 },
@@ -3819,6 +4348,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif
#endif
{ "sqlite3_global_recover", test_global_recover, 0 },
+ { "working_64bit_int", working_64bit_int, 0 },
/* Functions from os.h */
#ifndef SQLITE_OMIT_DISKIO
@@ -3855,10 +4385,15 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
extern int sqlite3_sync_count, sqlite3_fullsync_count;
extern int sqlite3_opentemp_count;
extern int sqlite3_memUsed;
- extern int sqlite3_malloc_id;
+ extern char *sqlite3_malloc_id;
extern int sqlite3_memMax;
extern int sqlite3_like_count;
extern int sqlite3_tsd_count;
+ extern int sqlite3_xferopt_count;
+ extern int sqlite3_pager_readdb_count;
+ extern int sqlite3_pager_writedb_count;
+ extern int sqlite3_pager_writej_count;
+ extern int sqlite3_pager_pgfree_count;
#if OS_UNIX && defined(SQLITE_TEST) && defined(THREADSAFE) && THREADSAFE
extern int threadsOverrideEachOthersLocks;
#endif
@@ -3896,6 +4431,16 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
(char*)&sqlite3_os_trace, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite3_tsd_count",
(char*)&sqlite3_tsd_count, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite3_xferopt_count",
+ (char*)&sqlite3_xferopt_count, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite3_pager_readdb_count",
+ (char*)&sqlite3_pager_readdb_count, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite3_pager_writedb_count",
+ (char*)&sqlite3_pager_writedb_count, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite3_pager_writej_count",
+ (char*)&sqlite3_pager_writej_count, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite3_pager_pgfree_count",
+ (char*)&sqlite3_pager_pgfree_count, TCL_LINK_INT);
#ifndef SQLITE_OMIT_UTF16
Tcl_LinkVar(interp, "unaligned_string_counter",
(char*)&unaligned_string_counter, TCL_LINK_INT);
@@ -3938,6 +4483,8 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
#endif
Tcl_LinkVar(interp, "sqlite_static_bind_value",
(char*)&sqlite_static_bind_value, TCL_LINK_STRING);
+ Tcl_LinkVar(interp, "sqlite_static_bind_nbyte",
+ (char*)&sqlite_static_bind_nbyte, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_temp_directory",
(char*)&sqlite3_temp_directory, TCL_LINK_STRING);
Tcl_LinkVar(interp, "bitmask_size",
diff --git a/ext/pdo_sqlite/sqlite/src/test2.c b/ext/pdo_sqlite/sqlite/src/test2.c
index 80e57cd87..9be8a58ba 100644
--- a/ext/pdo_sqlite/sqlite/src/test2.c
+++ b/ext/pdo_sqlite/sqlite/src/test2.c
@@ -78,13 +78,13 @@ static int pager_open(
return TCL_ERROR;
}
if( Tcl_GetInt(interp, argv[2], &nPage) ) return TCL_ERROR;
- rc = sqlite3pager_open(&pPager, argv[1], 0, 0);
+ rc = sqlite3PagerOpen(&pPager, argv[1], 0, 0);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
- sqlite3pager_set_cachesize(pPager, nPage);
- sqlite3pager_set_pagesize(pPager, test_pagesize);
+ sqlite3PagerSetCachesize(pPager, nPage);
+ sqlite3PagerSetPagesize(pPager, test_pagesize);
sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPager);
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
@@ -109,7 +109,7 @@ static int pager_close(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_close(pPager);
+ rc = sqlite3PagerClose(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -136,7 +136,7 @@ static int pager_rollback(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_rollback(pPager);
+ rc = sqlite3PagerRollback(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -163,7 +163,12 @@ static int pager_commit(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_commit(pPager);
+ rc = sqlite3PagerCommitPhaseOne(pPager, 0, 0);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, errorName(rc), 0);
+ return TCL_ERROR;
+ }
+ rc = sqlite3PagerCommitPhaseTwo(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -190,7 +195,7 @@ static int pager_stmt_begin(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_stmt_begin(pPager);
+ rc = sqlite3PagerStmtBegin(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -217,7 +222,7 @@ static int pager_stmt_rollback(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_stmt_rollback(pPager);
+ rc = sqlite3PagerStmtRollback(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -244,7 +249,7 @@ static int pager_stmt_commit(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_stmt_commit(pPager);
+ rc = sqlite3PagerStmtCommit(pPager);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -271,7 +276,7 @@ static int pager_stats(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- a = sqlite3pager_stats(pPager);
+ a = sqlite3PagerStats(pPager);
for(i=0; i<9; i++){
static char *zName[] = {
"ref", "page", "max", "size", "state", "err",
@@ -304,7 +309,7 @@ static int pager_pagecount(
return TCL_ERROR;
}
pPager = sqlite3TextToPtr(argv[1]);
- sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3pager_pagecount(pPager));
+ sqlite3_snprintf(sizeof(zBuf),zBuf,"%d",sqlite3PagerPagecount(pPager));
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
@@ -322,7 +327,7 @@ static int page_get(
){
Pager *pPager;
char zBuf[100];
- void *pPage;
+ DbPage *pPage;
int pgno;
int rc;
if( argc!=3 ){
@@ -332,7 +337,7 @@ static int page_get(
}
pPager = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
- rc = sqlite3pager_get(pPager, pgno, &pPage);
+ rc = sqlite3PagerGet(pPager, pgno, &pPage);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -356,7 +361,7 @@ static int page_lookup(
){
Pager *pPager;
char zBuf[100];
- void *pPage;
+ DbPage *pPage;
int pgno;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
@@ -365,7 +370,7 @@ static int page_lookup(
}
pPager = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
- pPage = sqlite3pager_lookup(pPager, pgno);
+ pPage = sqlite3PagerLookup(pPager, pgno);
if( pPage ){
sqlite3_snprintf(sizeof(zBuf),zBuf,"%p",pPage);
Tcl_AppendResult(interp, zBuf, 0);
@@ -392,7 +397,7 @@ static int pager_truncate(
}
pPager = sqlite3TextToPtr(argv[1]);
if( Tcl_GetInt(interp, argv[2], &pgno) ) return TCL_ERROR;
- rc = sqlite3pager_truncate(pPager, pgno);
+ rc = sqlite3PagerTruncate(pPager, pgno);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -412,15 +417,15 @@ static int page_unref(
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
- void *pPage;
+ DbPage *pPage;
int rc;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE\"", 0);
return TCL_ERROR;
}
- pPage = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_unref(pPage);
+ pPage = (DbPage *)sqlite3TextToPtr(argv[1]);
+ rc = sqlite3PagerUnref(pPage);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
@@ -440,14 +445,14 @@ static int page_read(
const char **argv /* Text of each argument */
){
char zBuf[100];
- void *pPage;
+ DbPage *pPage;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE\"", 0);
return TCL_ERROR;
}
pPage = sqlite3TextToPtr(argv[1]);
- memcpy(zBuf, pPage, sizeof(zBuf));
+ memcpy(zBuf, sqlite3PagerGetData(pPage), sizeof(zBuf));
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
@@ -464,14 +469,14 @@ static int page_number(
const char **argv /* Text of each argument */
){
char zBuf[100];
- void *pPage;
+ DbPage *pPage;
if( argc!=2 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE\"", 0);
return TCL_ERROR;
}
- pPage = sqlite3TextToPtr(argv[1]);
- sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3pager_pagenumber(pPage));
+ pPage = (DbPage *)sqlite3TextToPtr(argv[1]);
+ sqlite3_snprintf(sizeof(zBuf), zBuf, "%d", sqlite3PagerPagenumber(pPage));
Tcl_AppendResult(interp, zBuf, 0);
return TCL_OK;
}
@@ -487,21 +492,23 @@ static int page_write(
int argc, /* Number of arguments */
const char **argv /* Text of each argument */
){
- void *pPage;
+ DbPage *pPage;
+ char *pData;
int rc;
if( argc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" PAGE DATA\"", 0);
return TCL_ERROR;
}
- pPage = sqlite3TextToPtr(argv[1]);
- rc = sqlite3pager_write(pPage);
+ pPage = (DbPage *)sqlite3TextToPtr(argv[1]);
+ rc = sqlite3PagerWrite(pPage);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, errorName(rc), 0);
return TCL_ERROR;
}
- strncpy((char*)pPage, argv[2], test_pagesize-1);
- ((char*)pPage)[test_pagesize-1] = 0;
+ pData = sqlite3PagerGetData(pPage);
+ strncpy(pData, argv[2], test_pagesize-1);
+ pData[test_pagesize-1] = 0;
return TCL_OK;
}
@@ -558,10 +565,12 @@ static int fake_big_file(
** Register commands with the TCL interpreter.
*/
int Sqlitetest2_Init(Tcl_Interp *interp){
+ extern int sqlite3_io_error_persist;
extern int sqlite3_io_error_pending;
extern int sqlite3_io_error_hit;
extern int sqlite3_diskfull_pending;
extern int sqlite3_diskfull;
+ extern int sqlite3_pager_n_sort_bucket;
static struct {
char *zName;
Tcl_CmdProc *xProc;
@@ -592,6 +601,8 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
}
Tcl_LinkVar(interp, "sqlite_io_error_pending",
(char*)&sqlite3_io_error_pending, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite_io_error_persist",
+ (char*)&sqlite3_io_error_persist, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_io_error_hit",
(char*)&sqlite3_io_error_hit, TCL_LINK_INT);
Tcl_LinkVar(interp, "sqlite_diskfull_pending",
@@ -602,5 +613,7 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
(char*)&sqlite3_pending_byte, TCL_LINK_INT);
Tcl_LinkVar(interp, "pager_pagesize",
(char*)&test_pagesize, TCL_LINK_INT);
+ Tcl_LinkVar(interp, "sqlite_pager_n_sort_bucket",
+ (char*)&sqlite3_pager_n_sort_bucket, TCL_LINK_INT);
return TCL_OK;
}
diff --git a/ext/pdo_sqlite/sqlite/src/test3.c b/ext/pdo_sqlite/sqlite/src/test3.c
index 6557fb4f4..f2540cacd 100644
--- a/ext/pdo_sqlite/sqlite/src/test3.c
+++ b/ext/pdo_sqlite/sqlite/src/test3.c
@@ -511,7 +511,7 @@ static int btree_pager_stats(
return TCL_ERROR;
}
pBt = sqlite3TextToPtr(argv[1]);
- a = sqlite3pager_stats(sqlite3BtreePager(pBt));
+ a = sqlite3PagerStats(sqlite3BtreePager(pBt));
for(i=0; i<11; i++){
static char *zName[] = {
"ref", "page", "max", "size", "state", "err",
@@ -545,7 +545,7 @@ static int btree_pager_ref_dump(
}
pBt = sqlite3TextToPtr(argv[1]);
#ifdef SQLITE_DEBUG
- sqlite3pager_refdump(sqlite3BtreePager(pBt));
+ sqlite3PagerRefdump(sqlite3BtreePager(pBt));
#endif
return TCL_OK;
}
@@ -567,6 +567,7 @@ static int btree_integrity_check(
int nRoot;
int *aRoot;
int i;
+ int nErr;
char *zResult;
if( argc<3 ){
@@ -576,16 +577,16 @@ static int btree_integrity_check(
}
pBt = sqlite3TextToPtr(argv[1]);
nRoot = argc-2;
- aRoot = malloc( sizeof(int)*(argc-2) );
+ aRoot = (int*)malloc( sizeof(int)*(argc-2) );
for(i=0; i<argc-2; i++){
if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
}
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
- zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot);
+ zResult = sqlite3BtreeIntegrityCheck(pBt, aRoot, nRoot, 10000, &nErr);
#else
zResult = 0;
#endif
- free(aRoot);
+ free((void*)aRoot);
if( zResult ){
Tcl_AppendResult(interp, zResult, 0);
sqliteFree(zResult);
@@ -598,7 +599,6 @@ static int btree_integrity_check(
**
** Print information about all cursors to standard output for debugging.
*/
-#ifdef SQLITE_DEBUG
static int btree_cursor_list(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
@@ -616,7 +616,6 @@ static int btree_cursor_list(
sqlite3BtreeCursorList(pBt);
return SQLITE_OK;
}
-#endif
/*
** Usage: btree_cursor ID TABLENUM WRITEABLE
@@ -707,9 +706,9 @@ static int btree_move_to(
if( sqlite3BtreeFlags(pCur) & BTREE_INTKEY ){
int iKey;
if( Tcl_GetInt(interp, argv[2], &iKey) ) return TCL_ERROR;
- rc = sqlite3BtreeMoveto(pCur, 0, iKey, &res);
+ rc = sqlite3BtreeMoveto(pCur, 0, iKey, 0, &res);
}else{
- rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), &res);
+ rc = sqlite3BtreeMoveto(pCur, argv[2], strlen(argv[2]), 0, &res);
}
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
@@ -776,7 +775,7 @@ static int btree_insert(
unsigned char *pBuf;
if( Tcl_GetWideIntFromObj(interp, objv[2], &iKey) ) return TCL_ERROR;
pBuf = Tcl_GetByteArrayFromObj(objv[3], &len);
- rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len);
+ rc = sqlite3BtreeInsert(pCur, 0, iKey, pBuf, len, 0);
}else{
int keylen;
int dlen;
@@ -784,7 +783,7 @@ static int btree_insert(
unsigned char *pDBuf;
pKBuf = Tcl_GetByteArrayFromObj(objv[2], &keylen);
pDBuf = Tcl_GetByteArrayFromObj(objv[3], &dlen);
- rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen);
+ rc = sqlite3BtreeInsert(pCur, pKBuf, keylen, pDBuf, dlen, 0);
}
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
@@ -1053,6 +1052,7 @@ static int btree_data(
rc = sqlite3BtreeData(pCur, 0, n, zBuf);
if( rc ){
Tcl_AppendResult(interp, errorName(rc), 0);
+ free(zBuf);
return TCL_ERROR;
}
zBuf[n] = 0;
@@ -1186,8 +1186,8 @@ static int btree_payload_size(
** aResult[7] = Header size in bytes
** aResult[8] = Local payload size
** aResult[9] = Parent page number
+** aResult[10]= Page number of the first overflow page
*/
-#ifdef SQLITE_DEBUG
static int btree_cursor_info(
void *NotUsed,
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
@@ -1198,7 +1198,7 @@ static int btree_cursor_info(
int rc;
int i, j;
int up;
- int aResult[10];
+ int aResult[11];
char zBuf[400];
if( argc!=2 && argc!=3 ){
@@ -1225,7 +1225,78 @@ static int btree_cursor_info(
Tcl_AppendResult(interp, &zBuf[1], 0);
return SQLITE_OK;
}
-#endif
+
+/*
+** Copied from btree.c:
+*/
+static u32 t4Get4byte(unsigned char *p){
+ return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
+}
+
+/*
+** btree_ovfl_info BTREE CURSOR
+**
+** Given a cursor, return the sequence of pages number that form the
+** overflow pages for the data of the entry that the cursor is point
+** to.
+*/
+static int btree_ovfl_info(
+ void *NotUsed,
+ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
+ int argc, /* Number of arguments */
+ const char **argv /* Text of each argument */
+){
+ Btree *pBt;
+ BtCursor *pCur;
+ Pager *pPager;
+ int rc;
+ int n;
+ int dataSize;
+ u32 pgno;
+ void *pPage;
+ int aResult[11];
+ char zElem[100];
+ Tcl_DString str;
+
+ if( argc!=3 ){
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " BTREE CURSOR", 0);
+ return TCL_ERROR;
+ }
+ pBt = sqlite3TextToPtr(argv[1]);
+ pCur = sqlite3TextToPtr(argv[2]);
+ if( (*(void**)pCur) != (void*)pBt ){
+ Tcl_AppendResult(interp, "Cursor ", argv[2], " does not belong to btree ",
+ argv[1], 0);
+ return TCL_ERROR;
+ }
+ pPager = sqlite3BtreePager(pBt);
+ rc = sqlite3BtreeCursorInfo(pCur, aResult, 0);
+ if( rc ){
+ Tcl_AppendResult(interp, errorName(rc), 0);
+ return TCL_ERROR;
+ }
+ dataSize = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserve(pBt);
+ Tcl_DStringInit(&str);
+ n = aResult[6] - aResult[8];
+ n = (n + dataSize - 1)/dataSize;
+ pgno = (u32)aResult[10];
+ while( pgno && n-- ){
+ DbPage *pDbPage;
+ sprintf(zElem, "%d", pgno);
+ Tcl_DStringAppendElement(&str, zElem);
+ if( sqlite3PagerGet(pPager, pgno, &pDbPage)!=SQLITE_OK ){
+ Tcl_DStringFree(&str);
+ Tcl_AppendResult(interp, "unable to get page ", zElem, 0);
+ return TCL_ERROR;
+ }
+ pPage = sqlite3PagerGetData(pDbPage);
+ pgno = t4Get4byte((unsigned char*)pPage);
+ sqlite3PagerUnref(pDbPage);
+ }
+ Tcl_DStringResult(interp, &str);
+ return SQLITE_OK;
+}
/*
** The command is provided for the purpose of setting breakpoints.
@@ -1441,10 +1512,9 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
{ "btree_rollback_statement", (Tcl_CmdProc*)btree_rollback_statement },
{ "btree_from_db", (Tcl_CmdProc*)btree_from_db },
{ "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size },
-#ifdef SQLITE_DEBUG
{ "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info },
+ { "btree_ovfl_info", (Tcl_CmdProc*)btree_ovfl_info },
{ "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
-#endif
};
int i;
diff --git a/ext/pdo_sqlite/sqlite/src/tokenize.c b/ext/pdo_sqlite/sqlite/src/tokenize.c
index 69db09aa4..96212b588 100644
--- a/ext/pdo_sqlite/sqlite/src/tokenize.c
+++ b/ext/pdo_sqlite/sqlite/src/tokenize.c
@@ -394,16 +394,16 @@ int sqlite3RunParser(Parse *pParse, const char *zSql, char **pzErrMsg){
int tokenType;
int lastTokenParsed = -1;
sqlite3 *db = pParse->db;
- extern void *sqlite3ParserAlloc(void*(*)(int));
+ extern void *sqlite3ParserAlloc(void*(*)(size_t));
extern void sqlite3ParserFree(void*, void(*)(void*));
- extern int sqlite3Parser(void*, int, Token, Parse*);
+ extern void sqlite3Parser(void*, int, Token, Parse*);
if( db->activeVdbeCnt==0 ){
db->u1.isInterrupted = 0;
}
pParse->rc = SQLITE_OK;
i = 0;
- pEngine = sqlite3ParserAlloc((void*(*)(int))sqlite3MallocX);
+ pEngine = sqlite3ParserAlloc((void*(*)(size_t))sqlite3MallocX);
if( pEngine==0 ){
return SQLITE_NOMEM;
}
@@ -495,7 +495,7 @@ abort_parse:
** structure built up in pParse->pNewTable. The calling code (see vtab.c)
** will take responsibility for freeing the Table structure.
*/
- sqlite3DeleteTable(pParse->db, pParse->pNewTable);
+ sqlite3DeleteTable(pParse->pNewTable);
}
sqlite3DeleteTrigger(pParse->pNewTrigger);
diff --git a/ext/pdo_sqlite/sqlite/src/trigger.c b/ext/pdo_sqlite/sqlite/src/trigger.c
index 15992df38..4a929adde 100644
--- a/ext/pdo_sqlite/sqlite/src/trigger.c
+++ b/ext/pdo_sqlite/sqlite/src/trigger.c
@@ -47,9 +47,9 @@ void sqlite3BeginTrigger(
int op, /* One of TK_INSERT, TK_UPDATE, TK_DELETE */
IdList *pColumns, /* column list if this is an UPDATE OF trigger */
SrcList *pTableName,/* The name of the table/view the trigger applies to */
- int foreach, /* One of TK_ROW or TK_STATEMENT */
Expr *pWhen, /* WHEN clause */
- int isTemp /* True if the TEMPORARY keyword is present */
+ int isTemp, /* True if the TEMPORARY keyword is present */
+ int noErr /* Suppress errors if the trigger already exists */
){
Trigger *pTrigger = 0;
Table *pTab;
@@ -115,7 +115,9 @@ void sqlite3BeginTrigger(
goto trigger_cleanup;
}
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,strlen(zName)) ){
- sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
+ if( !noErr ){
+ sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
+ }
goto trigger_cleanup;
}
@@ -177,7 +179,6 @@ void sqlite3BeginTrigger(
pTrigger->tr_tm = tr_tm==TK_BEFORE ? TRIGGER_BEFORE : TRIGGER_AFTER;
pTrigger->pWhen = sqlite3ExprDup(pWhen);
pTrigger->pColumns = sqlite3IdListDup(pColumns);
- pTrigger->foreach = foreach;
sqlite3TokenCopy(&pTrigger->nameToken,pName);
assert( pParse->pNewTrigger==0 );
pParse->pNewTrigger = pTrigger;
@@ -387,7 +388,11 @@ TriggerStep *sqlite3TriggerUpdateStep(
int orconf /* The conflict algorithm. (OE_Abort, OE_Ignore, etc) */
){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
- if( pTriggerStep==0 ) return 0;
+ if( pTriggerStep==0 ){
+ sqlite3ExprListDelete(pEList);
+ sqlite3ExprDelete(pWhere);
+ return 0;
+ }
pTriggerStep->op = TK_UPDATE;
pTriggerStep->target = *pTableName;
@@ -406,7 +411,10 @@ TriggerStep *sqlite3TriggerUpdateStep(
*/
TriggerStep *sqlite3TriggerDeleteStep(Token *pTableName, Expr *pWhere){
TriggerStep *pTriggerStep = sqliteMalloc(sizeof(TriggerStep));
- if( pTriggerStep==0 ) return 0;
+ if( pTriggerStep==0 ){
+ sqlite3ExprDelete(pWhere);
+ return 0;
+ }
pTriggerStep->op = TK_DELETE;
pTriggerStep->target = *pTableName;
@@ -439,7 +447,7 @@ void sqlite3DeleteTrigger(Trigger *pTrigger){
** same job as this routine except it takes a pointer to the trigger
** instead of the trigger name.
**/
-void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
+void sqlite3DropTrigger(Parse *pParse, SrcList *pName, int noErr){
Trigger *pTrigger = 0;
int i;
const char *zDb;
@@ -463,7 +471,9 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
if( pTrigger ) break;
}
if( !pTrigger ){
- sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
+ if( !noErr ){
+ sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
+ }
goto drop_trigger_cleanup;
}
sqlite3DropTriggerPtr(pParse, pTrigger);
@@ -663,12 +673,12 @@ static int codeTriggerProgram(
pParse->trigStack->orconf = orconf;
switch( pTriggerStep->op ){
case TK_SELECT: {
- Select * ss = sqlite3SelectDup(pTriggerStep->pSelect);
- assert(ss);
- assert(ss->pSrc);
- sqlite3SelectResolve(pParse, ss, 0);
- sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
- sqlite3SelectDelete(ss);
+ Select *ss = sqlite3SelectDup(pTriggerStep->pSelect);
+ if( ss ){
+ sqlite3SelectResolve(pParse, ss, 0);
+ sqlite3Select(pParse, ss, SRT_Discard, 0, 0, 0, 0, 0);
+ sqlite3SelectDelete(ss);
+ }
break;
}
case TK_UPDATE: {
diff --git a/ext/pdo_sqlite/sqlite/src/update.c b/ext/pdo_sqlite/sqlite/src/update.c
index 2565787f0..07647a3d5 100644
--- a/ext/pdo_sqlite/sqlite/src/update.c
+++ b/ext/pdo_sqlite/sqlite/src/update.c
@@ -103,6 +103,7 @@ void sqlite3Update(
AuthContext sContext; /* The authorization context */
NameContext sNC; /* The name-context to resolve expressions in */
int iDb; /* Database containing the table being updated */
+ int memCnt = 0; /* Memory cell used for counting rows changed */
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* Trying to update a view */
@@ -311,7 +312,8 @@ void sqlite3Update(
/* Initialize the count of updated rows
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
- sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
+ memCnt = pParse->nMem++;
+ sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
}
if( triggers_exist ){
@@ -463,13 +465,13 @@ void sqlite3Update(
/* Create the new index entries and the new record.
*/
- sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1);
+ sqlite3CompleteInsertion(pParse, pTab, iCur, aIdxUsed, chngRowid, 1, -1, 0);
}
/* Increment the row counter
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack){
- sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
+ sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
}
/* If there are triggers, close all the cursors after each iteration
@@ -514,6 +516,7 @@ void sqlite3Update(
** invoke the callback function.
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
+ sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0);
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
sqlite3VdbeSetNumCols(v, 1);
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);
@@ -614,6 +617,7 @@ static void updateVirtualTable(
sqlite3VdbeOp3(v, OP_VUpdate, 0, pTab->nCol+2,
(const char*)pTab->pVtab, P3_VTAB);
sqlite3VdbeAddOp(v, OP_Next, ephemTab, addr);
+ sqlite3VdbeJumpHere(v, addr-1);
sqlite3VdbeAddOp(v, OP_Close, ephemTab, 0);
/* Cleanup */
diff --git a/ext/pdo_sqlite/sqlite/src/utf.c b/ext/pdo_sqlite/sqlite/src/utf.c
index 05d238433..58c964759 100644
--- a/ext/pdo_sqlite/sqlite/src/utf.c
+++ b/ext/pdo_sqlite/sqlite/src/utf.c
@@ -63,8 +63,14 @@
#include "vdbeInt.h"
/*
+** The following constant value is used by the SQLITE_BIGENDIAN and
+** SQLITE_LITTLEENDIAN macros.
+*/
+const int sqlite3one = 1;
+
+/*
** This table maps from the first byte of a UTF-8 character to the number
-** of trailing bytes expected. A value '255' indicates that the table key
+** of trailing bytes expected. A value '4' indicates that the table key
** is not a legal first byte for a UTF-8 character.
*/
static const u8 xtra_utf8_bytes[256] = {
@@ -79,10 +85,10 @@ static const u8 xtra_utf8_bytes[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/* 10wwwwww */
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
-255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
/* 110yyyyy */
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -92,7 +98,7 @@ static const u8 xtra_utf8_bytes[256] = {
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* 11110yyy */
-3, 3, 3, 3, 3, 3, 3, 3, 255, 255, 255, 255, 255, 255, 255, 255,
+3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
};
/*
@@ -101,11 +107,24 @@ static const u8 xtra_utf8_bytes[256] = {
** read by a naive implementation of a UTF-8 character reader. The code
** in the READ_UTF8 macro explains things best.
*/
-static const int xtra_utf8_bits[4] = {
-0,
-12416, /* (0xC0 << 6) + (0x80) */
-925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */
-63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
+static const int xtra_utf8_bits[] = {
+ 0,
+ 12416, /* (0xC0 << 6) + (0x80) */
+ 925824, /* (0xE0 << 12) + (0x80 << 6) + (0x80) */
+ 63447168 /* (0xF0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
+};
+
+/*
+** If a UTF-8 character contains N bytes extra bytes (N bytes follow
+** the initial byte so that the total character length is N+1) then
+** masking the character with utf8_mask[N] must produce a non-zero
+** result. Otherwise, we have an (illegal) overlong encoding.
+*/
+static const int utf_mask[] = {
+ 0x00000000,
+ 0xffffff80,
+ 0xfffff800,
+ 0xffff0000,
};
#define READ_UTF8(zIn, c) { \
@@ -113,11 +132,14 @@ static const int xtra_utf8_bits[4] = {
c = *(zIn)++; \
xtra = xtra_utf8_bytes[c]; \
switch( xtra ){ \
- case 255: c = (int)0xFFFD; break; \
+ case 4: c = (int)0xFFFD; break; \
case 3: c = (c<<6) + *(zIn)++; \
case 2: c = (c<<6) + *(zIn)++; \
case 1: c = (c<<6) + *(zIn)++; \
c -= xtra_utf8_bits[xtra]; \
+ if( (utf_mask[xtra]&c)==0 \
+ || (c&0xFFFFF800)==0xD800 \
+ || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \
} \
}
int sqlite3ReadUtf8(const unsigned char *z){
@@ -181,6 +203,7 @@ int sqlite3ReadUtf8(const unsigned char *z){
int c2 = (*zIn++); \
c2 += ((*zIn++)<<8); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
+ if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \
} \
}
@@ -191,6 +214,7 @@ int sqlite3ReadUtf8(const unsigned char *z){
int c2 = ((*zIn++)<<8); \
c2 += (*zIn++); \
c = (c2&0x03FF) + ((c&0x003F)<<10) + (((c&0x03C0)+0x0040)<<10); \
+ if( (c & 0xFFFF0000)==0 ) c = 0xFFFD; \
} \
}
@@ -245,7 +269,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
unsigned char *zIn; /* Input iterator */
unsigned char *zTerm; /* End of input */
unsigned char *z; /* Output iterator */
- int c;
+ unsigned int c;
assert( pMem->flags&MEM_Str );
assert( pMem->enc!=desiredEnc );
@@ -475,7 +499,7 @@ char *sqlite3utf16to8(const void *z, int nByte){
** in pZ (or up until the first pair of 0x00 bytes, whichever comes first).
*/
int sqlite3utf16ByteLen(const void *zIn, int nChar){
- int c = 1;
+ unsigned int c = 1;
char const *z = zIn;
int n = 0;
if( SQLITE_UTF16NATIVE==SQLITE_UTF16BE ){
@@ -556,11 +580,11 @@ void sqlite3utf16Substr(
** characters in each encoding are inverses of each other.
*/
void sqlite3utfSelfTest(){
- int i;
+ unsigned int i, t;
unsigned char zBuf[20];
unsigned char *z;
int n;
- int c;
+ unsigned int c;
for(i=0; i<0x00110000; i++){
z = zBuf;
@@ -568,7 +592,10 @@ void sqlite3utfSelfTest(){
n = z-zBuf;
z = zBuf;
READ_UTF8(z, c);
- assert( c==i );
+ t = i;
+ if( i>=0xD800 && i<=0xDFFF ) t = 0xFFFD;
+ if( (i&0xFFFFFFFE)==0xFFFE ) t = 0xFFFD;
+ assert( c==t );
assert( (z-zBuf)==n );
}
for(i=0; i<0x00110000; i++){
diff --git a/ext/pdo_sqlite/sqlite/src/util.c b/ext/pdo_sqlite/sqlite/src/util.c
index 5ca9ec408..d95a8828b 100644
--- a/ext/pdo_sqlite/sqlite/src/util.c
+++ b/ext/pdo_sqlite/sqlite/src/util.c
@@ -83,7 +83,7 @@ void sqlite3_soft_heap_limit(int n){
** Release memory held by SQLite instances created by the current thread.
*/
int sqlite3_release_memory(int n){
- return sqlite3pager_release_memory(n);
+ return sqlite3PagerReleaseMemory(n);
}
#else
/* If SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined, then define a version
@@ -661,12 +661,13 @@ void *sqlite3Malloc(int n, int doMemManage){
}
return p;
}
-void sqlite3ReallocOrFree(void **pp, int n){
- void *p = sqlite3Realloc(*pp, n);
- if( !p ){
- sqlite3FreeX(*pp);
+void *sqlite3ReallocOrFree(void *p, int n){
+ void *pNew;
+ pNew = sqlite3Realloc(p, n);
+ if( !pNew ){
+ sqlite3FreeX(p);
}
- *pp = p;
+ return pNew;
}
/*
@@ -750,7 +751,7 @@ void sqlite3SetString(char **pz, ...){
const char *z;
char *zResult;
- if( pz==0 ) return;
+ assert( pz!=0 );
nByte = 1;
va_start(ap, pz);
while( (z = va_arg(ap, const char*))!=0 ){
@@ -1132,6 +1133,13 @@ int sqlite3FitsIn64Bits(const char *zNum){
** Return an error (non-zero) if the magic was not SQLITE_MAGIC_OPEN
** when this routine is called.
**
+** This routine is called when entering an SQLite API. The SQLITE_MAGIC_OPEN
+** value indicates that the database connection passed into the API is
+** open and is not being used by another thread. By changing the value
+** to SQLITE_MAGIC_BUSY we indicate that the connection is in use.
+** sqlite3SafetyOff() below will change the value back to SQLITE_MAGIC_OPEN
+** when the API exits.
+**
** This routine is a attempt to detect if two threads use the
** same sqlite* pointer at the same time. There is a race
** condition so it is possible that the error is not detected.
@@ -1165,11 +1173,11 @@ int sqlite3SafetyOff(sqlite3 *db){
if( db->magic==SQLITE_MAGIC_BUSY ){
db->magic = SQLITE_MAGIC_OPEN;
return 0;
- }else if( db->magic==SQLITE_MAGIC_OPEN ){
+ }else {
db->magic = SQLITE_MAGIC_ERROR;
db->u1.isInterrupted = 1;
+ return 1;
}
- return 1;
}
/*
@@ -1384,11 +1392,11 @@ void *sqlite3TextToPtr(const char *z){
z++;
}
if( sizeof(p)==sizeof(v) ){
- p = *(void**)&v;
+ memcpy(&p, &v, sizeof(p));
}else{
assert( sizeof(p)==sizeof(v2) );
v2 = (u32)v;
- p = *(void**)&v2;
+ memcpy(&p, &v2, sizeof(p));
}
return p;
}
@@ -1446,7 +1454,7 @@ int sqlite3ApiExit(sqlite3* db, int rc){
sqlite3Error(db, SQLITE_NOMEM, 0);
rc = SQLITE_NOMEM;
}
- return rc;
+ return rc & (db ? db->errMask : 0xff);
}
/*
@@ -1461,9 +1469,11 @@ int sqlite3MallocFailed(){
** Set the "malloc has failed" condition to true for this thread.
*/
void sqlite3FailedMalloc(){
- sqlite3OsEnterMutex();
- assert( mallocHasFailed==0 );
- mallocHasFailed = 1;
+ if( !sqlite3MallocFailed() ){
+ sqlite3OsEnterMutex();
+ assert( mallocHasFailed==0 );
+ mallocHasFailed = 1;
+ }
}
#ifdef SQLITE_MEMDEBUG
diff --git a/ext/pdo_sqlite/sqlite/src/vacuum.c b/ext/pdo_sqlite/sqlite/src/vacuum.c
index 336df67cc..3f4057382 100644
--- a/ext/pdo_sqlite/sqlite/src/vacuum.c
+++ b/ext/pdo_sqlite/sqlite/src/vacuum.c
@@ -20,21 +20,7 @@
#include "vdbeInt.h"
#include "os.h"
-#ifndef SQLITE_OMIT_VACUUM
-/*
-** Generate a random name of 20 character in length.
-*/
-static void randomName(unsigned char *zBuf){
- static const unsigned char zChars[] =
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789";
- int i;
- sqlite3Randomness(20, zBuf);
- for(i=0; i<20; i++){
- zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
- }
-}
-
+#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
/*
** Execute zSql on database db. Return an error code.
*/
@@ -69,8 +55,6 @@ static int execExecSql(sqlite3 *db, const char *zSql){
return sqlite3_finalize(pStmt);
}
-#endif
-
/*
** The non-standard VACUUM command is used to clean up the database,
** collapse free space, etc. It is modelled after the VACUUM command
@@ -94,15 +78,11 @@ void sqlite3Vacuum(Parse *pParse){
*/
int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
int rc = SQLITE_OK; /* Return code from service routines */
-#ifndef SQLITE_OMIT_VACUUM
- const char *zFilename; /* full pathname of the database file */
- int nFilename; /* number of characters in zFilename[] */
- char *zTemp = 0; /* a temporary file in same directory as zFilename */
Btree *pMain; /* The database being vacuumed */
- Btree *pTemp;
- char *zSql = 0;
- int saved_flags; /* Saved value of the db->flags */
- Db *pDb = 0; /* Database to detach at end of vacuum */
+ Btree *pTemp; /* The temporary database we vacuum into */
+ char *zSql = 0; /* SQL statements */
+ int saved_flags; /* Saved value of the db->flags */
+ Db *pDb = 0; /* Database to detach at end of vacuum */
/* Save the current value of the write-schema flag before setting it. */
saved_flags = db->flags;
@@ -114,40 +94,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
rc = SQLITE_ERROR;
goto end_of_vacuum;
}
-
- /* Get the full pathname of the database file and create a
- ** temporary filename in the same directory as the original file.
- */
pMain = db->aDb[0].pBt;
- zFilename = sqlite3BtreeGetFilename(pMain);
- assert( zFilename );
- if( zFilename[0]=='\0' ){
- /* The in-memory database. Do nothing. Return directly to avoid causing
- ** an error trying to DETACH the vacuum_db (which never got attached)
- ** in the exit-handler.
- */
- return SQLITE_OK;
- }
- nFilename = strlen(zFilename);
- zTemp = sqliteMalloc( nFilename+100 );
- if( zTemp==0 ){
- rc = SQLITE_NOMEM;
- goto end_of_vacuum;
- }
- strcpy(zTemp, zFilename);
-
- /* The randomName() procedure in the following loop uses an excellent
- ** source of randomness to generate a name from a space of 1.3e+31
- ** possibilities. So unless the directory already contains on the order
- ** of 1.3e+31 files, the probability that the following loop will
- ** run more than once or twice is vanishingly small. We are certain
- ** enough that this loop will always terminate (and terminate quickly)
- ** that we don't even bother to set a maximum loop count.
- */
- do {
- zTemp[nFilename] = '-';
- randomName((unsigned char*)&zTemp[nFilename+1]);
- } while( sqlite3OsFileExists(zTemp) );
/* Attach the temporary database as 'vacuum_db'. The synchronous pragma
** can be set to 'off' for this file, as it is not recovered if a crash
@@ -157,20 +104,18 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
**
** An optimisation would be to use a non-journaled pager.
*/
- zSql = sqlite3MPrintf("ATTACH '%q' AS vacuum_db;", zTemp);
- if( !zSql ){
- rc = SQLITE_NOMEM;
- goto end_of_vacuum;
- }
+ zSql = "ATTACH '' AS vacuum_db;";
rc = execSql(db, zSql);
- sqliteFree(zSql);
- zSql = 0;
if( rc!=SQLITE_OK ) goto end_of_vacuum;
pDb = &db->aDb[db->nDb-1];
assert( strcmp(db->aDb[db->nDb-1].zName,"vacuum_db")==0 );
pTemp = db->aDb[db->nDb-1].pBt;
sqlite3BtreeSetPageSize(pTemp, sqlite3BtreeGetPageSize(pMain),
sqlite3BtreeGetReserve(pMain));
+ if( sqlite3MallocFailed() ){
+ rc = SQLITE_NOMEM;
+ goto end_of_vacuum;
+ }
assert( sqlite3BtreeGetPageSize(pTemp)==sqlite3BtreeGetPageSize(pMain) );
rc = execSql(db, "PRAGMA vacuum_db.synchronous=OFF");
if( rc!=SQLITE_OK ){
@@ -190,7 +135,9 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
*/
rc = execExecSql(db,
"SELECT 'CREATE TABLE vacuum_db.' || substr(sql,14,100000000) "
- " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'");
+ " FROM sqlite_master WHERE type='table' AND name!='sqlite_sequence'"
+ " AND rootpage>0"
+ );
if( rc!=SQLITE_OK ) goto end_of_vacuum;
rc = execExecSql(db,
"SELECT 'CREATE INDEX vacuum_db.' || substr(sql,14,100000000)"
@@ -200,11 +147,6 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
"SELECT 'CREATE UNIQUE INDEX vacuum_db.' || substr(sql,21,100000000) "
" FROM sqlite_master WHERE sql LIKE 'CREATE UNIQUE INDEX %'");
if( rc!=SQLITE_OK ) goto end_of_vacuum;
- rc = execExecSql(db,
- "SELECT 'CREATE VIEW vacuum_db.' || substr(sql,13,100000000) "
- " FROM sqlite_master WHERE type='view'"
- );
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
/* Loop through the tables in the main database. For each, do
** an "INSERT INTO vacuum_db.xxx SELECT * FROM xxx;" to copy
@@ -214,7 +156,9 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
"SELECT 'INSERT INTO vacuum_db.' || quote(name) "
"|| ' SELECT * FROM ' || quote(name) || ';'"
"FROM sqlite_master "
- "WHERE type = 'table' AND name!='sqlite_sequence';"
+ "WHERE type = 'table' AND name!='sqlite_sequence' "
+ " AND rootpage>0"
+
);
if( rc!=SQLITE_OK ) goto end_of_vacuum;
@@ -233,17 +177,19 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){
if( rc!=SQLITE_OK ) goto end_of_vacuum;
- /* Copy the triggers from the main database to the temporary database.
- ** This was deferred before in case the triggers interfered with copying
- ** the data. It's possible the indices should be deferred until this
- ** point also.
+ /* Copy the triggers, views, and virtual tables from the main database
+ ** over to the temporary database. None of these objects has any
+ ** associated storage, so all we have to do is copy their entries
+ ** from the SQLITE_MASTER table.
*/
- rc = execExecSql(db,
- "SELECT 'CREATE TRIGGER vacuum_db.' || substr(sql, 16, 1000000) "
- "FROM sqlite_master WHERE type='trigger'"
+ rc = execSql(db,
+ "INSERT INTO vacuum_db.sqlite_master "
+ " SELECT type, name, tbl_name, rootpage, sql"
+ " FROM sqlite_master"
+ " WHERE type='view' OR type='trigger'"
+ " OR (type='table' AND rootpage=0)"
);
- if( rc!=SQLITE_OK ) goto end_of_vacuum;
-
+ if( rc ) goto end_of_vacuum;
/* At this point, unless the main db was completely empty, there is now a
** transaction open on the vacuum database, but not on the main database.
@@ -309,21 +255,8 @@ end_of_vacuum:
pDb->pSchema = 0;
}
- /* If one of the execSql() calls above returned SQLITE_NOMEM, then the
- ** mallocFailed flag will be clear (because execSql() calls sqlite3_exec()).
- ** Fix this so the flag and return code match.
- */
- if( rc==SQLITE_NOMEM ){
- sqlite3MallocFailed();
- }
-
- if( zTemp ){
- sqlite3OsDelete(zTemp);
- sqliteFree(zTemp);
- }
- sqliteFree( zSql );
sqlite3ResetInternalSchema(db, 0);
-#endif
return rc;
}
+#endif /* SQLITE_OMIT_VACUUM && SQLITE_OMIT_ATTACH */
diff --git a/ext/pdo_sqlite/sqlite/src/vdbe.c b/ext/pdo_sqlite/sqlite/src/vdbe.c
index 98b9916ab..9bbc65a2e 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbe.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbe.c
@@ -211,7 +211,7 @@ static void applyNumericAffinity(Mem *pRec){
sqlite3VdbeChangeEncoding(pRec, SQLITE_UTF8);
if( !realnum && sqlite3atoi64(pRec->z, &value) ){
sqlite3VdbeMemRelease(pRec);
- pRec->i = value;
+ pRec->u.i = value;
pRec->flags = MEM_Int;
}else{
sqlite3VdbeMemRealify(pRec);
@@ -454,6 +454,22 @@ int sqlite3VdbeExec(
p->resOnStack = 0;
db->busyHandler.nBusy = 0;
CHECK_FOR_INTERRUPT;
+ sqlite3VdbeIOTraceSql(p);
+#ifdef SQLITE_DEBUG
+ if( (p->db->flags & SQLITE_VdbeListing)!=0
+ || sqlite3OsFileExists("vdbe_explain")
+ ){
+ int i;
+ printf("VDBE Program Listing:\n");
+ sqlite3VdbePrintSql(p);
+ for(i=0; i<p->nOp; i++){
+ sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
+ }
+ }
+ if( sqlite3OsFileExists("vdbe_trace") ){
+ p->trace = stdout;
+ }
+#endif
for(pc=p->pc; rc==SQLITE_OK; pc++){
assert( pc>=0 && pc<p->nOp );
assert( pTos<=&p->aStack[pc] );
@@ -654,7 +670,7 @@ case OP_Halt: { /* no-push */
case OP_Integer: {
pTos++;
pTos->flags = MEM_Int;
- pTos->i = pOp->p1;
+ pTos->u.i = pOp->p1;
break;
}
@@ -670,7 +686,7 @@ case OP_Int64: {
pTos->z = pOp->p3;
pTos->n = strlen(pTos->z);
pTos->enc = SQLITE_UTF8;
- pTos->i = sqlite3VdbeIntValue(pTos);
+ pTos->u.i = sqlite3VdbeIntValue(pTos);
pTos->flags |= MEM_Int;
break;
}
@@ -1083,8 +1099,8 @@ case OP_Remainder: { /* same as TK_REM, no-push */
pTos->flags = MEM_Null;
}else if( (pTos->flags & pNos->flags & MEM_Int)==MEM_Int ){
i64 a, b;
- a = pTos->i;
- b = pNos->i;
+ a = pTos->u.i;
+ b = pNos->u.i;
switch( pOp->opcode ){
case OP_Add: b += a; break;
case OP_Subtract: b -= a; break;
@@ -1103,7 +1119,7 @@ case OP_Remainder: { /* same as TK_REM, no-push */
Release(pTos);
pTos--;
Release(pTos);
- pTos->i = b;
+ pTos->u.i = b;
pTos->flags = MEM_Int;
}else{
double a, b;
@@ -1294,7 +1310,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, no-push */
Release(pTos);
pTos--;
Release(pTos);
- pTos->i = a;
+ pTos->u.i = a;
pTos->flags = MEM_Int;
break;
}
@@ -1309,7 +1325,7 @@ case OP_ShiftRight: { /* same as TK_RSHIFT, no-push */
case OP_AddImm: { /* no-push */
assert( pTos>=p->aStack );
sqlite3VdbeMemIntegerify(pTos);
- pTos->i += pOp->p1;
+ pTos->u.i += pOp->p1;
break;
}
@@ -1334,7 +1350,7 @@ case OP_ForceInt: { /* no-push */
break;
}
if( pTos->flags & MEM_Int ){
- v = pTos->i + (pOp->p1!=0);
+ v = pTos->u.i + (pOp->p1!=0);
}else{
/* FIX ME: should this not be assert( pTos->flags & MEM_Real ) ??? */
sqlite3VdbeMemRealify(pTos);
@@ -1343,7 +1359,7 @@ case OP_ForceInt: { /* no-push */
if( pOp->p1 && pTos->r==(double)v ) v++;
}
Release(pTos);
- pTos->i = v;
+ pTos->u.i = v;
pTos->flags = MEM_Int;
break;
}
@@ -1632,7 +1648,7 @@ case OP_Ge: { /* same as TK_GE, no-push */
}else{
pTos++;
pTos->flags = MEM_Int;
- pTos->i = res;
+ pTos->u.i = res;
}
break;
}
@@ -1659,13 +1675,13 @@ case OP_Or: { /* same as TK_OR, no-push */
v1 = 2;
}else{
sqlite3VdbeMemIntegerify(pTos);
- v1 = pTos->i==0;
+ v1 = pTos->u.i==0;
}
if( pNos->flags & MEM_Null ){
v2 = 2;
}else{
sqlite3VdbeMemIntegerify(pNos);
- v2 = pNos->i==0;
+ v2 = pNos->u.i==0;
}
if( pOp->opcode==OP_And ){
static const unsigned char and_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 };
@@ -1679,7 +1695,7 @@ case OP_Or: { /* same as TK_OR, no-push */
if( v1==2 ){
pTos->flags = MEM_Null;
}else{
- pTos->i = v1==0;
+ pTos->u.i = v1==0;
pTos->flags = MEM_Int;
}
break;
@@ -1709,8 +1725,8 @@ case OP_AbsValue: {
pTos->flags = MEM_Real;
}else if( pTos->flags & MEM_Int ){
Release(pTos);
- if( pOp->opcode==OP_Negative || pTos->i<0 ){
- pTos->i = -pTos->i;
+ if( pOp->opcode==OP_Negative || pTos->u.i<0 ){
+ pTos->u.i = -pTos->u.i;
}
pTos->flags = MEM_Int;
}else if( pTos->flags & MEM_Null ){
@@ -1733,7 +1749,7 @@ case OP_Not: { /* same as TK_NOT, no-push */
if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
sqlite3VdbeMemIntegerify(pTos);
assert( (pTos->flags & MEM_Dyn)==0 );
- pTos->i = !pTos->i;
+ pTos->u.i = !pTos->u.i;
pTos->flags = MEM_Int;
break;
}
@@ -1749,7 +1765,7 @@ case OP_BitNot: { /* same as TK_BITNOT, no-push */
if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */
sqlite3VdbeMemIntegerify(pTos);
assert( (pTos->flags & MEM_Dyn)==0 );
- pTos->i = ~pTos->i;
+ pTos->u.i = ~pTos->u.i;
pTos->flags = MEM_Int;
break;
}
@@ -1812,32 +1828,31 @@ case OP_IfNot: { /* no-push */
/* Opcode: IsNull P1 P2 *
**
-** If any of the top abs(P1) values on the stack are NULL, then jump
-** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack
-** unchanged.
+** Check the top of the stack and jump to P2 if the top of the stack
+** is NULL. If P1 is positive, then pop P1 elements from the stack
+** regardless of whether or not the jump is taken. If P1 is negative,
+** pop -P1 elements from the stack only if the jump is taken and leave
+** the stack unchanged if the jump is not taken.
*/
case OP_IsNull: { /* same as TK_ISNULL, no-push */
- int i, cnt;
- Mem *pTerm;
- cnt = pOp->p1;
- if( cnt<0 ) cnt = -cnt;
- pTerm = &pTos[1-cnt];
- assert( pTerm>=p->aStack );
- for(i=0; i<cnt; i++, pTerm++){
- if( pTerm->flags & MEM_Null ){
- pc = pOp->p2-1;
- break;
+ if( pTos->flags & MEM_Null ){
+ pc = pOp->p2-1;
+ if( pOp->p1<0 ){
+ popStack(&pTos, -pOp->p1);
}
}
- if( pOp->p1>0 ) popStack(&pTos, cnt);
+ if( pOp->p1>0 ){
+ popStack(&pTos, pOp->p1);
+ }
break;
}
/* Opcode: NotNull P1 P2 *
**
-** Jump to P2 if the top P1 values on the stack are all not NULL. Pop the
-** stack if P1 times if P1 is greater than zero. If P1 is less than
-** zero then leave the stack unchanged.
+** Jump to P2 if the top abs(P1) values on the stack are all not NULL.
+** Regardless of whether or not the jump is taken, pop the stack
+** P1 times if P1 is greater than zero. But if P1 is negative,
+** leave the stack unchanged.
*/
case OP_NotNull: { /* same as TK_NOTNULL, no-push */
int i, cnt;
@@ -1922,6 +1937,9 @@ case OP_Column: {
** which is the number of records.
*/
pC = p->apCsr[p1];
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+ assert( pC->pVtabCursor==0 );
+#endif
assert( pC!=0 );
if( pC->pCursor!=0 ){
/* The record is stored in a B-Tree */
@@ -2010,7 +2028,9 @@ case OP_Column: {
pC->aRow = 0;
}
}
- assert( zRec!=0 || avail>=payloadSize || avail>=9 );
+ /* The following assert is true in all cases accept when
+ ** the database file has been corrupted externally.
+ ** assert( zRec!=0 || avail>=payloadSize || avail>=9 ); */
szHdrSz = GetVarint((u8*)zData, offset);
/* The KeyFetch() or DataFetch() above are fast and will get the entire
@@ -2429,7 +2449,7 @@ case OP_ReadCookie: {
*/
rc = sqlite3BtreeGetMeta(db->aDb[pOp->p1].pBt, 1 + pOp->p2, (u32 *)&iMeta);
pTos++;
- pTos->i = iMeta;
+ pTos->u.i = iMeta;
pTos->flags = MEM_Int;
break;
}
@@ -2453,14 +2473,14 @@ case OP_SetCookie: { /* no-push */
assert( pTos>=p->aStack );
sqlite3VdbeMemIntegerify(pTos);
/* See note about index shifting on OP_ReadCookie */
- rc = sqlite3BtreeUpdateMeta(pDb->pBt, 1+pOp->p2, (int)pTos->i);
+ rc = sqlite3BtreeUpdateMeta(pDb->pBt, 1+pOp->p2, (int)pTos->u.i);
if( pOp->p2==0 ){
/* When the schema cookie changes, record the new cookie internally */
- pDb->pSchema->schema_cookie = pTos->i;
+ pDb->pSchema->schema_cookie = pTos->u.i;
db->flags |= SQLITE_InternChanges;
}else if( pOp->p2==1 ){
/* Record changes in the file format */
- pDb->pSchema->file_format = pTos->i;
+ pDb->pSchema->file_format = pTos->u.i;
}
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
@@ -2501,6 +2521,24 @@ case OP_VerifyCookie: { /* no-push */
}
if( rc==SQLITE_OK && iMeta!=pOp->p2 ){
sqlite3SetString(&p->zErrMsg, "database schema has changed", (char*)0);
+ /* If the schema-cookie from the database file matches the cookie
+ ** stored with the in-memory representation of the schema, do
+ ** not reload the schema from the database file.
+ **
+ ** If virtual-tables are in use, this is not just an optimisation.
+ ** Often, v-tables store their data in other SQLite tables, which
+ ** are queried from within xNext() and other v-table methods using
+ ** prepared queries. If such a query is out-of-date, we do not want to
+ ** discard the database schema, as the user code implementing the
+ ** v-table would have to be ready for the sqlite3_vtab structure itself
+ ** to be invalidated whenever sqlite3_step() is called from within
+ ** a v-table method.
+ */
+ if( db->aDb[pOp->p1].pSchema->schema_cookie!=iMeta ){
+ sqlite3ResetInternalSchema(db, pOp->p1);
+ }
+
+ sqlite3ExpirePreparedStatements(db);
rc = SQLITE_SCHEMA;
}
break;
@@ -2560,7 +2598,7 @@ case OP_OpenWrite: { /* no-push */
assert( pTos>=p->aStack );
sqlite3VdbeMemIntegerify(pTos);
- iDb = pTos->i;
+ iDb = pTos->u.i;
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
assert( iDb>=0 && iDb<db->nDb );
@@ -2578,7 +2616,7 @@ case OP_OpenWrite: { /* no-push */
if( p2<=0 ){
assert( pTos>=p->aStack );
sqlite3VdbeMemIntegerify(pTos);
- p2 = pTos->i;
+ p2 = pTos->u.i;
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
assert( p2>=2 );
@@ -2804,7 +2842,7 @@ case OP_MoveGt: { /* no-push */
if( pC->isTable ){
i64 iKey;
sqlite3VdbeMemIntegerify(pTos);
- iKey = intToKey(pTos->i);
+ iKey = intToKey(pTos->u.i);
if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){
pC->movetoTarget = iKey;
pC->deferredMoveto = 1;
@@ -2812,16 +2850,16 @@ case OP_MoveGt: { /* no-push */
pTos--;
break;
}
- rc = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, &res);
+ rc = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)iKey, 0, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
- pC->lastRowid = pTos->i;
+ pC->lastRowid = pTos->u.i;
pC->rowidIsValid = res==0;
}else{
assert( pTos->flags & MEM_Blob );
/* Stringify(pTos, encoding); */
- rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
+ rc = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, 0, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
@@ -2907,7 +2945,7 @@ case OP_MoveGt: { /* no-push */
**
** The top of the stack holds a blob constructed by MakeRecord. P1 is
** an index. If no entry exists in P1 that matches the blob then jump
-** to P1. If an entry does existing, fall through. The cursor is left
+** to P2. If an entry does existing, fall through. The cursor is left
** pointing to the entry that matches. The blob is popped from the stack.
**
** The difference between this operation and Distinct is that
@@ -2928,7 +2966,7 @@ case OP_Found: { /* no-push */
int res, rx;
assert( pC->isTable==0 );
Stringify(pTos, encoding);
- rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res);
+ rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, 0, &res);
alreadyExists = rx==SQLITE_OK && res==0;
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
@@ -2977,10 +3015,10 @@ case OP_IsUnique: { /* no-push */
*/
assert( pNos>=p->aStack );
sqlite3VdbeMemIntegerify(pTos);
- R = pTos->i;
+ R = pTos->u.i;
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
- assert( i>=0 && i<=p->nCursor );
+ assert( i>=0 && i<p->nCursor );
pCx = p->apCsr[i];
assert( pCx!=0 );
pCrsr = pCx->pCursor;
@@ -3006,7 +3044,7 @@ case OP_IsUnique: { /* no-push */
*/
assert( pCx->deferredMoveto==0 );
pCx->cacheStatus = CACHE_STALE;
- rc = sqlite3BtreeMoveto(pCrsr, zKey, len, &res);
+ rc = sqlite3BtreeMoveto(pCrsr, zKey, len, 0, &res);
if( rc!=SQLITE_OK ){
goto abort_due_to_error;
}
@@ -3043,7 +3081,7 @@ case OP_IsUnique: { /* no-push */
** constraint.)
*/
pTos++;
- pTos->i = v;
+ pTos->u.i = v;
pTos->flags = MEM_Int;
}
break;
@@ -3075,12 +3113,17 @@ case OP_NotExists: { /* no-push */
u64 iKey;
assert( pTos->flags & MEM_Int );
assert( p->apCsr[i]->isTable );
- iKey = intToKey(pTos->i);
- rc = sqlite3BtreeMoveto(pCrsr, 0, iKey, &res);
- pC->lastRowid = pTos->i;
+ iKey = intToKey(pTos->u.i);
+ rc = sqlite3BtreeMoveto(pCrsr, 0, iKey, 0,&res);
+ pC->lastRowid = pTos->u.i;
pC->rowidIsValid = res==0;
pC->nullRow = 0;
pC->cacheStatus = CACHE_STALE;
+ /* res might be uninitialized if rc!=SQLITE_OK. But if rc!=SQLITE_OK
+ ** processing is about to abort so we really do not care whether or not
+ ** the following jump is taken. (In other words, do not stress over
+ ** the error that valgrind sometimes shows on the next statement when
+ ** running ioerr.test and similar failure-recovery test scripts.) */
if( res!=0 ){
pc = pOp->p2 - 1;
pC->rowidIsValid = 0;
@@ -3103,7 +3146,7 @@ case OP_Sequence: {
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
pTos++;
- pTos->i = p->apCsr[i]->seqCount++;
+ pTos->u.i = p->apCsr[i]->seqCount++;
pTos->flags = MEM_Int;
break;
}
@@ -3212,14 +3255,14 @@ case OP_NewRowid: {
pMem = &p->aMem[pOp->p2];
sqlite3VdbeMemIntegerify(pMem);
assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P2) holds an integer */
- if( pMem->i==MAX_ROWID || pC->useRandomRowid ){
+ if( pMem->u.i==MAX_ROWID || pC->useRandomRowid ){
rc = SQLITE_FULL;
goto abort_due_to_error;
}
- if( v<pMem->i+1 ){
- v = pMem->i + 1;
+ if( v<pMem->u.i+1 ){
+ v = pMem->u.i + 1;
}
- pMem->i = v;
+ pMem->u.i = v;
}
#endif
@@ -3245,7 +3288,7 @@ case OP_NewRowid: {
}
if( v==0 ) continue;
x = intToKey(v);
- rx = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)x, &res);
+ rx = sqlite3BtreeMoveto(pC->pCursor, 0, (u64)x, 0, &res);
cnt++;
}while( cnt<1000 && rx==SQLITE_OK && res==0 );
db->priorNewRowid = v;
@@ -3259,7 +3302,7 @@ case OP_NewRowid: {
pC->cacheStatus = CACHE_STALE;
}
pTos++;
- pTos->i = v;
+ pTos->u.i = v;
pTos->flags = MEM_Int;
break;
}
@@ -3296,11 +3339,11 @@ case OP_Insert: { /* no-push */
assert( pNos->flags & MEM_Int );
assert( pC->isTable );
- iKey = intToKey(pNos->i);
+ iKey = intToKey(pNos->u.i);
if( pOp->p2 & OPFLAG_NCHANGE ) p->nChange++;
- if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->i;
- if( pC->nextRowidValid && pNos->i>=pC->nextRowid ){
+ if( pOp->p2 & OPFLAG_LASTROWID ) db->lastRowid = pNos->u.i;
+ if( pC->nextRowidValid && pNos->u.i>=pC->nextRowid ){
pC->nextRowidValid = 0;
}
if( pTos->flags & MEM_Null ){
@@ -3325,7 +3368,9 @@ case OP_Insert: { /* no-push */
}
pC->nullRow = 0;
}else{
- rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, pTos->z, pTos->n);
+ rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
+ pTos->z, pTos->n,
+ pOp->p2 & OPFLAG_APPEND);
}
pC->rowidIsValid = 0;
@@ -3479,9 +3524,9 @@ case OP_RowData: {
pTos->z = z;
}
if( pC->isIndex ){
- sqlite3BtreeKey(pCrsr, 0, n, pTos->z);
+ rc = sqlite3BtreeKey(pCrsr, 0, n, pTos->z);
}else{
- sqlite3BtreeData(pCrsr, 0, n, pTos->z);
+ rc = sqlite3BtreeData(pCrsr, 0, n, pTos->z);
}
}else if( pC->pseudoTable ){
pTos->n = pC->nData;
@@ -3522,7 +3567,7 @@ case OP_Rowid: {
sqlite3BtreeKeySize(pC->pCursor, &v);
v = keyToInt(v);
}
- pTos->i = v;
+ pTos->u.i = v;
pTos->flags = MEM_Int;
break;
}
@@ -3652,7 +3697,9 @@ case OP_Next: { /* no-push */
CHECK_FOR_INTERRUPT;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
- assert( pC!=0 );
+ if( pC==0 ){
+ break; /* See ticket #2273 */
+ }
if( (pCrsr = pC->pCursor)!=0 ){
int res;
if( pC->nullRow ){
@@ -3677,12 +3724,15 @@ case OP_Next: { /* no-push */
break;
}
-/* Opcode: IdxInsert P1 * *
+/* Opcode: IdxInsert P1 P2 *
**
** The top of the stack holds a SQL index key made using either the
** MakeIdxRec or MakeRecord instructions. This opcode writes that key
** into the index P1. Data for the entry is nil.
**
+** P2 is a flag that provides a hint to the b-tree layer that this
+** insert is likely to be an append.
+**
** This instruction only works for indices. The equivalent instruction
** for tables is OP_Insert.
*/
@@ -3694,12 +3744,11 @@ case OP_IdxInsert: { /* no-push */
assert( i>=0 && i<p->nCursor );
assert( p->apCsr[i]!=0 );
assert( pTos->flags & MEM_Blob );
- assert( pOp->p2==0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
int nKey = pTos->n;
const char *zKey = pTos->z;
assert( pC->isTable==0 );
- rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0);
+ rc = sqlite3BtreeInsert(pCrsr, zKey, nKey, "", 0, pOp->p2);
assert( pC->deferredMoveto==0 );
pC->cacheStatus = CACHE_STALE;
}
@@ -3724,7 +3773,7 @@ case OP_IdxDelete: { /* no-push */
assert( p->apCsr[i]!=0 );
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
int res;
- rc = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, &res);
+ rc = sqlite3BtreeMoveto(pCrsr, pTos->z, pTos->n, 0, &res);
if( rc==SQLITE_OK && res==0 ){
rc = sqlite3BtreeDelete(pCrsr);
}
@@ -3766,7 +3815,7 @@ case OP_IdxRowid: {
goto abort_due_to_error;
}
pTos->flags = MEM_Int;
- pTos->i = rowid;
+ pTos->u.i = rowid;
}
}
break;
@@ -3852,38 +3901,6 @@ case OP_IdxGE: { /* no-push */
break;
}
-/* Opcode: IdxIsNull P1 P2 *
-**
-** The top of the stack contains an index entry such as might be generated
-** by the MakeIdxRec opcode. This routine looks at the first P1 fields of
-** that key. If any of the first P1 fields are NULL, then a jump is made
-** to address P2. Otherwise we fall straight through.
-**
-** The index entry is always popped from the stack.
-*/
-case OP_IdxIsNull: { /* no-push */
- int i = pOp->p1;
- int k, n;
- const char *z;
- u32 serial_type;
-
- assert( pTos>=p->aStack );
- assert( pTos->flags & MEM_Blob );
- z = pTos->z;
- n = pTos->n;
- k = sqlite3GetVarint32((u8*)z, &serial_type);
- for(; k<n && i>0; i--){
- k += sqlite3GetVarint32((u8*)&z[k], &serial_type);
- if( serial_type==0 ){ /* Serial type 0 is a NULL */
- pc = pOp->p2-1;
- break;
- }
- }
- Release(pTos);
- pTos--;
- break;
-}
-
/* Opcode: Destroy P1 P2 *
**
** Delete an entire database table or index whose root page in the database
@@ -3906,9 +3923,9 @@ case OP_IdxIsNull: { /* no-push */
*/
case OP_Destroy: {
int iMoved;
- Vdbe *pVdbe;
int iCnt;
#ifndef SQLITE_OMIT_VIRTUALTABLE
+ Vdbe *pVdbe;
iCnt = 0;
for(pVdbe=db->pVdbe; pVdbe; pVdbe=pVdbe->pNext){
if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 ){
@@ -3925,7 +3942,7 @@ case OP_Destroy: {
rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved);
pTos++;
pTos->flags = MEM_Int;
- pTos->i = iMoved;
+ pTos->u.i = iMoved;
#ifndef SQLITE_OMIT_AUTOVACUUM
if( rc==SQLITE_OK && iMoved!=0 ){
sqlite3RootPageMoved(&db->aDb[pOp->p2], iMoved, pOp->p1);
@@ -4024,7 +4041,7 @@ case OP_CreateTable: {
rc = sqlite3BtreeCreateTable(pDb->pBt, &pgno, flags);
pTos++;
if( rc==SQLITE_OK ){
- pTos->i = pgno;
+ pTos->u.i = pgno;
pTos->flags = MEM_Int;
}else{
pTos->flags = MEM_Null;
@@ -4032,10 +4049,14 @@ case OP_CreateTable: {
break;
}
-/* Opcode: ParseSchema P1 * P3
+/* Opcode: ParseSchema P1 P2 P3
**
** Read and parse all entries from the SQLITE_MASTER table of database P1
-** that match the WHERE clause P3.
+** that match the WHERE clause P3. P2 is the "force" flag. Always do
+** the parsing if P2 is true. If P2 is false, then this routine is a
+** no-op if the schema is not currently loaded. In other words, if P2
+** is false, the SQLITE_MASTER table is only parsed if the rest of the
+** schema is already loaded into the symbol table.
**
** This opcode invokes the parser to create a new virtual machine,
** then runs the new virtual machine. It is thus a reentrant opcode.
@@ -4047,13 +4068,16 @@ case OP_ParseSchema: { /* no-push */
InitData initData;
assert( iDb>=0 && iDb<db->nDb );
- if( !DbHasProperty(db, iDb, DB_SchemaLoaded) ) break;
+ if( !pOp->p2 && !DbHasProperty(db, iDb, DB_SchemaLoaded) ){
+ break;
+ }
zMaster = SCHEMA_TABLE(iDb);
initData.db = db;
+ initData.iDb = pOp->p1;
initData.pzErrMsg = &p->zErrMsg;
zSql = sqlite3MPrintf(
- "SELECT name, rootpage, sql, %d FROM '%q'.%s WHERE %s",
- pOp->p1, db->aDb[iDb].zName, zMaster, pOp->p3);
+ "SELECT name, rootpage, sql FROM '%q'.%s WHERE %s",
+ db->aDb[iDb].zName, zMaster, pOp->p3);
if( zSql==0 ) goto no_mem;
sqlite3SafetyOff(db);
assert( db->init.busy==0 );
@@ -4124,11 +4148,16 @@ case OP_DropTrigger: { /* no-push */
#ifndef SQLITE_OMIT_INTEGRITY_CHECK
-/* Opcode: IntegrityCk * P2 *
+/* Opcode: IntegrityCk P1 P2 *
**
** Do an analysis of the currently open database. Push onto the
** stack the text of an error message describing any problems.
-** If there are no errors, push a "ok" onto the stack.
+** If no problems are found, push a NULL onto the stack.
+**
+** P1 is the address of a memory cell that contains the maximum
+** number of allowed errors. At most mem[P1] errors will be reported.
+** In other words, the analysis stops as soon as mem[P1] errors are
+** seen. Mem[P1] is updated with the number of errors remaining.
**
** The root page numbers of all tables in the database are integer
** values on the stack. This opcode pulls as many integers as it
@@ -4137,13 +4166,15 @@ case OP_DropTrigger: { /* no-push */
** If P2 is not zero, the check is done on the auxiliary database
** file, not the main database file.
**
-** This opcode is used for testing purposes only.
+** This opcode is used to implement the integrity_check pragma.
*/
case OP_IntegrityCk: {
int nRoot;
int *aRoot;
int j;
+ int nErr;
char *z;
+ Mem *pnErr;
for(nRoot=0; &pTos[-nRoot]>=p->aStack; nRoot++){
if( (pTos[-nRoot].flags & MEM_Int)==0 ) break;
@@ -4151,19 +4182,23 @@ case OP_IntegrityCk: {
assert( nRoot>0 );
aRoot = sqliteMallocRaw( sizeof(int*)*(nRoot+1) );
if( aRoot==0 ) goto no_mem;
+ j = pOp->p1;
+ assert( j>=0 && j<p->nMem );
+ pnErr = &p->aMem[j];
+ assert( (pnErr->flags & MEM_Int)!=0 );
for(j=0; j<nRoot; j++){
Mem *pMem = &pTos[-j];
- aRoot[j] = pMem->i;
+ aRoot[j] = pMem->u.i;
}
aRoot[j] = 0;
popStack(&pTos, nRoot);
pTos++;
- z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot);
- if( z==0 || z[0]==0 ){
- if( z ) sqliteFree(z);
- pTos->z = "ok";
- pTos->n = 2;
- pTos->flags = MEM_Str | MEM_Static | MEM_Term;
+ z = sqlite3BtreeIntegrityCheck(db->aDb[pOp->p2].pBt, aRoot, nRoot,
+ pnErr->u.i, &nErr);
+ pnErr->u.i -= nErr;
+ if( nErr==0 ){
+ assert( z==0 );
+ pTos->flags = MEM_Null;
}else{
pTos->z = z;
pTos->n = strlen(z);
@@ -4185,7 +4220,7 @@ case OP_IntegrityCk: {
case OP_FifoWrite: { /* no-push */
assert( pTos>=p->aStack );
sqlite3VdbeMemIntegerify(pTos);
- sqlite3VdbeFifoPush(&p->sFifo, pTos->i);
+ sqlite3VdbeFifoPush(&p->sFifo, pTos->u.i);
assert( (pTos->flags & MEM_Dyn)==0 );
pTos--;
break;
@@ -4204,7 +4239,7 @@ case OP_FifoRead: {
pc = pOp->p2 - 1;
}else{
pTos++;
- pTos->i = v;
+ pTos->u.i = v;
pTos->flags = MEM_Int;
}
break;
@@ -4225,7 +4260,8 @@ case OP_ContextPush: { /* no-push */
/* FIX ME: This should be allocated as part of the vdbe at compile-time */
if( i>=p->contextStackDepth ){
p->contextStackDepth = i+1;
- sqliteReallocOrFree((void**)&p->contextStack, sizeof(Context)*(i+1));
+ p->contextStack = sqliteReallocOrFree(p->contextStack,
+ sizeof(Context)*(i+1));
if( p->contextStack==0 ) goto no_mem;
}
pContext = &p->contextStack[i];
@@ -4310,8 +4346,8 @@ case OP_MemMax: { /* no-push */
pMem = &p->aMem[i];
sqlite3VdbeMemIntegerify(pMem);
sqlite3VdbeMemIntegerify(pTos);
- if( pMem->i<pTos->i){
- pMem->i = pTos->i;
+ if( pMem->u.i<pTos->u.i){
+ pMem->u.i = pTos->u.i;
}
break;
}
@@ -4330,7 +4366,7 @@ case OP_MemIncr: { /* no-push */
assert( i>=0 && i<p->nMem );
pMem = &p->aMem[i];
assert( pMem->flags==MEM_Int );
- pMem->i += pOp->p1;
+ pMem->u.i += pOp->p1;
break;
}
@@ -4347,7 +4383,7 @@ case OP_IfMemPos: { /* no-push */
assert( i>=0 && i<p->nMem );
pMem = &p->aMem[i];
assert( pMem->flags==MEM_Int );
- if( pMem->i>0 ){
+ if( pMem->u.i>0 ){
pc = pOp->p2 - 1;
}
break;
@@ -4366,7 +4402,7 @@ case OP_IfMemNeg: { /* no-push */
assert( i>=0 && i<p->nMem );
pMem = &p->aMem[i];
assert( pMem->flags==MEM_Int );
- if( pMem->i<0 ){
+ if( pMem->u.i<0 ){
pc = pOp->p2 - 1;
}
break;
@@ -4385,7 +4421,7 @@ case OP_IfMemZero: { /* no-push */
assert( i>=0 && i<p->nMem );
pMem = &p->aMem[i];
assert( pMem->flags==MEM_Int );
- if( pMem->i==0 ){
+ if( pMem->u.i==0 ){
pc = pOp->p2 - 1;
}
break;
@@ -4499,6 +4535,7 @@ case OP_AggFinal: { /* no-push */
}
+#if !defined(SQLITE_OMIT_VACUUM) && !defined(SQLITE_OMIT_ATTACH)
/* Opcode: Vacuum * * *
**
** Vacuum the entire database. This opcode will cause other virtual
@@ -4511,6 +4548,7 @@ case OP_Vacuum: { /* no-push */
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
break;
}
+#endif
/* Opcode: Expire P1 * *
**
@@ -4670,11 +4708,11 @@ case OP_VFilter: { /* no-push */
/* Grab the index number and argc parameters off the top of the stack. */
assert( (&pTos[-1])>=p->aStack );
assert( (pTos[0].flags&MEM_Int)!=0 && pTos[-1].flags==MEM_Int );
- nArg = pTos[-1].i;
+ nArg = pTos[-1].u.i;
- /* Invoke the xFilter method if one is defined. */
- if( pModule->xFilter ){
- int res;
+ /* Invoke the xFilter method */
+ {
+ int res = 0;
int i;
Mem **apArg = p->apArg;
for(i = 0; i<nArg; i++){
@@ -4684,7 +4722,7 @@ case OP_VFilter: { /* no-push */
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
p->inVtabMethod = 1;
- rc = pModule->xFilter(pCur->pVtabCursor, pTos->i, pOp->p3, nArg, apArg);
+ rc = pModule->xFilter(pCur->pVtabCursor, pTos->u.i, pOp->p3, nArg, apArg);
p->inVtabMethod = 0;
if( rc==SQLITE_OK ){
res = pModule->xEof(pCur->pVtabCursor);
@@ -4726,7 +4764,7 @@ case OP_VRowid: {
pTos++;
pTos->flags = MEM_Int;
- pTos->i = iRow;
+ pTos->u.i = iRow;
}
break;
@@ -4857,7 +4895,9 @@ case OP_VUpdate: { /* no-push */
apArg[i] = pX;
}
if( sqlite3SafetyOff(db) ) goto abort_due_to_misuse;
+ sqlite3VtabLock(pVtab);
rc = pModule->xUpdate(pVtab, nArg, apArg, &rowid);
+ sqlite3VtabUnlock(db, pVtab);
if( sqlite3SafetyOn(db) ) goto abort_due_to_misuse;
if( pOp->p1 && rc==SQLITE_OK ){
assert( nArg>1 && apArg[0] && (apArg[0]->flags&MEM_Null) );
@@ -4923,9 +4963,9 @@ default: {
if( pTos[i].flags & MEM_Null ){
fprintf(p->trace, " NULL");
}else if( (pTos[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){
- fprintf(p->trace, " si:%lld", pTos[i].i);
+ fprintf(p->trace, " si:%lld", pTos[i].u.i);
}else if( pTos[i].flags & MEM_Int ){
- fprintf(p->trace, " i:%lld", pTos[i].i);
+ fprintf(p->trace, " i:%lld", pTos[i].u.i);
}else if( pTos[i].flags & MEM_Real ){
fprintf(p->trace, " r:%g", pTos[i].r);
}else{
diff --git a/ext/pdo_sqlite/sqlite/src/vdbe.h b/ext/pdo_sqlite/sqlite/src/vdbe.h
index 903a18dcd..385a60bd8 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbe.h
+++ b/ext/pdo_sqlite/sqlite/src/vdbe.h
@@ -129,12 +129,16 @@ int sqlite3VdbeFinalize(Vdbe*);
void sqlite3VdbeResolveLabel(Vdbe*, int);
int sqlite3VdbeCurrentAddr(Vdbe*);
void sqlite3VdbeTrace(Vdbe*,FILE*);
+void sqlite3VdbeResetStepResult(Vdbe*);
int sqlite3VdbeReset(Vdbe*);
int sqliteVdbeSetVariables(Vdbe*,int,const char**);
void sqlite3VdbeSetNumCols(Vdbe*,int);
int sqlite3VdbeSetColName(Vdbe*, int, int, const char *, int);
void sqlite3VdbeCountChanges(Vdbe*);
sqlite3 *sqlite3VdbeDb(Vdbe*);
+void sqlite3VdbeSetSql(Vdbe*, const char *z, int n);
+const char *sqlite3VdbeGetSql(Vdbe*);
+void sqlite3VdbeSwap(Vdbe*,Vdbe*);
#ifndef NDEBUG
void sqlite3VdbeComment(Vdbe*, const char*, ...);
diff --git a/ext/pdo_sqlite/sqlite/src/vdbeInt.h b/ext/pdo_sqlite/sqlite/src/vdbeInt.h
index db8034061..11c906100 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbeInt.h
+++ b/ext/pdo_sqlite/sqlite/src/vdbeInt.h
@@ -15,6 +15,8 @@
** 6000 lines long) it was split up into several smaller files and
** this header information was factored out.
*/
+#ifndef _VDBEINT_H_
+#define _VDBEINT_H_
/*
** intToKey() and keyToInt() used to transform the rowid. But with
@@ -29,7 +31,7 @@
** array is defined in a separate source code file named opcode.c which is
** automatically generated by the makefile.
*/
-extern char *sqlite3OpcodeNames[];
+extern const char *const sqlite3OpcodeNames[];
/*
** SQL is translated into a sequence of instructions to be
@@ -123,7 +125,10 @@ typedef struct Cursor Cursor;
** SQLITE_BLOB.
*/
struct Mem {
- i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
+ union {
+ i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
+ FuncDef *pDef; /* Used only when flags==MEM_Agg */
+ } u;
double r; /* Real value */
char *z; /* String or BLOB value */
int n; /* Number of characters in string value, including '\0' */
@@ -328,6 +333,8 @@ struct Vdbe {
u8 inVtabMethod; /* See comments above */
int nChange; /* Number of db changes made since last reset */
i64 startTime; /* Time when query started - used for profiling */
+ int nSql; /* Number of bytes in zSql */
+ char *zSql; /* Text of the SQL statement that generated this */
#ifdef SQLITE_SSE
int fetchId; /* Statement number used by sqlite3_fetch_statement */
int lru; /* Counter used for LRU cache replacement */
@@ -401,3 +408,5 @@ void sqlite3VdbeFifoInit(Fifo*);
int sqlite3VdbeFifoPush(Fifo*, i64);
int sqlite3VdbeFifoPop(Fifo*, i64*);
void sqlite3VdbeFifoClear(Fifo*);
+
+#endif /* !defined(_VDBEINT_H_) */
diff --git a/ext/pdo_sqlite/sqlite/src/vdbeapi.c b/ext/pdo_sqlite/sqlite/src/vdbeapi.c
index a0ced3d79..3d3d815c7 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbeapi.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbeapi.c
@@ -153,9 +153,13 @@ void sqlite3_result_value(sqlite3_context *pCtx, sqlite3_value *pValue){
/*
** Execute the statement pStmt, either until a row of data is ready, the
** statement is completely executed or an error occurs.
+**
+** This routine implements the bulk of the logic behind the sqlite_step()
+** API. The only thing omitted is the automatic recompile if a
+** schema change has occurred. That detail is handled by the
+** outer sqlite3_step() wrapper procedure.
*/
-int sqlite3_step(sqlite3_stmt *pStmt){
- Vdbe *p = (Vdbe*)pStmt;
+static int sqlite3Step(Vdbe *p){
sqlite3 *db;
int rc;
@@ -172,7 +176,8 @@ int sqlite3_step(sqlite3_stmt *pStmt){
if( p->rc==SQLITE_OK ){
p->rc = SQLITE_SCHEMA;
}
- return SQLITE_ERROR;
+ rc = SQLITE_ERROR;
+ goto end_of_step;
}
db = p->db;
if( sqlite3SafetyOn(db) ){
@@ -254,8 +259,42 @@ int sqlite3_step(sqlite3_stmt *pStmt){
sqlite3Error(p->db, rc, 0);
p->rc = sqlite3ApiExit(p->db, p->rc);
+end_of_step:
+ assert( (rc&0xff)==rc );
+ if( p->zSql && (rc&0xff)<SQLITE_ROW ){
+ /* This behavior occurs if sqlite3_prepare_v2() was used to build
+ ** the prepared statement. Return error codes directly */
+ return p->rc;
+ }else{
+ /* This is for legacy sqlite3_prepare() builds and when the code
+ ** is SQLITE_ROW or SQLITE_DONE */
+ return rc;
+ }
+}
+
+/*
+** This is the top-level implementation of sqlite3_step(). Call
+** sqlite3Step() to do most of the work. If a schema error occurs,
+** call sqlite3Reprepare() and try again.
+*/
+#ifdef SQLITE_OMIT_PARSER
+int sqlite3_step(sqlite3_stmt *pStmt){
+ return sqlite3Step((Vdbe*)pStmt);
+}
+#else
+int sqlite3_step(sqlite3_stmt *pStmt){
+ int cnt = 0;
+ int rc;
+ Vdbe *v = (Vdbe*)pStmt;
+ while( (rc = sqlite3Step(v))==SQLITE_SCHEMA
+ && cnt++ < 5
+ && sqlite3Reprepare(v) ){
+ sqlite3_reset(pStmt);
+ v->expired = 0;
+ }
return rc;
}
+#endif
/*
** Extract the user data from a sqlite3_context structure and return a
@@ -267,6 +306,27 @@ void *sqlite3_user_data(sqlite3_context *p){
}
/*
+** The following is the implementation of an SQL function that always
+** fails with an error message stating that the function is used in the
+** wrong context. The sqlite3_overload_function() API might construct
+** SQL function that use this routine so that the functions will exist
+** for name resolution but are actually overloaded by the xFindFunction
+** method of virtual tables.
+*/
+void sqlite3InvalidFunction(
+ sqlite3_context *context, /* The function calling context */
+ int argc, /* Number of arguments to the function */
+ sqlite3_value **argv /* Value of each argument */
+){
+ const char *zName = context->pFunc->zName;
+ char *zErr;
+ zErr = sqlite3MPrintf(
+ "unable to use function %s in the requested context", zName);
+ sqlite3_result_error(context, zErr, -1);
+ sqliteFree(zErr);
+}
+
+/*
** Allocate or return the aggregate context for a user function. A new
** context is allocated on the first call. Subsequent calls return the
** same context that was returned on prior calls.
@@ -281,7 +341,7 @@ void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
}else{
pMem->flags = MEM_Agg;
pMem->xDel = sqlite3FreeX;
- *(FuncDef**)&pMem->i = p->pFunc;
+ pMem->u.pDef = p->pFunc;
if( nByte<=NBFS ){
pMem->z = pMem->zShort;
memset(pMem->z, 0, nByte);
@@ -383,7 +443,7 @@ static Mem *columnMem(sqlite3_stmt *pStmt, int i){
Vdbe *pVm = (Vdbe *)pStmt;
int vals = sqlite3_data_count(pStmt);
if( i>=vals || i<0 ){
- static const Mem nullMem = {0, 0.0, "", 0, MEM_Null, MEM_Null };
+ static const Mem nullMem = {{0}, 0.0, "", 0, MEM_Null, MEM_Null };
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
return (Mem*)&nullMem;
}
@@ -815,6 +875,7 @@ int sqlite3_transfer_bindings(sqlite3_stmt *pFromStmt, sqlite3_stmt *pToStmt){
rc = sqlite3VdbeMemMove(&pTo->aVar[i], &pFrom->aVar[i]);
sqlite3MallocAllow();
}
+ assert( rc==SQLITE_OK || rc==SQLITE_NOMEM );
return rc;
}
diff --git a/ext/pdo_sqlite/sqlite/src/vdbeaux.c b/ext/pdo_sqlite/sqlite/src/vdbeaux.c
index c71c8f4ea..6c1af395a 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbeaux.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbeaux.c
@@ -49,6 +49,46 @@ Vdbe *sqlite3VdbeCreate(sqlite3 *db){
}
/*
+** Remember the SQL string for a prepared statement.
+*/
+void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n){
+ if( p==0 ) return;
+ assert( p->zSql==0 );
+ p->zSql = sqlite3StrNDup(z, n);
+}
+
+/*
+** Return the SQL associated with a prepared statement
+*/
+const char *sqlite3VdbeGetSql(Vdbe *p){
+ return p->zSql;
+}
+
+/*
+** Swap all content between two VDBE structures.
+*/
+void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){
+ Vdbe tmp, *pTmp;
+ char *zTmp;
+ int nTmp;
+ tmp = *pA;
+ *pA = *pB;
+ *pB = tmp;
+ pTmp = pA->pNext;
+ pA->pNext = pB->pNext;
+ pB->pNext = pTmp;
+ pTmp = pA->pPrev;
+ pA->pPrev = pB->pPrev;
+ pB->pPrev = pTmp;
+ zTmp = pA->zSql;
+ pA->zSql = pB->zSql;
+ pB->zSql = zTmp;
+ nTmp = pA->nSql;
+ pA->nSql = pB->nSql;
+ pB->nSql = nTmp;
+}
+
+/*
** Turn tracing on or off
*/
void sqlite3VdbeTrace(Vdbe *p, FILE *trace){
@@ -105,7 +145,6 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
VdbeOp *pOp;
i = p->nOp;
- p->nOp++;
assert( p->magic==VDBE_MAGIC_INIT );
if( p->nOpAlloc<=i ){
resizeOpArray(p, i+1);
@@ -113,6 +152,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
return 0;
}
}
+ p->nOp++;
pOp = &p->aOp[i];
pOp->opcode = op;
pOp->p1 = p1;
@@ -155,8 +195,8 @@ int sqlite3VdbeMakeLabel(Vdbe *p){
assert( p->magic==VDBE_MAGIC_INIT );
if( i>=p->nLabelAlloc ){
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
- sqliteReallocOrFree((void**)&p->aLabel,
- p->nLabelAlloc*sizeof(p->aLabel[0]));
+ p->aLabel = sqliteReallocOrFree(p->aLabel,
+ p->nLabelAlloc*sizeof(p->aLabel[0]));
}
if( p->aLabel ){
p->aLabel[i] = -1;
@@ -517,9 +557,8 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
*/
void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
va_list ap;
- assert( p->nOp>0 );
- assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0
- || sqlite3MallocFailed() );
+ assert( p->nOp>0 || p->aOp==0 );
+ assert( p->aOp==0 || p->aOp[p->nOp-1].p3==0 || sqlite3MallocFailed() );
va_start(ap, zFormat);
sqlite3VdbeChangeP3(p, -1, sqlite3VMPrintf(zFormat, ap), P3_DYNAMIC);
va_end(ap);
@@ -531,8 +570,8 @@ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){
*/
VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
assert( p->magic==VDBE_MAGIC_INIT );
- assert( addr>=0 && addr<p->nOp );
- return &p->aOp[addr];
+ assert( (addr>=0 && addr<p->nOp) || sqlite3MallocFailed() );
+ return ((addr>=0 && addr<p->nOp)?(&p->aOp[addr]):0);
}
#if !defined(SQLITE_OMIT_EXPLAIN) || !defined(NDEBUG) \
@@ -679,11 +718,11 @@ int sqlite3VdbeList(
Mem *pMem = p->aStack;
pMem->flags = MEM_Int;
pMem->type = SQLITE_INTEGER;
- pMem->i = i; /* Program counter */
+ pMem->u.i = i; /* Program counter */
pMem++;
pMem->flags = MEM_Static|MEM_Str|MEM_Term;
- pMem->z = sqlite3OpcodeNames[pOp->opcode]; /* Opcode */
+ pMem->z = (char*)sqlite3OpcodeNames[pOp->opcode]; /* Opcode */
assert( pMem->z!=0 );
pMem->n = strlen(pMem->z);
pMem->type = SQLITE_TEXT;
@@ -691,12 +730,12 @@ int sqlite3VdbeList(
pMem++;
pMem->flags = MEM_Int;
- pMem->i = pOp->p1; /* P1 */
+ pMem->u.i = pOp->p1; /* P1 */
pMem->type = SQLITE_INTEGER;
pMem++;
pMem->flags = MEM_Int;
- pMem->i = pOp->p2; /* P2 */
+ pMem->u.i = pOp->p2; /* P2 */
pMem->type = SQLITE_INTEGER;
pMem++;
@@ -717,11 +756,11 @@ int sqlite3VdbeList(
}
#endif /* SQLITE_OMIT_EXPLAIN */
+#ifdef SQLITE_DEBUG
/*
** Print the SQL that was used to generate a VDBE program.
*/
void sqlite3VdbePrintSql(Vdbe *p){
-#ifdef SQLITE_DEBUG
int nOp = p->nOp;
VdbeOp *pOp;
if( nOp<1 ) return;
@@ -731,8 +770,39 @@ void sqlite3VdbePrintSql(Vdbe *p){
while( isspace(*(u8*)z) ) z++;
printf("SQL: [%s]\n", z);
}
+}
#endif
+
+#if !defined(SQLITE_OMIT_TRACE) && defined(SQLITE_ENABLE_IOTRACE)
+/*
+** Print an IOTRACE message showing SQL content.
+*/
+void sqlite3VdbeIOTraceSql(Vdbe *p){
+ int nOp = p->nOp;
+ VdbeOp *pOp;
+ if( sqlite3_io_trace==0 ) return;
+ if( nOp<1 ) return;
+ pOp = &p->aOp[nOp-1];
+ if( pOp->opcode==OP_Noop && pOp->p3!=0 ){
+ char *z = sqlite3StrDup(pOp->p3);
+ int i, j;
+ for(i=0; isspace(z[i]); i++){}
+ for(j=0; z[i]; i++){
+ if( isspace(z[i]) ){
+ if( z[i-1]!=' ' ){
+ z[j++] = ' ';
+ }
+ }else{
+ z[j++] = z[i];
+ }
+ }
+ z[j] = 0;
+ sqlite3_io_trace("SQL %s\n", z);
+ sqliteFree(z);
+ }
}
+#endif /* !SQLITE_OMIT_TRACE && SQLITE_ENABLE_IOTRACE */
+
/*
** Prepare a virtual machine for execution. This involves things such
@@ -812,21 +882,6 @@ void sqlite3VdbeMakeReady(
p->aMem[n].flags = MEM_Null;
}
-#ifdef SQLITE_DEBUG
- if( (p->db->flags & SQLITE_VdbeListing)!=0
- || sqlite3OsFileExists("vdbe_explain")
- ){
- int i;
- printf("VDBE Program Listing:\n");
- sqlite3VdbePrintSql(p);
- for(i=0; i<p->nOp; i++){
- sqlite3VdbePrintOp(stdout, i, &p->aOp[i]);
- }
- }
- if( sqlite3OsFileExists("vdbe_trace") ){
- p->trace = stdout;
- }
-#endif
p->pTos = &p->aStack[-1];
p->pc = -1;
p->rc = SQLITE_OK;
@@ -1034,18 +1089,22 @@ static int vdbeCommit(sqlite3 *db){
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
- rc = sqlite3BtreeSync(pBt, 0);
+ rc = sqlite3BtreeCommitPhaseOne(pBt, 0);
}
}
- /* Do the commit only if all databases successfully synced */
- if( rc==SQLITE_OK ){
- for(i=0; i<db->nDb; i++){
- Btree *pBt = db->aDb[i].pBt;
- if( pBt ){
- sqlite3BtreeCommit(pBt);
- }
+ /* Do the commit only if all databases successfully complete phase 1.
+ ** If one of the BtreeCommitPhaseOne() calls fails, this indicates an
+ ** IO error while deleting or truncating a journal file. It is unlikely,
+ ** but could happen. In this case abandon processing and return the error.
+ */
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
+ Btree *pBt = db->aDb[i].pBt;
+ if( pBt ){
+ rc = sqlite3BtreeCommitPhaseTwo(pBt);
}
+ }
+ if( rc==SQLITE_OK ){
sqlite3VtabCommit(db);
}
}
@@ -1122,16 +1181,16 @@ static int vdbeCommit(sqlite3 *db){
** sets the master journal pointer in each individual journal. If
** an error occurs here, do not delete the master journal file.
**
- ** If the error occurs during the first call to sqlite3BtreeSync(),
- ** then there is a chance that the master journal file will be
- ** orphaned. But we cannot delete it, in case the master journal
- ** file name was written into the journal file before the failure
- ** occured.
+ ** If the error occurs during the first call to
+ ** sqlite3BtreeCommitPhaseOne(), then there is a chance that the
+ ** master journal file will be orphaned. But we cannot delete it,
+ ** in case the master journal file name was written into the journal
+ ** file before the failure occured.
*/
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt && sqlite3BtreeIsInTrans(pBt) ){
- rc = sqlite3BtreeSync(pBt, zMaster);
+ rc = sqlite3BtreeCommitPhaseOne(pBt, zMaster);
}
}
sqlite3OsClose(&master);
@@ -1145,9 +1204,11 @@ static int vdbeCommit(sqlite3 *db){
** transaction files are deleted.
*/
rc = sqlite3OsDelete(zMaster);
- assert( rc==SQLITE_OK );
sqliteFree(zMaster);
zMaster = 0;
+ if( rc ){
+ return rc;
+ }
rc = sqlite3OsSyncDirectory(zMainFile);
if( rc!=SQLITE_OK ){
/* This is not good. The master journal file has been deleted, but
@@ -1161,18 +1222,21 @@ static int vdbeCommit(sqlite3 *db){
}
/* All files and directories have already been synced, so the following
- ** calls to sqlite3BtreeCommit() are only closing files and deleting
- ** journals. If something goes wrong while this is happening we don't
- ** really care. The integrity of the transaction is already guaranteed,
- ** but some stray 'cold' journals may be lying around. Returning an
- ** error code won't help matters.
+ ** calls to sqlite3BtreeCommitPhaseTwo() are only closing files and
+ ** deleting or truncating journals. If something goes wrong while
+ ** this is happening we don't really care. The integrity of the
+ ** transaction is already guaranteed, but some stray 'cold' journals
+ ** may be lying around. Returning an error code won't help matters.
*/
+ disable_simulated_io_errors();
for(i=0; i<db->nDb; i++){
Btree *pBt = db->aDb[i].pBt;
if( pBt ){
- sqlite3BtreeCommit(pBt);
+ sqlite3BtreeCommitPhaseTwo(pBt);
}
}
+ enable_simulated_io_errors();
+
sqlite3VtabCommit(db);
}
#endif
@@ -1287,9 +1351,10 @@ int sqlite3VdbeHalt(Vdbe *p){
/* No commit or rollback needed if the program never started */
if( p->pc>=0 ){
-
+ int mrc; /* Primary error code from p->rc */
/* Check for one of the special errors - SQLITE_NOMEM or SQLITE_IOERR */
- isSpecialError = ((p->rc==SQLITE_NOMEM || p->rc==SQLITE_IOERR)?1:0);
+ mrc = p->rc & 0xff;
+ isSpecialError = ((mrc==SQLITE_NOMEM || mrc==SQLITE_IOERR)?1:0);
if( isSpecialError ){
/* This loop does static analysis of the query to see which of the
** following three categories it falls into:
@@ -1422,6 +1487,14 @@ int sqlite3VdbeHalt(Vdbe *p){
}
/*
+** Each VDBE holds the result of the most recent sqlite3_step() call
+** in p->rc. This routine sets that result back to SQLITE_OK.
+*/
+void sqlite3VdbeResetStepResult(Vdbe *p){
+ p->rc = SQLITE_OK;
+}
+
+/*
** Clean up a VDBE after execution but do not delete the VDBE just yet.
** Write any error messages into *pzErrMsg. Return the result code.
**
@@ -1433,18 +1506,16 @@ int sqlite3VdbeHalt(Vdbe *p){
** VDBE_MAGIC_INIT.
*/
int sqlite3VdbeReset(Vdbe *p){
- if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){
- sqlite3Error(p->db, SQLITE_MISUSE, 0);
- return SQLITE_MISUSE;
- }
+ sqlite3 *db;
+ db = p->db;
/* If the VM did not run to completion or if it encountered an
** error, then it might not have been halted properly. So halt
** it now.
*/
- sqlite3SafetyOn(p->db);
+ sqlite3SafetyOn(db);
sqlite3VdbeHalt(p);
- sqlite3SafetyOff(p->db);
+ sqlite3SafetyOff(db);
/* If the VDBE has be run even partially, then transfer the error code
** and error message from the VDBE into the main database structure. But
@@ -1453,21 +1524,20 @@ int sqlite3VdbeReset(Vdbe *p){
*/
if( p->pc>=0 ){
if( p->zErrMsg ){
- sqlite3* db = p->db;
sqlite3ValueSetStr(db->pErr, -1, p->zErrMsg, SQLITE_UTF8, sqlite3FreeX);
db->errCode = p->rc;
p->zErrMsg = 0;
}else if( p->rc ){
- sqlite3Error(p->db, p->rc, 0);
+ sqlite3Error(db, p->rc, 0);
}else{
- sqlite3Error(p->db, SQLITE_OK, 0);
+ sqlite3Error(db, SQLITE_OK, 0);
}
}else if( p->rc && p->expired ){
/* The expired flag was set on the VDBE before the first call
** to sqlite3_step(). For consistency (since sqlite3_step() was
** called), set the database error in this case as well.
*/
- sqlite3Error(p->db, p->rc, 0);
+ sqlite3Error(db, p->rc, 0);
}
/* Reclaim all memory used by the VDBE
@@ -1502,9 +1572,9 @@ int sqlite3VdbeReset(Vdbe *p){
p->magic = VDBE_MAGIC_INIT;
p->aborted = 0;
if( p->rc==SQLITE_SCHEMA ){
- sqlite3ResetInternalSchema(p->db, 0);
+ sqlite3ResetInternalSchema(db, 0);
}
- return p->rc;
+ return p->rc & db->errMask;
}
/*
@@ -1515,6 +1585,7 @@ int sqlite3VdbeFinalize(Vdbe *p){
int rc = SQLITE_OK;
if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){
rc = sqlite3VdbeReset(p);
+ assert( (rc & p->db->errMask)==rc );
}else if( p->magic!=VDBE_MAGIC_INIT ){
return SQLITE_MISUSE;
}
@@ -1569,6 +1640,7 @@ void sqlite3VdbeDelete(Vdbe *p){
sqliteFree(p->aStack);
releaseMemArray(p->aColName, p->nResColumn*COLNAME_N);
sqliteFree(p->aColName);
+ sqliteFree(p->zSql);
p->magic = VDBE_MAGIC_DEAD;
sqliteFree(p);
}
@@ -1585,12 +1657,7 @@ int sqlite3VdbeCursorMoveto(Cursor *p){
extern int sqlite3_search_count;
#endif
assert( p->isTable );
- if( p->isTable ){
- rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, &res);
- }else{
- rc = sqlite3BtreeMoveto(p->pCursor,(char*)&p->movetoTarget,
- sizeof(i64),&res);
- }
+ rc = sqlite3BtreeMoveto(p->pCursor, 0, p->movetoTarget, 0, &res);
if( rc ) return rc;
*p->pIncrKey = 0;
p->lastRowid = keyToInt(p->movetoTarget);
@@ -1662,7 +1729,7 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
if( flags&MEM_Int ){
/* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */
# define MAX_6BYTE ((((i64)0x00001000)<<32)-1)
- i64 i = pMem->i;
+ i64 i = pMem->u.i;
u64 u;
if( file_format>=4 && (i&1)==i ){
return 8+i;
@@ -1683,10 +1750,8 @@ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){
assert( n>=0 );
return ((n*2) + 13);
}
- if( flags&MEM_Blob ){
- return (pMem->n*2 + 12);
- }
- return 0;
+ assert( (flags & MEM_Blob)!=0 );
+ return (pMem->n*2 + 12);
}
/*
@@ -1715,9 +1780,10 @@ int sqlite3VdbeSerialPut(unsigned char *buf, Mem *pMem, int file_format){
u64 v;
int i;
if( serial_type==7 ){
- v = *(u64*)&pMem->r;
+ assert( sizeof(v)==sizeof(pMem->r) );
+ memcpy(&v, &pMem->r, sizeof(v));
}else{
- v = *(u64*)&pMem->i;
+ v = pMem->u.i;
}
len = i = sqlite3VdbeSerialTypeLen(serial_type);
while( i-- ){
@@ -1755,22 +1821,22 @@ int sqlite3VdbeSerialGet(
break;
}
case 1: { /* 1-byte signed integer */
- pMem->i = (signed char)buf[0];
+ pMem->u.i = (signed char)buf[0];
pMem->flags = MEM_Int;
return 1;
}
case 2: { /* 2-byte signed integer */
- pMem->i = (((signed char)buf[0])<<8) | buf[1];
+ pMem->u.i = (((signed char)buf[0])<<8) | buf[1];
pMem->flags = MEM_Int;
return 2;
}
case 3: { /* 3-byte signed integer */
- pMem->i = (((signed char)buf[0])<<16) | (buf[1]<<8) | buf[2];
+ pMem->u.i = (((signed char)buf[0])<<16) | (buf[1]<<8) | buf[2];
pMem->flags = MEM_Int;
return 3;
}
case 4: { /* 4-byte signed integer */
- pMem->i = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
+ pMem->u.i = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
pMem->flags = MEM_Int;
return 4;
}
@@ -1778,7 +1844,7 @@ int sqlite3VdbeSerialGet(
u64 x = (((signed char)buf[0])<<8) | buf[1];
u32 y = (buf[2]<<24) | (buf[3]<<16) | (buf[4]<<8) | buf[5];
x = (x<<32) | y;
- pMem->i = *(i64*)&x;
+ pMem->u.i = *(i64*)&x;
pMem->flags = MEM_Int;
return 6;
}
@@ -1791,24 +1857,27 @@ int sqlite3VdbeSerialGet(
** byte order. The byte order differs on some (broken) architectures.
*/
static const u64 t1 = ((u64)0x3ff00000)<<32;
- assert( 1.0==*(double*)&t1 );
+ static const double r1 = 1.0;
+ assert( sizeof(r1)==sizeof(t1) && memcmp(&r1, &t1, sizeof(r1))==0 );
#endif
x = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
y = (buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7];
x = (x<<32) | y;
if( serial_type==6 ){
- pMem->i = *(i64*)&x;
+ pMem->u.i = *(i64*)&x;
pMem->flags = MEM_Int;
}else{
- pMem->r = *(double*)&x;
+ assert( sizeof(x)==8 && sizeof(pMem->r)==8 );
+ memcpy(&pMem->r, &x, sizeof(x));
+ /* pMem->r = *(double*)&x; */
pMem->flags = MEM_Real;
}
return 8;
}
case 8: /* Integer 0 */
case 9: { /* Integer 1 */
- pMem->i = serial_type-8;
+ pMem->u.i = serial_type-8;
pMem->flags = MEM_Int;
return 0;
}
@@ -1887,14 +1956,13 @@ int sqlite3VdbeRecordCompare(
idx2 += GetVarint( aKey2+idx2, serial_type2 );
if( d2>=nKey2 && sqlite3VdbeSerialTypeLen(serial_type2)>0 ) break;
- /* Assert that there is enough space left in each key for the blob of
- ** data to go with the serial type just read. This assert may fail if
- ** the file is corrupted. Then read the value from each key into mem1
- ** and mem2 respectively.
+ /* Extract the values to be compared.
*/
d1 += sqlite3VdbeSerialGet(&aKey1[d1], serial_type1, &mem1);
d2 += sqlite3VdbeSerialGet(&aKey2[d2], serial_type2, &mem2);
+ /* Do the comparison
+ */
rc = sqlite3MemCompare(&mem1, &mem2, i<nField ? pKeyInfo->aColl[i] : 0);
if( mem1.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem1);
if( mem2.flags & MEM_Dyn ) sqlite3VdbeMemRelease(&mem2);
@@ -1946,7 +2014,7 @@ int sqlite3VdbeIdxRowidLen(const u8 *aKey){
** Return SQLITE_OK if everything works, or an error code otherwise.
*/
int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
- i64 nCellKey;
+ i64 nCellKey = 0;
int rc;
u32 szHdr; /* Size of the header */
u32 typeRowid; /* Serial type of the rowid */
@@ -1965,7 +2033,7 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
sqlite3GetVarint32((u8*)&m.z[szHdr-1], &typeRowid);
lenRowid = sqlite3VdbeSerialTypeLen(typeRowid);
sqlite3VdbeSerialGet((u8*)&m.z[m.n-lenRowid], typeRowid, &v);
- *rowid = v.i;
+ *rowid = v.u.i;
sqlite3VdbeMemRelease(&m);
return SQLITE_OK;
}
@@ -1985,7 +2053,7 @@ int sqlite3VdbeIdxKeyCompare(
int nKey, const u8 *pKey, /* The key to compare */
int *res /* Write the comparison result here */
){
- i64 nCellKey;
+ i64 nCellKey = 0;
int rc;
BtCursor *pCur = pC->pCursor;
int lenRowid;
diff --git a/ext/pdo_sqlite/sqlite/src/vdbefifo.c b/ext/pdo_sqlite/sqlite/src/vdbefifo.c
index 7ea6c050f..a7c419ae5 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbefifo.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbefifo.c
@@ -19,7 +19,7 @@
** Allocate a new FifoPage and return a pointer to it. Return NULL if
** we run out of memory. Leave space on the page for nEntry entries.
*/
-static FifoPage *allocatePage(int nEntry){
+static FifoPage *allocateFifoPage(int nEntry){
FifoPage *pPage;
if( nEntry>32767 ){
nEntry = 32767;
@@ -50,12 +50,12 @@ int sqlite3VdbeFifoPush(Fifo *pFifo, i64 val){
FifoPage *pPage;
pPage = pFifo->pLast;
if( pPage==0 ){
- pPage = pFifo->pLast = pFifo->pFirst = allocatePage(20);
+ pPage = pFifo->pLast = pFifo->pFirst = allocateFifoPage(20);
if( pPage==0 ){
return SQLITE_NOMEM;
}
}else if( pPage->iWrite>=pPage->nSlot ){
- pPage->pNext = allocatePage(pFifo->nEntry);
+ pPage->pNext = allocateFifoPage(pFifo->nEntry);
if( pPage->pNext==0 ){
return SQLITE_NOMEM;
}
diff --git a/ext/pdo_sqlite/sqlite/src/vdbemem.c b/ext/pdo_sqlite/sqlite/src/vdbemem.c
index 51cd6827f..5aed1df3d 100644
--- a/ext/pdo_sqlite/sqlite/src/vdbemem.c
+++ b/ext/pdo_sqlite/sqlite/src/vdbemem.c
@@ -50,14 +50,6 @@ int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
assert(rc==SQLITE_OK || rc==SQLITE_NOMEM);
assert(rc==SQLITE_OK || pMem->enc!=desiredEnc);
assert(rc==SQLITE_NOMEM || pMem->enc==desiredEnc);
-
- if( rc==SQLITE_NOMEM ){
-/*
- sqlite3VdbeMemRelease(pMem);
- pMem->flags = MEM_Null;
- pMem->z = 0;
-*/
- }
return rc;
#endif
}
@@ -127,22 +119,9 @@ int sqlite3VdbeMemMakeWriteable(Mem *pMem){
** Make sure the given Mem is \u0000 terminated.
*/
int sqlite3VdbeMemNulTerminate(Mem *pMem){
- /* In SQLite, a string without a nul terminator occurs when a string
- ** is loaded from disk (in this case the memory management is ephemeral),
- ** or when it is supplied by the user as a bound variable or function
- ** return value. Therefore, the memory management of the string must be
- ** either ephemeral, static or controlled by a user-supplied destructor.
- */
- assert(
- !(pMem->flags&MEM_Str) || /* it's not a string, or */
- (pMem->flags&MEM_Term) || /* it's nul term. already, or */
- (pMem->flags&(MEM_Ephem|MEM_Static)) || /* it's static or ephem, or */
- (pMem->flags&MEM_Dyn && pMem->xDel) /* external management */
- );
if( (pMem->flags & MEM_Term)!=0 || (pMem->flags & MEM_Str)==0 ){
return SQLITE_OK; /* Nothing to do */
}
-
if( pMem->flags & (MEM_Static|MEM_Ephem) ){
return sqlite3VdbeMemMakeWriteable(pMem);
}else{
@@ -151,9 +130,14 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){
memcpy(z, pMem->z, pMem->n);
z[pMem->n] = 0;
z[pMem->n+1] = 0;
- pMem->xDel(pMem->z);
+ if( pMem->xDel ){
+ pMem->xDel(pMem->z);
+ }else{
+ sqliteFree(pMem->z);
+ }
pMem->xDel = 0;
pMem->z = z;
+ pMem->flags |= MEM_Term;
}
return SQLITE_OK;
}
@@ -186,7 +170,7 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16.
*/
if( fg & MEM_Int ){
- sqlite3_snprintf(NBFS, z, "%lld", pMem->i);
+ sqlite3_snprintf(NBFS, z, "%lld", pMem->u.i);
}else{
assert( fg & MEM_Real );
sqlite3_snprintf(NBFS, z, "%!.15g", pMem->r);
@@ -211,7 +195,7 @@ int sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
int rc = SQLITE_OK;
if( pFunc && pFunc->xFinalize ){
sqlite3_context ctx;
- assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i );
+ assert( (pMem->flags & MEM_Null)!=0 || pFunc==pMem->u.pDef );
ctx.s.flags = MEM_Null;
ctx.s.z = pMem->zShort;
ctx.pMem = pMem;
@@ -241,7 +225,7 @@ void sqlite3VdbeMemRelease(Mem *p){
if( p->flags & (MEM_Dyn|MEM_Agg) ){
if( p->xDel ){
if( p->flags & MEM_Agg ){
- sqlite3VdbeMemFinalize(p, *(FuncDef**)&p->i);
+ sqlite3VdbeMemFinalize(p, p->u.pDef);
assert( (p->flags & MEM_Agg)==0 );
sqlite3VdbeMemRelease(p);
}else{
@@ -268,7 +252,7 @@ void sqlite3VdbeMemRelease(Mem *p){
i64 sqlite3VdbeIntValue(Mem *pMem){
int flags = pMem->flags;
if( flags & MEM_Int ){
- return pMem->i;
+ return pMem->u.i;
}else if( flags & MEM_Real ){
return (i64)pMem->r;
}else if( flags & (MEM_Str|MEM_Blob) ){
@@ -295,7 +279,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
if( pMem->flags & MEM_Real ){
return pMem->r;
}else if( pMem->flags & MEM_Int ){
- return (double)pMem->i;
+ return (double)pMem->u.i;
}else if( pMem->flags & (MEM_Str|MEM_Blob) ){
double val = 0.0;
if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
@@ -316,8 +300,8 @@ double sqlite3VdbeRealValue(Mem *pMem){
*/
void sqlite3VdbeIntegerAffinity(Mem *pMem){
assert( pMem->flags & MEM_Real );
- pMem->i = pMem->r;
- if( ((double)pMem->i)==pMem->r ){
+ pMem->u.i = pMem->r;
+ if( ((double)pMem->u.i)==pMem->r ){
pMem->flags |= MEM_Int;
}
}
@@ -326,7 +310,7 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
** Convert pMem to type integer. Invalidate any prior representations.
*/
int sqlite3VdbeMemIntegerify(Mem *pMem){
- pMem->i = sqlite3VdbeIntValue(pMem);
+ pMem->u.i = sqlite3VdbeIntValue(pMem);
sqlite3VdbeMemRelease(pMem);
pMem->flags = MEM_Int;
return SQLITE_OK;
@@ -369,7 +353,7 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
*/
void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){
sqlite3VdbeMemRelease(pMem);
- pMem->i = val;
+ pMem->u.i = val;
pMem->flags = MEM_Int;
pMem->type = SQLITE_INTEGER;
}
@@ -554,12 +538,12 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
if( (f1 & f2 & MEM_Int)==0 ){
double r1, r2;
if( (f1&MEM_Real)==0 ){
- r1 = pMem1->i;
+ r1 = pMem1->u.i;
}else{
r1 = pMem1->r;
}
if( (f2&MEM_Real)==0 ){
- r2 = pMem2->i;
+ r2 = pMem2->u.i;
}else{
r2 = pMem2->r;
}
@@ -569,8 +553,8 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
}else{
assert( f1&MEM_Int );
assert( f2&MEM_Int );
- if( pMem1->i < pMem2->i ) return -1;
- if( pMem1->i > pMem2->i ) return 1;
+ if( pMem1->u.i < pMem2->u.i ) return -1;
+ if( pMem1->u.i > pMem2->u.i ) return 1;
return 0;
}
}
@@ -653,14 +637,15 @@ int sqlite3VdbeMemFromBtree(
int key, /* If true, retrieve from the btree key, not data. */
Mem *pMem /* OUT: Return data in this Mem structure. */
){
- char *zData; /* Data from the btree layer */
- int available; /* Number of bytes available on the local btree page */
+ char *zData; /* Data from the btree layer */
+ int available = 0; /* Number of bytes available on the local btree page */
if( key ){
zData = (char *)sqlite3BtreeKeyFetch(pCur, &available);
}else{
zData = (char *)sqlite3BtreeDataFetch(pCur, &available);
}
+ assert( zData!=0 );
pMem->n = amt;
if( offset+amt<=available ){
@@ -751,7 +736,7 @@ void sqlite3VdbeMemSanity(Mem *pMem){
|| (pMem->flags&MEM_Null)==0 );
/* If the MEM is both real and integer, the values are equal */
assert( (pMem->flags & (MEM_Int|MEM_Real))!=(MEM_Int|MEM_Real)
- || pMem->r==pMem->i );
+ || pMem->r==pMem->u.i );
}
#endif
@@ -782,7 +767,9 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
return 0;
}
}
- }else if( !(pVal->flags&MEM_Blob) ){
+ sqlite3VdbeMemNulTerminate(pVal);
+ }else{
+ assert( (pVal->flags&MEM_Blob)==0 );
sqlite3VdbeMemStringify(pVal, enc);
assert( 0==(1&(int)pVal->z) );
}
@@ -845,7 +832,7 @@ int sqlite3ValueFromExpr(
}
}else if( op==TK_UMINUS ) {
if( SQLITE_OK==sqlite3ValueFromExpr(pExpr->pLeft, enc, affinity, &pVal) ){
- pVal->i = -1 * pVal->i;
+ pVal->u.i = -1 * pVal->u.i;
pVal->r = -1.0 * pVal->r;
}
}
diff --git a/ext/pdo_sqlite/sqlite/src/vtab.c b/ext/pdo_sqlite/sqlite/src/vtab.c
index d1bf95f98..502120f64 100644
--- a/ext/pdo_sqlite/sqlite/src/vtab.c
+++ b/ext/pdo_sqlite/sqlite/src/vtab.c
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to help implement virtual tables.
**
-** $Id: vtab.c,v 1.1.2.1 2006/08/14 16:15:29 iliaa Exp $
+** $Id: vtab.c,v 1.1.2.3 2007/04/18 22:53:46 iliaa Exp $
*/
#ifndef SQLITE_OMIT_VIRTUALTABLE
#include "sqliteInt.h"
@@ -41,6 +41,37 @@ int sqlite3_create_module(
}
/*
+** Lock the virtual table so that it cannot be disconnected.
+** Locks nest. Every lock should have a corresponding unlock.
+** If an unlock is omitted, resources leaks will occur.
+**
+** If a disconnect is attempted while a virtual table is locked,
+** the disconnect is deferred until all locks have been removed.
+*/
+void sqlite3VtabLock(sqlite3_vtab *pVtab){
+ pVtab->nRef++;
+}
+
+/*
+** Unlock a virtual table. When the last lock is removed,
+** disconnect the virtual table.
+*/
+void sqlite3VtabUnlock(sqlite3 *db, sqlite3_vtab *pVtab){
+ pVtab->nRef--;
+ assert(db);
+ assert(!sqlite3SafetyCheck(db));
+ if( pVtab->nRef==0 ){
+ if( db->magic==SQLITE_MAGIC_BUSY ){
+ sqlite3SafetyOff(db);
+ pVtab->pModule->xDisconnect(pVtab);
+ sqlite3SafetyOn(db);
+ } else {
+ pVtab->pModule->xDisconnect(pVtab);
+ }
+ }
+}
+
+/*
** Clear any and all virtual-table information from the Table record.
** This routine is called, for example, just before deleting the Table
** record.
@@ -49,10 +80,7 @@ void sqlite3VtabClear(Table *p){
sqlite3_vtab *pVtab = p->pVtab;
if( pVtab ){
assert( p->pMod && p->pMod->pModule );
- pVtab->nRef--;
- if( pVtab->nRef==0 ){
- pVtab->pModule->xDisconnect(pVtab);
- }
+ sqlite3VtabUnlock(p->pSchema->db, pVtab);
p->pVtab = 0;
}
if( p->azModuleArg ){
@@ -104,6 +132,11 @@ void sqlite3VtabBeginParse(
int iDb; /* The database the table is being created in */
Table *pTable; /* The new virtual table */
+ if( sqlite3ThreadDataReadOnly()->useSharedData ){
+ sqlite3ErrorMsg(pParse, "Cannot use virtual tables in shared-cache mode");
+ return;
+ }
+
sqlite3StartTable(pParse, pName1, pName2, 0, 0, 1, 0);
pTable = pParse->pNewTable;
if( pTable==0 || pParse->nErr ) return;
@@ -139,7 +172,7 @@ void sqlite3VtabBeginParse(
*/
static void addArgumentToVtab(Parse *pParse){
if( pParse->sArg.z && pParse->pNewTable ){
- const char *z = pParse->sArg.z;
+ const char *z = (const char*)pParse->sArg.z;
int n = pParse->sArg.n;
addModuleArgument(pParse->pNewTable, sqliteStrNDup(z, n));
}
@@ -210,7 +243,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
sqlite3VdbeAddOp(v, OP_Expire, 0, 0);
zWhere = sqlite3MPrintf("name='%q'", pTab->zName);
- sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 0, zWhere, P3_DYNAMIC);
+ sqlite3VdbeOp3(v, OP_ParseSchema, iDb, 1, zWhere, P3_DYNAMIC);
sqlite3VdbeOp3(v, OP_VCreate, iDb, 0, pTab->zName, strlen(pTab->zName) + 1);
}
@@ -228,6 +261,7 @@ void sqlite3VtabFinishParse(Parse *pParse, Token *pEnd){
assert( pTab==pOld ); /* Malloc must have failed inside HashInsert() */
return;
}
+ pSchema->db = pParse->db;
pParse->pNewTable = 0;
}
}
@@ -266,14 +300,20 @@ static int vtabCallConstructor(
sqlite3 *db,
Table *pTab,
Module *pMod,
- int (*xConstruct)(sqlite3*, void *, int, char **, sqlite3_vtab **),
+ int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**),
char **pzErr
){
int rc;
int rc2;
- char **azArg = pTab->azModuleArg;
+ sqlite3_vtab *pVtab;
+ const char *const*azArg = (const char *const*)pTab->azModuleArg;
int nArg = pTab->nModuleArg;
- char *zErr = sqlite3MPrintf("vtable constructor failed: %s", pTab->zName);
+ char *zErr = 0;
+ char *zModuleName = sqlite3MPrintf("%s", pTab->zName);
+
+ if( !zModuleName ){
+ return SQLITE_NOMEM;
+ }
assert( !db->pVTab );
assert( xConstruct );
@@ -281,17 +321,22 @@ static int vtabCallConstructor(
db->pVTab = pTab;
rc = sqlite3SafetyOff(db);
assert( rc==SQLITE_OK );
- rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab);
+ rc = xConstruct(db, pMod->pAux, nArg, azArg, &pTab->pVtab, &zErr);
rc2 = sqlite3SafetyOn(db);
- if( rc==SQLITE_OK && pTab->pVtab ){
- pTab->pVtab->pModule = pMod->pModule;
- pTab->pVtab->nRef = 1;
+ pVtab = pTab->pVtab;
+ if( rc==SQLITE_OK && pVtab ){
+ pVtab->pModule = pMod->pModule;
+ pVtab->nRef = 1;
}
if( SQLITE_OK!=rc ){
- *pzErr = zErr;
- zErr = 0;
- } else if( db->pVTab ){
+ if( zErr==0 ){
+ *pzErr = sqlite3MPrintf("vtable constructor failed: %s", zModuleName);
+ }else {
+ *pzErr = sqlite3MPrintf("%s", zErr);
+ sqlite3_free(zErr);
+ }
+ }else if( db->pVTab ){
const char *zFormat = "vtable constructor did not declare schema: %s";
*pzErr = sqlite3MPrintf(zFormat, pTab->zName);
rc = SQLITE_ERROR;
@@ -300,7 +345,7 @@ static int vtabCallConstructor(
rc = rc2;
}
db->pVTab = 0;
- sqliteFree(zErr);
+ sqliteFree(zModuleName);
return rc;
}
@@ -313,7 +358,6 @@ static int vtabCallConstructor(
*/
int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
Module *pMod;
- const char *zModule;
int rc = SQLITE_OK;
if( !pTab || !pTab->isVirtual || pTab->pVtab ){
@@ -321,7 +365,6 @@ int sqlite3VtabCallConnect(Parse *pParse, Table *pTab){
}
pMod = pTab->pMod;
- zModule = pTab->azModuleArg[0];
if( !pMod ){
const char *zModule = pTab->azModuleArg[0];
sqlite3ErrorMsg(pParse, "no such module: %s", zModule);
@@ -359,7 +402,7 @@ static int addToVTrans(sqlite3 *db, sqlite3_vtab *pVtab){
/* Add pVtab to the end of sqlite3.aVTrans */
db->aVTrans[db->nVTrans++] = pVtab;
- pVtab->nRef++;
+ sqlite3VtabLock(pVtab);
return SQLITE_OK;
}
@@ -432,6 +475,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
pTab->nCol = sParse.pNewTable->nCol;
sParse.pNewTable->nCol = 0;
sParse.pNewTable->aCol = 0;
+ db->pVTab = 0;
} else {
sqlite3Error(db, SQLITE_ERROR, zErr);
sqliteFree(zErr);
@@ -440,11 +484,11 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
sParse.declareVtab = 0;
sqlite3_finalize((sqlite3_stmt*)sParse.pVdbe);
- sqlite3DeleteTable(0, sParse.pNewTable);
+ sqlite3DeleteTable(sParse.pNewTable);
sParse.pNewTable = 0;
- db->pVTab = 0;
- return rc;
+ assert( (rc&0xff)==rc );
+ return sqlite3ApiExit(db, rc);
}
/*
@@ -492,10 +536,7 @@ static void callFinaliser(sqlite3 *db, int offset){
int (*x)(sqlite3_vtab *);
x = *(int (**)(sqlite3_vtab *))((char *)pVtab->pModule + offset);
if( x ) x(pVtab);
- pVtab->nRef--;
- if( pVtab->nRef==0 ){
- pVtab->pModule->xDisconnect(pVtab);
- }
+ sqlite3VtabUnlock(db, pVtab);
}
sqliteFree(db->aVTrans);
db->nVTrans = 0;
@@ -623,6 +664,10 @@ FuncDef *sqlite3VtabOverloadFunction(
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
void *pArg;
FuncDef *pNew;
+ int rc;
+ char *zLowerName;
+ unsigned char *z;
+
/* Check to see the left operand is a column in a virtual table */
if( pExpr==0 ) return pDef;
@@ -637,8 +682,15 @@ FuncDef *sqlite3VtabOverloadFunction(
if( pMod->xFindFunction==0 ) return pDef;
/* Call the xFuncFunction method on the virtual table implementation
- ** to see if the implementation wants to overload this function */
- if( pMod->xFindFunction(pVtab, nArg, pDef->zName, &xFunc, &pArg)==0 ){
+ ** to see if the implementation wants to overload this function
+ */
+ zLowerName = sqlite3StrDup(pDef->zName);
+ for(z=(unsigned char*)zLowerName; *z; z++){
+ *z = sqlite3UpperToLower[*z];
+ }
+ rc = pMod->xFindFunction(pVtab, nArg, zLowerName, &xFunc, &pArg);
+ sqliteFree(zLowerName);
+ if( rc==0 ){
return pDef;
}
diff --git a/ext/pdo_sqlite/sqlite/src/where.c b/ext/pdo_sqlite/sqlite/src/where.c
index bdbac8112..ac3df19d5 100644
--- a/ext/pdo_sqlite/sqlite/src/where.c
+++ b/ext/pdo_sqlite/sqlite/src/where.c
@@ -35,14 +35,15 @@
*/
#if defined(SQLITE_TEST) || defined(SQLITE_DEBUG)
int sqlite3_where_trace = 0;
-# define TRACE(X) if(sqlite3_where_trace) sqlite3DebugPrintf X
+# define WHERETRACE(X) if(sqlite3_where_trace) sqlite3DebugPrintf X
#else
-# define TRACE(X)
+# define WHERETRACE(X)
#endif
/* Forward reference
*/
typedef struct WhereClause WhereClause;
+typedef struct ExprMaskSet ExprMaskSet;
/*
** The query generator uses an array of instances of this structure to
@@ -106,6 +107,7 @@ struct WhereTerm {
*/
struct WhereClause {
Parse *pParse; /* The parser context */
+ ExprMaskSet *pMaskSet; /* Mapping of table indices to bitmasks */
int nTerm; /* Number of terms */
int nSlot; /* Number of entries in a[] */
WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
@@ -138,7 +140,6 @@ struct WhereClause {
** numbers all get mapped into bit numbers that begin with 0 and contain
** no gaps.
*/
-typedef struct ExprMaskSet ExprMaskSet;
struct ExprMaskSet {
int n; /* Number of assigned cursor values */
int ix[sizeof(Bitmask)*8]; /* Cursor assigned to each bit */
@@ -157,28 +158,42 @@ struct ExprMaskSet {
#define WO_GT (WO_EQ<<(TK_GT-TK_EQ))
#define WO_GE (WO_EQ<<(TK_GE-TK_EQ))
#define WO_MATCH 64
+#define WO_ISNULL 128
/*
-** Value for flags returned by bestIndex()
+** Value for flags returned by bestIndex().
+**
+** The least significant byte is reserved as a mask for WO_ values above.
+** The WhereLevel.flags field is usually set to WO_IN|WO_EQ|WO_ISNULL.
+** But if the table is the right table of a left join, WhereLevel.flags
+** is set to WO_IN|WO_EQ. The WhereLevel.flags field can then be used as
+** the "op" parameter to findTerm when we are resolving equality constraints.
+** ISNULL constraints will then not be used on the right table of a left
+** join. Tickets #2177 and #2189.
*/
-#define WHERE_ROWID_EQ 0x0001 /* rowid=EXPR or rowid IN (...) */
-#define WHERE_ROWID_RANGE 0x0002 /* rowid<EXPR and/or rowid>EXPR */
-#define WHERE_COLUMN_EQ 0x0010 /* x=EXPR or x IN (...) */
-#define WHERE_COLUMN_RANGE 0x0020 /* x<EXPR and/or x>EXPR */
-#define WHERE_COLUMN_IN 0x0040 /* x IN (...) */
-#define WHERE_TOP_LIMIT 0x0100 /* x<EXPR or x<=EXPR constraint */
-#define WHERE_BTM_LIMIT 0x0200 /* x>EXPR or x>=EXPR constraint */
-#define WHERE_IDX_ONLY 0x0800 /* Use index only - omit table */
-#define WHERE_ORDERBY 0x1000 /* Output will appear in correct order */
-#define WHERE_REVERSE 0x2000 /* Scan in reverse order */
-#define WHERE_UNIQUE 0x4000 /* Selects no more than one row */
-#define WHERE_VIRTUALTABLE 0x8000 /* Use virtual-table processing */
+#define WHERE_ROWID_EQ 0x000100 /* rowid=EXPR or rowid IN (...) */
+#define WHERE_ROWID_RANGE 0x000200 /* rowid<EXPR and/or rowid>EXPR */
+#define WHERE_COLUMN_EQ 0x001000 /* x=EXPR or x IN (...) */
+#define WHERE_COLUMN_RANGE 0x002000 /* x<EXPR and/or x>EXPR */
+#define WHERE_COLUMN_IN 0x004000 /* x IN (...) */
+#define WHERE_TOP_LIMIT 0x010000 /* x<EXPR or x<=EXPR constraint */
+#define WHERE_BTM_LIMIT 0x020000 /* x>EXPR or x>=EXPR constraint */
+#define WHERE_IDX_ONLY 0x080000 /* Use index only - omit table */
+#define WHERE_ORDERBY 0x100000 /* Output will appear in correct order */
+#define WHERE_REVERSE 0x200000 /* Scan in reverse order */
+#define WHERE_UNIQUE 0x400000 /* Selects no more than one row */
+#define WHERE_VIRTUALTABLE 0x800000 /* Use virtual-table processing */
/*
** Initialize a preallocated WhereClause structure.
*/
-static void whereClauseInit(WhereClause *pWC, Parse *pParse){
+static void whereClauseInit(
+ WhereClause *pWC, /* The WhereClause to be initialized */
+ Parse *pParse, /* The parsing context */
+ ExprMaskSet *pMaskSet /* Mapping from table indices to bitmasks */
+){
pWC->pParse = pParse;
+ pWC->pMaskSet = pMaskSet;
pWC->nTerm = 0;
pWC->nSlot = ARRAYSIZE(pWC->aStatic);
pWC->a = pWC->aStatic;
@@ -205,6 +220,9 @@ static void whereClauseClear(WhereClause *pWC){
** Add a new entries to the WhereClause structure. Increase the allocated
** space as necessary.
**
+** If the flags argument includes TERM_DYNAMIC, then responsibility
+** for freeing the expression p is assumed by the WhereClause object.
+**
** WARNING: This routine might reallocate the space used to store
** WhereTerms. All pointers to WhereTerms should be invalided after
** calling this routine. Such pointers may be reinitialized by referencing
@@ -216,7 +234,12 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, int flags){
if( pWC->nTerm>=pWC->nSlot ){
WhereTerm *pOld = pWC->a;
pWC->a = sqliteMalloc( sizeof(pWC->a[0])*pWC->nSlot*2 );
- if( pWC->a==0 ) return 0;
+ if( pWC->a==0 ){
+ if( flags & TERM_DYNAMIC ){
+ sqlite3ExprDelete(p);
+ }
+ return 0;
+ }
memcpy(pWC->a, pOld, sizeof(pWC->a[0])*pWC->nTerm);
if( pOld!=pWC->aStatic ){
sqliteFree(pOld);
@@ -354,7 +377,7 @@ static int allowedOp(int op){
assert( TK_LT>TK_EQ && TK_LT<TK_GE );
assert( TK_LE>TK_EQ && TK_LE<TK_GE );
assert( TK_GE==TK_EQ+4 );
- return op==TK_IN || (op>=TK_EQ && op<=TK_GE);
+ return op==TK_IN || (op>=TK_EQ && op<=TK_GE) || op==TK_ISNULL;
}
/*
@@ -388,9 +411,12 @@ static int operatorMask(int op){
assert( allowedOp(op) );
if( op==TK_IN ){
c = WO_IN;
+ }else if( op==TK_ISNULL ){
+ c = WO_ISNULL;
}else{
c = WO_EQ<<(op-TK_EQ);
}
+ assert( op!=TK_ISNULL || c==WO_ISNULL );
assert( op!=TK_IN || c==WO_IN );
assert( op!=TK_EQ || c==WO_EQ );
assert( op!=TK_LT || c==WO_LT );
@@ -422,7 +448,7 @@ static WhereTerm *findTerm(
&& pTerm->leftColumn==iColumn
&& (pTerm->eOperator & op)!=0
){
- if( iCur>=0 && pIdx ){
+ if( iCur>=0 && pIdx && pTerm->eOperator!=WO_ISNULL ){
Expr *pX = pTerm->pExpr;
CollSeq *pColl;
char idxaff;
@@ -451,7 +477,7 @@ static WhereTerm *findTerm(
}
/* Forward reference */
-static void exprAnalyze(SrcList*, ExprMaskSet*, WhereClause*, int);
+static void exprAnalyze(SrcList*, WhereClause*, int);
/*
** Call exprAnalyze on all terms in a WHERE clause.
@@ -460,12 +486,11 @@ static void exprAnalyze(SrcList*, ExprMaskSet*, WhereClause*, int);
*/
static void exprAnalyzeAll(
SrcList *pTabList, /* the FROM clause */
- ExprMaskSet *pMaskSet, /* table masks */
WhereClause *pWC /* the WHERE clause to be analyzed */
){
int i;
for(i=pWC->nTerm-1; i>=0; i--){
- exprAnalyze(pTabList, pMaskSet, pWC, i);
+ exprAnalyze(pTabList, pWC, i);
}
}
@@ -506,6 +531,10 @@ static int isLikeOrGlob(
}
pColl = pLeft->pColl;
if( pColl==0 ){
+ /* TODO: Coverage testing doesn't get this case. Is it actually possible
+ ** for an expression of type TK_COLUMN to not have an assigned collation
+ ** sequence at this point?
+ */
pColl = db->pDfltColl;
}
if( (pColl->type!=SQLITE_COLL_BINARY || noCase) &&
@@ -565,6 +594,92 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
pDerived->iRightJoinTable = pBase->iRightJoinTable;
}
+#if !defined(SQLITE_OMIT_OR_OPTIMIZATION) && !defined(SQLITE_OMIT_SUBQUERY)
+/*
+** Return TRUE if the given term of an OR clause can be converted
+** into an IN clause. The iCursor and iColumn define the left-hand
+** side of the IN clause.
+**
+** The context is that we have multiple OR-connected equality terms
+** like this:
+**
+** a=<expr1> OR a=<expr2> OR b=<expr3> OR ...
+**
+** The pOrTerm input to this routine corresponds to a single term of
+** this OR clause. In order for the term to be a condidate for
+** conversion to an IN operator, the following must be true:
+**
+** * The left-hand side of the term must be the column which
+** is identified by iCursor and iColumn.
+**
+** * If the right-hand side is also a column, then the affinities
+** of both right and left sides must be such that no type
+** conversions are required on the right. (Ticket #2249)
+**
+** If both of these conditions are true, then return true. Otherwise
+** return false.
+*/
+static int orTermIsOptCandidate(WhereTerm *pOrTerm, int iCursor, int iColumn){
+ int affLeft, affRight;
+ assert( pOrTerm->eOperator==WO_EQ );
+ if( pOrTerm->leftCursor!=iCursor ){
+ return 0;
+ }
+ if( pOrTerm->leftColumn!=iColumn ){
+ return 0;
+ }
+ affRight = sqlite3ExprAffinity(pOrTerm->pExpr->pRight);
+ if( affRight==0 ){
+ return 1;
+ }
+ affLeft = sqlite3ExprAffinity(pOrTerm->pExpr->pLeft);
+ if( affRight!=affLeft ){
+ return 0;
+ }
+ return 1;
+}
+
+/*
+** Return true if the given term of an OR clause can be ignored during
+** a check to make sure all OR terms are candidates for optimization.
+** In other words, return true if a call to the orTermIsOptCandidate()
+** above returned false but it is not necessary to disqualify the
+** optimization.
+**
+** Suppose the original OR phrase was this:
+**
+** a=4 OR a=11 OR a=b
+**
+** During analysis, the third term gets flipped around and duplicate
+** so that we are left with this:
+**
+** a=4 OR a=11 OR a=b OR b=a
+**
+** Since the last two terms are duplicates, only one of them
+** has to qualify in order for the whole phrase to qualify. When
+** this routine is called, we know that pOrTerm did not qualify.
+** This routine merely checks to see if pOrTerm has a duplicate that
+** might qualify. If there is a duplicate that has not yet been
+** disqualified, then return true. If there are no duplicates, or
+** the duplicate has also been disqualifed, return false.
+*/
+static int orTermHasOkDuplicate(WhereClause *pOr, WhereTerm *pOrTerm){
+ if( pOrTerm->flags & TERM_COPIED ){
+ /* This is the original term. The duplicate is to the left had
+ ** has not yet been analyzed and thus has not yet been disqualified. */
+ return 1;
+ }
+ if( (pOrTerm->flags & TERM_VIRTUAL)!=0
+ && (pOr->a[pOrTerm->iParent].flags & TERM_OR_OK)!=0 ){
+ /* This is a duplicate term. The original qualified so this one
+ ** does not have to. */
+ return 1;
+ }
+ /* This is either a singleton term or else it is a duplicate for
+ ** which the original did not qualify. Either way we are done for. */
+ return 0;
+}
+#endif /* !SQLITE_OMIT_OR_OPTIMIZATION && !SQLITE_OMIT_SUBQUERY */
/*
** The input to this routine is an WhereTerm structure with only the
@@ -580,23 +695,27 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
*/
static void exprAnalyze(
SrcList *pSrc, /* the FROM clause */
- ExprMaskSet *pMaskSet, /* table masks */
WhereClause *pWC, /* the WHERE clause */
int idxTerm /* Index of the term to be analyzed */
){
WhereTerm *pTerm = &pWC->a[idxTerm];
+ ExprMaskSet *pMaskSet = pWC->pMaskSet;
Expr *pExpr = pTerm->pExpr;
Bitmask prereqLeft;
Bitmask prereqAll;
int nPattern;
int isComplete;
+ int op;
if( sqlite3MallocFailed() ) return;
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
- if( pExpr->op==TK_IN ){
+ op = pExpr->op;
+ if( op==TK_IN ){
assert( pExpr->pRight==0 );
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList)
| exprSelectTableUsage(pMaskSet, pExpr->pSelect);
+ }else if( op==TK_ISNULL ){
+ pTerm->prereqRight = 0;
}else{
pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
}
@@ -608,13 +727,13 @@ static void exprAnalyze(
pTerm->leftCursor = -1;
pTerm->iParent = -1;
pTerm->eOperator = 0;
- if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
+ if( allowedOp(op) && (pTerm->prereqRight & prereqLeft)==0 ){
Expr *pLeft = pExpr->pLeft;
Expr *pRight = pExpr->pRight;
if( pLeft->op==TK_COLUMN ){
pTerm->leftCursor = pLeft->iTable;
pTerm->leftColumn = pLeft->iColumn;
- pTerm->eOperator = operatorMask(pExpr->op);
+ pTerm->eOperator = operatorMask(op);
}
if( pRight && pRight->op==TK_COLUMN ){
WhereTerm *pNew;
@@ -622,6 +741,10 @@ static void exprAnalyze(
if( pTerm->leftCursor>=0 ){
int idxNew;
pDup = sqlite3ExprDup(pExpr);
+ if( sqlite3MallocFailed() ){
+ sqlite3ExprDelete(pDup);
+ return;
+ }
idxNew = whereClauseInsert(pWC, pDup, TERM_VIRTUAL|TERM_DYNAMIC);
if( idxNew==0 ) return;
pNew = &pWC->a[idxNew];
@@ -659,7 +782,7 @@ static void exprAnalyze(
pNewExpr = sqlite3Expr(ops[i], sqlite3ExprDup(pExpr->pLeft),
sqlite3ExprDup(pList->a[i].pExpr), 0);
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
- exprAnalyze(pSrc, pMaskSet, pWC, idxNew);
+ exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
pWC->a[idxNew].iParent = idxTerm;
}
@@ -688,12 +811,13 @@ static void exprAnalyze(
WhereTerm *pOrTerm;
assert( (pTerm->flags & TERM_DYNAMIC)==0 );
- whereClauseInit(&sOr, pWC->pParse);
+ whereClauseInit(&sOr, pWC->pParse, pMaskSet);
whereSplit(&sOr, pExpr, TK_OR);
- exprAnalyzeAll(pSrc, pMaskSet, &sOr);
- assert( sOr.nTerm>0 );
+ exprAnalyzeAll(pSrc, &sOr);
+ assert( sOr.nTerm>=2 );
j = 0;
do{
+ assert( j<sOr.nTerm );
iColumn = sOr.a[j].leftColumn;
iCursor = sOr.a[j].leftCursor;
ok = iCursor>=0;
@@ -701,37 +825,34 @@ static void exprAnalyze(
if( pOrTerm->eOperator!=WO_EQ ){
goto or_not_possible;
}
- if( pOrTerm->leftCursor==iCursor && pOrTerm->leftColumn==iColumn ){
+ if( orTermIsOptCandidate(pOrTerm, iCursor, iColumn) ){
pOrTerm->flags |= TERM_OR_OK;
- }else if( (pOrTerm->flags & TERM_COPIED)!=0 ||
- ((pOrTerm->flags & TERM_VIRTUAL)!=0 &&
- (sOr.a[pOrTerm->iParent].flags & TERM_OR_OK)!=0) ){
+ }else if( orTermHasOkDuplicate(&sOr, pOrTerm) ){
pOrTerm->flags &= ~TERM_OR_OK;
}else{
ok = 0;
}
}
- }while( !ok && (sOr.a[j++].flags & TERM_COPIED)!=0 && j<sOr.nTerm );
+ }while( !ok && (sOr.a[j++].flags & TERM_COPIED)!=0 && j<2 );
if( ok ){
ExprList *pList = 0;
Expr *pNew, *pDup;
+ Expr *pLeft = 0;
for(i=sOr.nTerm-1, pOrTerm=sOr.a; i>=0 && ok; i--, pOrTerm++){
if( (pOrTerm->flags & TERM_OR_OK)==0 ) continue;
pDup = sqlite3ExprDup(pOrTerm->pExpr->pRight);
pList = sqlite3ExprListAppend(pList, pDup, 0);
+ pLeft = pOrTerm->pExpr->pLeft;
}
- pDup = sqlite3Expr(TK_COLUMN, 0, 0, 0);
- if( pDup ){
- pDup->iTable = iCursor;
- pDup->iColumn = iColumn;
- }
+ assert( pLeft!=0 );
+ pDup = sqlite3ExprDup(pLeft);
pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
if( pNew ){
int idxNew;
transferJoinMarkings(pNew, pExpr);
pNew->pList = pList;
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
- exprAnalyze(pSrc, pMaskSet, pWC, idxNew);
+ exprAnalyze(pSrc, pWC, idxNew);
pTerm = &pWC->a[idxTerm];
pWC->a[idxNew].iParent = idxTerm;
pTerm->nChild = 1;
@@ -768,10 +889,10 @@ or_not_possible:
}
pNewExpr1 = sqlite3Expr(TK_GE, sqlite3ExprDup(pLeft), pStr1, 0);
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
- exprAnalyze(pSrc, pMaskSet, pWC, idxNew1);
+ exprAnalyze(pSrc, pWC, idxNew1);
pNewExpr2 = sqlite3Expr(TK_LT, sqlite3ExprDup(pLeft), pStr2, 0);
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
- exprAnalyze(pSrc, pMaskSet, pWC, idxNew2);
+ exprAnalyze(pSrc, pWC, idxNew2);
pTerm = &pWC->a[idxTerm];
if( isComplete ){
pWC->a[idxNew1].iParent = idxTerm;
@@ -817,6 +938,25 @@ or_not_possible:
#endif /* SQLITE_OMIT_VIRTUALTABLE */
}
+/*
+** Return TRUE if any of the expressions in pList->a[iFirst...] contain
+** a reference to any table other than the iBase table.
+*/
+static int referencesOtherTables(
+ ExprList *pList, /* Search expressions in ths list */
+ ExprMaskSet *pMaskSet, /* Mapping from tables to bitmaps */
+ int iFirst, /* Be searching with the iFirst-th expression */
+ int iBase /* Ignore references to this table */
+){
+ Bitmask allowed = ~getMask(pMaskSet, iBase);
+ while( iFirst<pList->nExpr ){
+ if( (exprTableUsage(pMaskSet, pList->a[iFirst++].pExpr)&allowed)!=0 ){
+ return 1;
+ }
+ }
+ return 0;
+}
+
/*
** This routine decides if pIdx can be used to satisfy the ORDER BY
@@ -839,6 +979,7 @@ or_not_possible:
*/
static int isSortingIndex(
Parse *pParse, /* Parsing context */
+ ExprMaskSet *pMaskSet, /* Mapping from table indices to bitmaps */
Index *pIdx, /* The index we are testing */
int base, /* Cursor number for the table to be sorted */
ExprList *pOrderBy, /* The ORDER BY clause */
@@ -857,22 +998,43 @@ static int isSortingIndex(
/* Match terms of the ORDER BY clause against columns of
** the index.
+ **
+ ** Note that indices have pIdx->nColumn regular columns plus
+ ** one additional column containing the rowid. The rowid column
+ ** of the index is also allowed to match against the ORDER BY
+ ** clause.
*/
- for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<pIdx->nColumn; i++){
+ for(i=j=0, pTerm=pOrderBy->a; j<nTerm && i<=pIdx->nColumn; i++){
Expr *pExpr; /* The expression of the ORDER BY pTerm */
CollSeq *pColl; /* The collating sequence of pExpr */
int termSortOrder; /* Sort order for this term */
+ int iColumn; /* The i-th column of the index. -1 for rowid */
+ int iSortOrder; /* 1 for DESC, 0 for ASC on the i-th index term */
+ const char *zColl; /* Name of the collating sequence for i-th index term */
pExpr = pTerm->pExpr;
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
/* Can not use an index sort on anything that is not a column in the
** left-most table of the FROM clause */
- return 0;
+ break;
}
pColl = sqlite3ExprCollSeq(pParse, pExpr);
- if( !pColl ) pColl = db->pDfltColl;
- if( pExpr->iColumn!=pIdx->aiColumn[i] ||
- sqlite3StrICmp(pColl->zName, pIdx->azColl[i]) ){
+ if( !pColl ){
+ pColl = db->pDfltColl;
+ }
+ if( i<pIdx->nColumn ){
+ iColumn = pIdx->aiColumn[i];
+ if( iColumn==pIdx->pTable->iPKey ){
+ iColumn = -1;
+ }
+ iSortOrder = pIdx->aSortOrder[i];
+ zColl = pIdx->azColl[i];
+ }else{
+ iColumn = -1;
+ iSortOrder = 0;
+ zColl = pColl->zName;
+ }
+ if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){
/* Term j of the ORDER BY clause does not match column i of the index */
if( i<nEqCol ){
/* If an index column that is constrained by == fails to match an
@@ -888,8 +1050,8 @@ static int isSortingIndex(
}
assert( pIdx->aSortOrder!=0 );
assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
- assert( pIdx->aSortOrder[i]==0 || pIdx->aSortOrder[i]==1 );
- termSortOrder = pIdx->aSortOrder[i] ^ pTerm->sortOrder;
+ assert( iSortOrder==0 || iSortOrder==1 );
+ termSortOrder = iSortOrder ^ pTerm->sortOrder;
if( i>nEqCol ){
if( termSortOrder!=sortOrder ){
/* Indices can only be used if all ORDER BY terms past the
@@ -901,13 +1063,29 @@ static int isSortingIndex(
}
j++;
pTerm++;
+ if( iColumn<0 && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){
+ /* If the indexed column is the primary key and everything matches
+ ** so far and none of the ORDER BY terms to the right reference other
+ ** tables in the join, then we are assured that the index can be used
+ ** to sort because the primary key is unique and so none of the other
+ ** columns will make any difference
+ */
+ j = nTerm;
+ }
}
- /* The index can be used for sorting if all terms of the ORDER BY clause
- ** are covered.
- */
+ *pbRev = sortOrder!=0;
if( j>=nTerm ){
- *pbRev = sortOrder!=0;
+ /* All terms of the ORDER BY clause are covered by this index so
+ ** this index can be used for sorting. */
+ return 1;
+ }
+ if( pIdx->onError!=OE_None && i==pIdx->nColumn
+ && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){
+ /* All terms of this index match some prefix of the ORDER BY clause
+ ** and the index is UNIQUE and no terms on the tail of the ORDER BY
+ ** clause reference other tables in a join. If this is all true then
+ ** the order by clause is superfluous. */
return 1;
}
return 0;
@@ -921,6 +1099,7 @@ static int isSortingIndex(
static int sortableByRowid(
int base, /* Cursor number for table to be sorted */
ExprList *pOrderBy, /* The ORDER BY clause */
+ ExprMaskSet *pMaskSet, /* Mapping from tables to bitmaps */
int *pbRev /* Set to 1 if ORDER BY is DESC */
){
Expr *p;
@@ -928,8 +1107,8 @@ static int sortableByRowid(
assert( pOrderBy!=0 );
assert( pOrderBy->nExpr>0 );
p = pOrderBy->a[0].pExpr;
- if( pOrderBy->nExpr==1 && p->op==TK_COLUMN && p->iTable==base
- && p->iColumn==-1 ){
+ if( p->op==TK_COLUMN && p->iTable==base && p->iColumn==-1
+ && !referencesOtherTables(pOrderBy, pMaskSet, 1, base) ){
*pbRev = pOrderBy->a[0].sortOrder;
return 1;
}
@@ -959,8 +1138,7 @@ static double estLog(double N){
** SQLITE_TEST or SQLITE_DEBUG are defined, then these routines
** are no-ops.
*/
-#if !defined(SQLITE_OMIT_VIRTUALTABLE) && \
- (defined(SQLITE_TEST) || defined(SQLITE_DEBUG))
+#if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_DEBUG)
static void TRACE_IDX_INPUTS(sqlite3_index_info *p){
int i;
if( !sqlite3_where_trace ) return;
@@ -1042,7 +1220,7 @@ static double bestVirtualIndex(
if( pIdxInfo==0 ){
WhereTerm *pTerm;
int nTerm;
- TRACE(("Recomputing index info for %s...\n", pTab->zName));
+ WHERETRACE(("Recomputing index info for %s...\n", pTab->zName));
/* Count the number of possible WHERE clause constraints referring
** to this virtual table */
@@ -1125,13 +1303,19 @@ static double bestVirtualIndex(
** xBestIndex.
*/
- /* The module name must be defined */
+ /* The module name must be defined. Also, by this point there must
+ ** be a pointer to an sqlite3_vtab structure. Otherwise
+ ** sqlite3ViewGetColumnNames() would have picked up the error.
+ */
assert( pTab->azModuleArg && pTab->azModuleArg[0] );
+ assert( pTab->pVtab );
+#if 0
if( pTab->pVtab==0 ){
sqlite3ErrorMsg(pParse, "undefined module %s for table %s",
pTab->azModuleArg[0], pTab->zName);
return 0.0;
}
+#endif
/* Set the aConstraint[].usable fields and initialize all
** output variables to zero.
@@ -1175,7 +1359,7 @@ static double bestVirtualIndex(
}
sqlite3SafetyOff(pParse->db);
- TRACE(("xBestIndex for %s\n", pTab->zName));
+ WHERETRACE(("xBestIndex for %s\n", pTab->zName));
TRACE_IDX_INPUTS(pIdxInfo);
rc = pTab->pVtab->pModule->xBestIndex(pTab->pVtab, pIdxInfo);
TRACE_IDX_OUTPUTS(pIdxInfo);
@@ -1190,6 +1374,7 @@ static double bestVirtualIndex(
rc = sqlite3SafetyOn(pParse->db);
}
*(int*)&pIdxInfo->nOrderBy = nOrderBy;
+
return pIdxInfo->estimatedCost;
}
#endif /* SQLITE_OMIT_VIRTUALTABLE */
@@ -1232,9 +1417,10 @@ static double bestIndex(
int rev; /* True to scan in reverse order */
int flags; /* Flags associated with pProbe */
int nEq; /* Number of == or IN constraints */
+ int eqTermMask; /* Mask of valid equality operators */
double cost; /* Cost of using pProbe */
- TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
+ WHERETRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
lowestCost = SQLITE_BIG_DBL;
pProbe = pSrc->pTab->pIndex;
@@ -1246,7 +1432,7 @@ static double bestIndex(
*/
if( pProbe==0 &&
findTerm(pWC, iCur, -1, 0, WO_EQ|WO_IN|WO_LT|WO_LE|WO_GT|WO_GE,0)==0 &&
- (pOrderBy==0 || !sortableByRowid(iCur, pOrderBy, &rev)) ){
+ (pOrderBy==0 || !sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev)) ){
*pFlags = 0;
*ppIndex = 0;
*pnEq = 0;
@@ -1265,7 +1451,7 @@ static double bestIndex(
** a single row is generated, output is always in sorted order */
*pFlags = WHERE_ROWID_EQ | WHERE_UNIQUE;
*pnEq = 1;
- TRACE(("... best is rowid\n"));
+ WHERETRACE(("... best is rowid\n"));
return 0.0;
}else if( (pExpr = pTerm->pExpr)->pList!=0 ){
/* Rowid IN (LIST): cost is NlogN where N is the number of list
@@ -1278,14 +1464,14 @@ static double bestIndex(
** that value so make a wild guess. */
lowestCost = 200;
}
- TRACE(("... rowid IN cost: %.9g\n", lowestCost));
+ WHERETRACE(("... rowid IN cost: %.9g\n", lowestCost));
}
/* Estimate the cost of a table scan. If we do not know how many
** entries are in the table, use 1 million as a guess.
*/
cost = pProbe ? pProbe->aiRowEst[0] : 1000000;
- TRACE(("... table scan base cost: %.9g\n", cost));
+ WHERETRACE(("... table scan base cost: %.9g\n", cost));
flags = WHERE_ROWID_RANGE;
/* Check for constraints on a range of rowids in a table scan.
@@ -1300,7 +1486,7 @@ static double bestIndex(
flags |= WHERE_BTM_LIMIT;
cost /= 3; /* Guess that rowid>EXPR eliminates two-thirds of rows */
}
- TRACE(("... rowid range reduces cost to %.9g\n", cost));
+ WHERETRACE(("... rowid range reduces cost to %.9g\n", cost));
}else{
flags = 0;
}
@@ -1308,14 +1494,14 @@ static double bestIndex(
/* If the table scan does not satisfy the ORDER BY clause, increase
** the cost by NlogN to cover the expense of sorting. */
if( pOrderBy ){
- if( sortableByRowid(iCur, pOrderBy, &rev) ){
+ if( sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev) ){
flags |= WHERE_ORDERBY|WHERE_ROWID_RANGE;
if( rev ){
flags |= WHERE_REVERSE;
}
}else{
cost += cost*estLog(cost);
- TRACE(("... sorting increases cost to %.9g\n", cost));
+ WHERETRACE(("... sorting increases cost to %.9g\n", cost));
}
}
if( cost<lowestCost ){
@@ -1323,13 +1509,24 @@ static double bestIndex(
bestFlags = flags;
}
+ /* If the pSrc table is the right table of a LEFT JOIN then we may not
+ ** use an index to satisfy IS NULL constraints on that table. This is
+ ** because columns might end up being NULL if the table does not match -
+ ** a circumstance which the index cannot help us discover. Ticket #2177.
+ */
+ if( (pSrc->jointype & JT_LEFT)!=0 ){
+ eqTermMask = WO_EQ|WO_IN;
+ }else{
+ eqTermMask = WO_EQ|WO_IN|WO_ISNULL;
+ }
+
/* Look at each index.
*/
for(; pProbe; pProbe=pProbe->pNext){
int i; /* Loop counter */
double inMultiplier = 1;
- TRACE(("... index %s:\n", pProbe->zName));
+ WHERETRACE(("... index %s:\n", pProbe->zName));
/* Count the number of columns in the index that are satisfied
** by x=EXPR constraints or x IN (...) constraints.
@@ -1337,7 +1534,7 @@ static double bestIndex(
flags = 0;
for(i=0; i<pProbe->nColumn; i++){
int j = pProbe->aiColumn[i];
- pTerm = findTerm(pWC, iCur, j, notReady, WO_EQ|WO_IN, pProbe);
+ pTerm = findTerm(pWC, iCur, j, notReady, eqTermMask, pProbe);
if( pTerm==0 ) break;
flags |= WHERE_COLUMN_EQ;
if( pTerm->eOperator & WO_IN ){
@@ -1356,7 +1553,7 @@ static double bestIndex(
&& nEq==pProbe->nColumn ){
flags |= WHERE_UNIQUE;
}
- TRACE(("...... nEq=%d inMult=%.9g cost=%.9g\n", nEq, inMultiplier, cost));
+ WHERETRACE(("...... nEq=%d inMult=%.9g cost=%.9g\n", nEq, inMultiplier, cost));
/* Look for range constraints
*/
@@ -1373,7 +1570,7 @@ static double bestIndex(
flags |= WHERE_BTM_LIMIT;
cost /= 3;
}
- TRACE(("...... range reduces cost to %.9g\n", cost));
+ WHERETRACE(("...... range reduces cost to %.9g\n", cost));
}
}
@@ -1381,7 +1578,7 @@ static double bestIndex(
*/
if( pOrderBy ){
if( (flags & WHERE_COLUMN_IN)==0 &&
- isSortingIndex(pParse,pProbe,iCur,pOrderBy,nEq,&rev) ){
+ isSortingIndex(pParse,pWC->pMaskSet,pProbe,iCur,pOrderBy,nEq,&rev) ){
if( flags==0 ){
flags = WHERE_COLUMN_RANGE;
}
@@ -1391,7 +1588,7 @@ static double bestIndex(
}
}else{
cost += cost*estLog(cost);
- TRACE(("...... orderby increases cost to %.9g\n", cost));
+ WHERETRACE(("...... orderby increases cost to %.9g\n", cost));
}
}
@@ -1411,7 +1608,7 @@ static double bestIndex(
if( m==0 ){
flags |= WHERE_IDX_ONLY;
cost /= 2;
- TRACE(("...... idx-only reduces cost to %.9g\n", cost));
+ WHERETRACE(("...... idx-only reduces cost to %.9g\n", cost));
}
}
@@ -1429,9 +1626,9 @@ static double bestIndex(
/* Report the best result
*/
*ppIndex = bestIdx;
- TRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n",
+ WHERETRACE(("best index is %s, cost=%.9g, flags=%x, nEq=%d\n",
bestIdx ? bestIdx->zName : "(none)", lowestCost, bestFlags, bestNEq));
- *pFlags = bestFlags;
+ *pFlags = bestFlags | eqTermMask;
*pnEq = bestNEq;
return lowestCost;
}
@@ -1476,30 +1673,18 @@ static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
}
/*
-** Generate code that builds a probe for an index. Details:
-**
-** * Check the top nColumn entries on the stack. If any
-** of those entries are NULL, jump immediately to brk,
-** which is the loop exit, since no index entry will match
-** if any part of the key is NULL. Pop (nColumn+nExtra)
-** elements from the stack.
-**
-** * Construct a probe entry from the top nColumn entries in
-** the stack with affinities appropriate for index pIdx.
-** Only nColumn elements are popped from the stack in this case
-** (by OP_MakeRecord).
+** Generate code that builds a probe for an index.
**
+** There should be nColumn values on the stack. The index
+** to be probed is pIdx. Pop the values from the stack and
+** replace them all with a single record that is the index
+** problem.
*/
static void buildIndexProbe(
- Vdbe *v,
- int nColumn,
- int nExtra,
- int brk,
- Index *pIdx
+ Vdbe *v, /* Generate code into this VM */
+ int nColumn, /* The number of columns to check for NULL */
+ Index *pIdx /* Index that we will be searching */
){
- sqlite3VdbeAddOp(v, OP_NotNull, -nColumn, sqlite3VdbeCurrentAddr(v)+3);
- sqlite3VdbeAddOp(v, OP_Pop, nColumn+nExtra, 0);
- sqlite3VdbeAddOp(v, OP_Goto, 0, brk);
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
sqlite3IndexAffinityStr(v, pIdx);
}
@@ -1519,31 +1704,36 @@ static void buildIndexProbe(
static void codeEqualityTerm(
Parse *pParse, /* The parsing context */
WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
- int brk, /* Jump here to abandon the loop */
WhereLevel *pLevel /* When level of the FROM clause we are working on */
){
Expr *pX = pTerm->pExpr;
- if( pX->op!=TK_IN ){
- assert( pX->op==TK_EQ );
+ Vdbe *v = pParse->pVdbe;
+ if( pX->op==TK_EQ ){
sqlite3ExprCode(pParse, pX->pRight);
+ }else if( pX->op==TK_ISNULL ){
+ sqlite3VdbeAddOp(v, OP_Null, 0, 0);
#ifndef SQLITE_OMIT_SUBQUERY
}else{
int iTab;
- int *aIn;
- Vdbe *v = pParse->pVdbe;
+ struct InLoop *pIn;
+ assert( pX->op==TK_IN );
sqlite3CodeSubselect(pParse, pX);
iTab = pX->iTable;
sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
+ if( pLevel->nIn==0 ){
+ pLevel->nxt = sqlite3VdbeMakeLabel(v);
+ }
pLevel->nIn++;
- sqliteReallocOrFree((void**)&pLevel->aInLoop,
- sizeof(pLevel->aInLoop[0])*2*pLevel->nIn);
- aIn = pLevel->aInLoop;
- if( aIn ){
- aIn += pLevel->nIn*2 - 2;
- aIn[0] = iTab;
- aIn[1] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
+ pLevel->aInLoop = sqliteReallocOrFree(pLevel->aInLoop,
+ sizeof(pLevel->aInLoop[0])*pLevel->nIn);
+ pIn = pLevel->aInLoop;
+ if( pIn ){
+ pIn += pLevel->nIn - 1;
+ pIn->iCur = iTab;
+ pIn->topAddr = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
+ sqlite3VdbeAddOp(v, OP_IsNull, -1, 0);
}else{
pLevel->nIn = 0;
}
@@ -1579,8 +1769,7 @@ static void codeAllEqualityTerms(
Parse *pParse, /* Parsing context */
WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */
WhereClause *pWC, /* The WHERE clause */
- Bitmask notReady, /* Which parts of FROM have not yet been coded */
- int brk /* Jump here to end the loop */
+ Bitmask notReady /* Which parts of FROM have not yet been coded */
){
int nEq = pLevel->nEq; /* The number of == or IN constraints to code */
int termsInMem = 0; /* If true, store value in mem[] cells */
@@ -1603,17 +1792,20 @@ static void codeAllEqualityTerms(
/* Evaluate the equality constraints
*/
- for(j=0; j<pIdx->nColumn; j++){
+ assert( pIdx->nColumn>=nEq );
+ for(j=0; j<nEq; j++){
int k = pIdx->aiColumn[j];
- pTerm = findTerm(pWC, iCur, k, notReady, WO_EQ|WO_IN, pIdx);
+ pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx);
if( pTerm==0 ) break;
assert( (pTerm->flags & TERM_CODED)==0 );
- codeEqualityTerm(pParse, pTerm, brk, pLevel);
+ codeEqualityTerm(pParse, pTerm, pLevel);
+ if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){
+ sqlite3VdbeAddOp(v, OP_IsNull, termsInMem ? -1 : -(j+1), pLevel->brk);
+ }
if( termsInMem ){
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem+j+1, 1);
}
}
- assert( j==nEq );
/* Make sure all the constraint values are on the top of the stack
*/
@@ -1647,6 +1839,10 @@ static void whereInfoFree(WhereInfo *pWInfo){
sqlite3_index_info *pInfo = pWInfo->a[i].pIdxInfo;
if( pInfo ){
if( pInfo->needToFreeIdxStr ){
+ /* Coverage: Don't think this can be reached. By the time this
+ ** function is called, the index-strings have been passed
+ ** to the vdbe layer for deletion.
+ */
sqlite3_free(pInfo->idxStr);
}
sqliteFree(pInfo);
@@ -1776,7 +1972,7 @@ WhereInfo *sqlite3WhereBegin(
** subexpression is separated by an AND operator.
*/
initMaskSet(&maskSet);
- whereClauseInit(&wc, pParse);
+ whereClauseInit(&wc, pParse, &maskSet);
whereSplit(&wc, pWhere, TK_AND);
/* Allocate and initialize the WhereInfo structure that will become the
@@ -1807,7 +2003,7 @@ WhereInfo *sqlite3WhereBegin(
for(i=0; i<pTabList->nSrc; i++){
createMask(&maskSet, pTabList->a[i].iCursor);
}
- exprAnalyzeAll(pTabList, &maskSet, &wc);
+ exprAnalyzeAll(pTabList, &wc);
if( sqlite3MallocFailed() ){
goto whereBeginNoMem;
}
@@ -1830,7 +2026,7 @@ WhereInfo *sqlite3WhereBegin(
pTabItem = pTabList->a;
pLevel = pWInfo->a;
andFlags = ~0;
- TRACE(("*** Optimizer Start ***\n"));
+ WHERETRACE(("*** Optimizer Start ***\n"));
for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
Index *pIdx; /* Index for FROM table at pTabItem */
int flags; /* Flags asssociated with pIdx */
@@ -1850,8 +2046,7 @@ WhereInfo *sqlite3WhereBegin(
for(j=iFrom, pTabItem=&pTabList->a[j]; j<pTabList->nSrc; j++, pTabItem++){
int doNotReorder; /* True if this table should not be reordered */
- doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
- || (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0);
+ doNotReorder = (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0;
if( once && doNotReorder ) break;
m = getMask(&maskSet, pTabItem->iCursor);
if( (m & notReady)==0 ){
@@ -1872,6 +2067,14 @@ WhereInfo *sqlite3WhereBegin(
}
pIdx = 0;
nEq = 0;
+ if( (SQLITE_BIG_DBL/2.0)<cost ){
+ /* The cost is not allowed to be larger than SQLITE_BIG_DBL (the
+ ** inital value of lowestCost in this loop. If it is, then
+ ** the (cost<lowestCost) test below will never be true and
+ ** pLevel->pBestIdx never set.
+ */
+ cost = (SQLITE_BIG_DBL/2.0);
+ }
}else
#endif
{
@@ -1891,7 +2094,7 @@ WhereInfo *sqlite3WhereBegin(
}
if( doNotReorder ) break;
}
- TRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
+ WHERETRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
pLevel-pWInfo->a));
if( (bestFlags & WHERE_ORDERBY)!=0 ){
*ppOrderBy = 0;
@@ -1910,7 +2113,7 @@ WhereInfo *sqlite3WhereBegin(
notReady &= ~getMask(&maskSet, pTabList->a[bestJ].iCursor);
pLevel->iFrom = bestJ;
}
- TRACE(("*** Optimizer Finished ***\n"));
+ WHERETRACE(("*** Optimizer Finished ***\n"));
/* If the total query only selects a single row, then the ORDER BY
** clause is irrelevant.
@@ -1986,7 +2189,9 @@ WhereInfo *sqlite3WhereBegin(
sqlite3VdbeOp3(v, OP_OpenRead, iIdxCur, pIx->tnum,
(char*)pKey, P3_KEYINFO_HANDOFF);
}
- if( (pLevel->flags & WHERE_IDX_ONLY)!=0 ){
+ if( (pLevel->flags & (WHERE_IDX_ONLY|WHERE_COLUMN_RANGE))!=0 ){
+ /* Only call OP_SetNumColumns on the index if we might later use
+ ** OP_Column on the index. */
sqlite3VdbeAddOp(v, OP_SetNumColumns, iIdxCur, pIx->nColumn+1);
}
sqlite3CodeVerifySchema(pParse, iDb);
@@ -2002,6 +2207,7 @@ WhereInfo *sqlite3WhereBegin(
int j;
int iCur = pTabItem->iCursor; /* The VDBE cursor for the table */
Index *pIdx; /* The index we will be using */
+ int nxt; /* Where to jump to continue with the next IN case */
int iIdxCur; /* The VDBE cursor for the index */
int omitTable; /* True if we use the index only */
int bRev; /* True if we need to scan in reverse order */
@@ -2017,15 +2223,20 @@ WhereInfo *sqlite3WhereBegin(
** for the current loop. Jump to brk to break out of a loop.
** Jump to cont to go immediately to the next iteration of the
** loop.
+ **
+ ** When there is an IN operator, we also have a "nxt" label that
+ ** means to continue with the next IN value combination. When
+ ** there are no IN operators in the constraints, the "nxt" label
+ ** is the same as "brk".
*/
- brk = pLevel->brk = sqlite3VdbeMakeLabel(v);
+ brk = pLevel->brk = pLevel->nxt = sqlite3VdbeMakeLabel(v);
cont = pLevel->cont = sqlite3VdbeMakeLabel(v);
/* If this is the right table of a LEFT OUTER JOIN, allocate and
** initialize a memory cell that records if this table matches any
** row of the left table of the join.
*/
- if( pLevel->iFrom>0 && (pTabItem[-1].jointype & JT_LEFT)!=0 ){
+ if( pLevel->iFrom>0 && (pTabItem[0].jointype & JT_LEFT)!=0 ){
if( !pParse->nMem ) pParse->nMem++;
pLevel->iLeftJoin = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_MemInt, 0, pLevel->iLeftJoin);
@@ -2084,9 +2295,10 @@ WhereInfo *sqlite3WhereBegin(
assert( pTerm->pExpr!=0 );
assert( pTerm->leftCursor==iCur );
assert( omitTable==0 );
- codeEqualityTerm(pParse, pTerm, brk, pLevel);
- sqlite3VdbeAddOp(v, OP_MustBeInt, 1, brk);
- sqlite3VdbeAddOp(v, OP_NotExists, iCur, brk);
+ codeEqualityTerm(pParse, pTerm, pLevel);
+ nxt = pLevel->nxt;
+ sqlite3VdbeAddOp(v, OP_MustBeInt, 1, nxt);
+ sqlite3VdbeAddOp(v, OP_NotExists, iCur, nxt);
VdbeComment((v, "pk"));
pLevel->op = OP_Noop;
}else if( pLevel->flags & WHERE_ROWID_RANGE ){
@@ -2159,14 +2371,13 @@ WhereInfo *sqlite3WhereBegin(
int btmEq=0; /* True if btm limit uses ==. False if strictly > */
int topOp, btmOp; /* Operators for the top and bottom search bounds */
int testOp;
- int nNotNull; /* Number of rows of index that must be non-NULL */
int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0;
int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0;
/* Generate code to evaluate all constraint terms using == or IN
** and level the values of those terms on the stack.
*/
- codeAllEqualityTerms(pParse, pLevel, &wc, notReady, brk);
+ codeAllEqualityTerms(pParse, pLevel, &wc, notReady);
/* Duplicate the equality term values because they will all be
** used twice: once to make the termination key and once to make the
@@ -2181,7 +2392,6 @@ WhereInfo *sqlite3WhereBegin(
** operator and the top bound is a < or <= operator. For a descending
** index the operators are reversed.
*/
- nNotNull = nEq + topLimit;
if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){
topOp = WO_LT|WO_LE;
btmOp = WO_GT|WO_GE;
@@ -2198,6 +2408,7 @@ WhereInfo *sqlite3WhereBegin(
** 2002-Dec-04: On a reverse-order scan, the so-called "termination"
** key computed here really ends up being the start key.
*/
+ nxt = pLevel->nxt;
if( topLimit ){
Expr *pX;
int k = pIdx->aiColumn[j];
@@ -2206,6 +2417,7 @@ WhereInfo *sqlite3WhereBegin(
pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 );
sqlite3ExprCode(pParse, pX->pRight);
+ sqlite3VdbeAddOp(v, OP_IsNull, -(nEq+1), nxt);
topEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm);
testOp = OP_IdxGE;
@@ -2216,10 +2428,10 @@ WhereInfo *sqlite3WhereBegin(
if( testOp!=OP_Noop ){
int nCol = nEq + topLimit;
pLevel->iMem = pParse->nMem++;
- buildIndexProbe(v, nCol, nEq, brk, pIdx);
+ buildIndexProbe(v, nCol, pIdx);
if( bRev ){
int op = topEq ? OP_MoveLe : OP_MoveLt;
- sqlite3VdbeAddOp(v, op, iIdxCur, brk);
+ sqlite3VdbeAddOp(v, op, iIdxCur, nxt);
}else{
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
}
@@ -2244,6 +2456,7 @@ WhereInfo *sqlite3WhereBegin(
pX = pTerm->pExpr;
assert( (pTerm->flags & TERM_CODED)==0 );
sqlite3ExprCode(pParse, pX->pRight);
+ sqlite3VdbeAddOp(v, OP_IsNull, -(nEq+1), nxt);
btmEq = pTerm->eOperator & (WO_LE|WO_GE);
disableTerm(pLevel, pTerm);
}else{
@@ -2251,14 +2464,14 @@ WhereInfo *sqlite3WhereBegin(
}
if( nEq>0 || btmLimit ){
int nCol = nEq + btmLimit;
- buildIndexProbe(v, nCol, 0, brk, pIdx);
+ buildIndexProbe(v, nCol, pIdx);
if( bRev ){
pLevel->iMem = pParse->nMem++;
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 1);
testOp = OP_IdxLT;
}else{
int op = btmEq ? OP_MoveGe : OP_MoveGt;
- sqlite3VdbeAddOp(v, op, iIdxCur, brk);
+ sqlite3VdbeAddOp(v, op, iIdxCur, nxt);
}
}else if( bRev ){
testOp = OP_Noop;
@@ -2273,13 +2486,15 @@ WhereInfo *sqlite3WhereBegin(
start = sqlite3VdbeCurrentAddr(v);
if( testOp!=OP_Noop ){
sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, testOp, iIdxCur, brk);
+ sqlite3VdbeAddOp(v, testOp, iIdxCur, nxt);
if( (topEq && !bRev) || (!btmEq && bRev) ){
sqlite3VdbeChangeP3(v, -1, "+", P3_STATIC);
}
}
- sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_IdxIsNull, nNotNull, cont);
+ if( topLimit | btmLimit ){
+ sqlite3VdbeAddOp(v, OP_Column, iIdxCur, nEq);
+ sqlite3VdbeAddOp(v, OP_IsNull, 1, cont);
+ }
if( !omitTable ){
sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
@@ -2300,34 +2515,33 @@ WhereInfo *sqlite3WhereBegin(
/* Generate code to evaluate all constraint terms using == or IN
** and leave the values of those terms on the stack.
*/
- codeAllEqualityTerms(pParse, pLevel, &wc, notReady, brk);
+ codeAllEqualityTerms(pParse, pLevel, &wc, notReady);
+ nxt = pLevel->nxt;
/* Generate a single key that will be used to both start and terminate
** the search
*/
- buildIndexProbe(v, nEq, 0, brk, pIdx);
+ buildIndexProbe(v, nEq, pIdx);
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iMem, 0);
/* Generate code (1) to move to the first matching element of the table.
- ** Then generate code (2) that jumps to "brk" after the cursor is past
+ ** Then generate code (2) that jumps to "nxt" after the cursor is past
** the last matching element of the table. The code (1) is executed
** once to initialize the search, the code (2) is executed before each
** iteration of the scan to see if the scan has finished. */
if( bRev ){
/* Scan in reverse order */
- sqlite3VdbeAddOp(v, OP_MoveLe, iIdxCur, brk);
+ sqlite3VdbeAddOp(v, OP_MoveLe, iIdxCur, nxt);
start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeAddOp(v, OP_IdxLT, iIdxCur, brk);
+ sqlite3VdbeAddOp(v, OP_IdxLT, iIdxCur, nxt);
pLevel->op = OP_Prev;
}else{
/* Scan in the forward order */
- sqlite3VdbeAddOp(v, OP_MoveGe, iIdxCur, brk);
+ sqlite3VdbeAddOp(v, OP_MoveGe, iIdxCur, nxt);
start = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0);
- sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, brk, "+", P3_STATIC);
+ sqlite3VdbeOp3(v, OP_IdxGE, iIdxCur, nxt, "+", P3_STATIC);
pLevel->op = OP_Next;
}
- sqlite3VdbeAddOp(v, OP_RowKey, iIdxCur, 0);
- sqlite3VdbeAddOp(v, OP_IdxIsNull, nEq, cont);
if( !omitTable ){
sqlite3VdbeAddOp(v, OP_IdxRowid, iIdxCur, 0);
sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0);
@@ -2458,16 +2672,18 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
if( pLevel->op!=OP_Noop ){
sqlite3VdbeAddOp(v, pLevel->op, pLevel->p1, pLevel->p2);
}
- sqlite3VdbeResolveLabel(v, pLevel->brk);
if( pLevel->nIn ){
- int *a;
+ struct InLoop *pIn;
int j;
- for(j=pLevel->nIn, a=&pLevel->aInLoop[j*2-2]; j>0; j--, a-=2){
- sqlite3VdbeAddOp(v, OP_Next, a[0], a[1]);
- sqlite3VdbeJumpHere(v, a[1]-1);
+ sqlite3VdbeResolveLabel(v, pLevel->nxt);
+ for(j=pLevel->nIn, pIn=&pLevel->aInLoop[j-1]; j>0; j--, pIn--){
+ sqlite3VdbeJumpHere(v, pIn->topAddr+1);
+ sqlite3VdbeAddOp(v, OP_Next, pIn->iCur, pIn->topAddr);
+ sqlite3VdbeJumpHere(v, pIn->topAddr-1);
}
sqliteFree(pLevel->aInLoop);
}
+ sqlite3VdbeResolveLabel(v, pLevel->brk);
if( pLevel->iLeftJoin ){
int addr;
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, pLevel->iLeftJoin, 0);