Bug 338155 r=vlad Upgrade to sqlite 3.3.5
git-svn-id: svn://10.0.0.236/trunk@198171 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
78efbec655
commit
9ad00cae93
@ -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.6 2006-02-22 20:47:51 brettw%gmail.com Exp $
|
||||
** $Id: alter.c,v 1.7 2006-05-22 17:48:14 brettw%gmail.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** This file contains code associated with the ANALYZE command.
|
||||
**
|
||||
** @(#) $Id: analyze.c,v 1.3 2006-02-22 20:47:51 brettw%gmail.com Exp $
|
||||
** @(#) $Id: analyze.c,v 1.4 2006-05-22 17:48:14 brettw%gmail.com Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_ANALYZE
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the ATTACH and DETACH commands.
|
||||
**
|
||||
** $Id: attach.c,v 1.49 2006/01/24 12:09:18 danielk1977 Exp $
|
||||
** $Id: attach.c,v 1.51 2006/04/10 13:37:47 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -185,7 +185,12 @@ static void attachFunc(
|
||||
}
|
||||
sqlite3ResetInternalSchema(db, 0);
|
||||
db->nDb = iDb;
|
||||
sqlite3_snprintf(127, zErr, "unable to open database: %s", zFile);
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
if( !sqlite3MallocFailed() ) sqlite3FailedMalloc();
|
||||
sqlite3_snprintf(127, zErr, "out of memory");
|
||||
}else{
|
||||
sqlite3_snprintf(127, zErr, "unable to open database: %s", zFile);
|
||||
}
|
||||
goto attach_error;
|
||||
}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
** May you share freely, never taking more than you give.
|
||||
**
|
||||
*************************************************************************
|
||||
** $Id: btree.c,v 1.315 2006/02/22 03:08:33 drh Exp $
|
||||
** $Id: btree.c,v 1.324 2006/04/04 01:54:55 drh Exp $
|
||||
**
|
||||
** This file implements a external (disk-based) database using BTrees.
|
||||
** For a detailed discussion of BTrees, refer to
|
||||
@ -388,8 +388,8 @@ struct BtCursor {
|
||||
u8 wrFlag; /* True if writable */
|
||||
u8 eState; /* One of the CURSOR_XXX constants (see below) */
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
void *pKey;
|
||||
i64 nKey;
|
||||
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
|
||||
};
|
||||
@ -469,8 +469,15 @@ static void put4byte(unsigned char *p, u32 v){
|
||||
/* The database page the PENDING_BYTE occupies. This page is never used.
|
||||
** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They
|
||||
** should possibly be consolidated (presumably in pager.h).
|
||||
**
|
||||
** If disk I/O is omitted (meaning that the database is stored purely
|
||||
** in memory) then there is no pending byte.
|
||||
*/
|
||||
#define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
|
||||
#ifdef SQLITE_OMIT_DISKIO
|
||||
# define PENDING_BYTE_PAGE(pBt) 0x7fffffff
|
||||
#else
|
||||
# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** A linked list of the following structures is stored at BtShared.pLock.
|
||||
@ -867,7 +874,8 @@ static int ptrmapGet(BtShared *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
|
||||
}
|
||||
|
||||
offset = PTRMAP_PTROFFSET(pBt, key);
|
||||
if( pEType ) *pEType = pPtrmap[offset];
|
||||
assert( pEType!=0 );
|
||||
*pEType = pPtrmap[offset];
|
||||
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
|
||||
|
||||
sqlite3pager_unref(pPtrmap);
|
||||
@ -1624,8 +1632,8 @@ int sqlite3BtreeOpen(
|
||||
** the right size. This is to guard against size changes that result
|
||||
** when compiling on a different architecture.
|
||||
*/
|
||||
assert( sizeof(i64)==8 );
|
||||
assert( sizeof(u64)==8 );
|
||||
assert( sizeof(i64)==8 || sizeof(i64)==4 );
|
||||
assert( sizeof(u64)==8 || sizeof(u64)==4 );
|
||||
assert( sizeof(u32)==4 );
|
||||
assert( sizeof(u16)==2 );
|
||||
assert( sizeof(Pgno)==4 );
|
||||
@ -1685,7 +1693,7 @@ int sqlite3BtreeOpen(
|
||||
assert( (pBt->pageSize & 7)==0 ); /* 8-byte alignment of pageSize */
|
||||
sqlite3pager_set_pagesize(pBt->pPager, pBt->pageSize);
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
|
||||
/* Add the new btree to the linked list starting at ThreadData.pBtree.
|
||||
** There is no chance that a malloc() may fail inside of the
|
||||
** sqlite3ThreadData() call, as the ThreadData structure must have already
|
||||
@ -1750,7 +1758,7 @@ int sqlite3BtreeClose(Btree *p){
|
||||
pTsd->pBtree = pBt->pNext;
|
||||
}else{
|
||||
BtShared *pPrev;
|
||||
for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext);
|
||||
for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext){}
|
||||
if( pPrev ){
|
||||
assert( pTsd==sqlite3ThreadData() );
|
||||
pPrev->pNext = pBt->pNext;
|
||||
@ -2463,7 +2471,6 @@ static int autoVacuumCommit(BtShared *pBt, Pgno *nTrunc){
|
||||
if( rc!=SQLITE_OK ) goto autovacuum_out;
|
||||
put4byte(&pBt->pPage1->aData[32], 0);
|
||||
put4byte(&pBt->pPage1->aData[36], 0);
|
||||
if( rc!=SQLITE_OK ) goto autovacuum_out;
|
||||
*nTrunc = finSize;
|
||||
assert( finSize!=PENDING_BYTE_PAGE(pBt) );
|
||||
|
||||
@ -4069,6 +4076,7 @@ static int fillInCell(
|
||||
n = nPayload;
|
||||
if( n>spaceLeft ) n = spaceLeft;
|
||||
if( n>nSrc ) n = nSrc;
|
||||
assert( pSrc );
|
||||
memcpy(pPayload, pSrc, n);
|
||||
nPayload -= n;
|
||||
pPayload += n;
|
||||
@ -4093,6 +4101,7 @@ static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){
|
||||
MemPage *pThis;
|
||||
unsigned char *aData;
|
||||
|
||||
assert( pNewParent!=0 );
|
||||
if( pgno==0 ) return SQLITE_OK;
|
||||
assert( pBt->pPager!=0 );
|
||||
aData = sqlite3pager_lookup(pBt->pPager, pgno);
|
||||
@ -4103,7 +4112,7 @@ static int reparentPage(BtShared *pBt, Pgno pgno, MemPage *pNewParent, int idx){
|
||||
if( pThis->pParent!=pNewParent ){
|
||||
if( pThis->pParent ) sqlite3pager_unref(pThis->pParent->aData);
|
||||
pThis->pParent = pNewParent;
|
||||
if( pNewParent ) sqlite3pager_ref(pNewParent->aData);
|
||||
sqlite3pager_ref(pNewParent->aData);
|
||||
}
|
||||
pThis->idxParent = idx;
|
||||
}
|
||||
@ -4816,6 +4825,7 @@ static int balance_nonroot(MemPage *pPage){
|
||||
rc = sqlite3pager_write(pNew->aData);
|
||||
if( rc ) goto balance_cleanup;
|
||||
}else{
|
||||
assert( i>0 );
|
||||
rc = allocatePage(pBt, &pNew, &pgnoNew[i], pgnoNew[i-1], 0);
|
||||
if( rc ) goto balance_cleanup;
|
||||
apNew[i] = pNew;
|
||||
@ -4967,6 +4977,8 @@ static int balance_nonroot(MemPage *pPage){
|
||||
}
|
||||
}
|
||||
assert( j==nCell );
|
||||
assert( nOld>0 );
|
||||
assert( nNew>0 );
|
||||
if( (pageFlags & PTF_LEAF)==0 ){
|
||||
memcpy(&apNew[nNew-1]->aData[8], &apCopy[nOld-1]->aData[8], 4);
|
||||
}
|
||||
@ -6221,11 +6233,7 @@ static int checkTreePage(
|
||||
IntegrityCk *pCheck, /* Context for the sanity check */
|
||||
int iPage, /* Page number of the page to check */
|
||||
MemPage *pParent, /* Parent page */
|
||||
char *zParentContext, /* Parent context */
|
||||
char *zLowerBound, /* All keys should be greater than this, if not NULL */
|
||||
int nLower, /* Number of characters in zLowerBound */
|
||||
char *zUpperBound, /* All keys should be less than this, if not NULL */
|
||||
int nUpper /* Number of characters in zUpperBound */
|
||||
char *zParentContext /* Parent context */
|
||||
){
|
||||
MemPage *pPage;
|
||||
int i, rc, depth, d2, pgno, cnt;
|
||||
@ -6291,7 +6299,7 @@ static int checkTreePage(
|
||||
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, zContext);
|
||||
}
|
||||
#endif
|
||||
d2 = checkTreePage(pCheck,pgno,pPage,zContext,0,0,0,0);
|
||||
d2 = checkTreePage(pCheck,pgno,pPage,zContext);
|
||||
if( i>0 && d2!=depth ){
|
||||
checkAppendMsg(pCheck, zContext, "Child page depth differs");
|
||||
}
|
||||
@ -6306,7 +6314,7 @@ static int checkTreePage(
|
||||
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage, 0);
|
||||
}
|
||||
#endif
|
||||
checkTreePage(pCheck, pgno, pPage, zContext,0,0,0,0);
|
||||
checkTreePage(pCheck, pgno, pPage, zContext);
|
||||
}
|
||||
|
||||
/* Check for complete coverage of the page
|
||||
@ -6418,7 +6426,7 @@ char *sqlite3BtreeIntegrityCheck(Btree *p, int *aRoot, int nRoot){
|
||||
checkPtrmap(&sCheck, aRoot[i], PTRMAP_ROOTPAGE, 0, 0);
|
||||
}
|
||||
#endif
|
||||
checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ", 0,0,0,0);
|
||||
checkTreePage(&sCheck, aRoot[i], 0, "List of tree roots: ");
|
||||
}
|
||||
|
||||
/* Make sure every page in the file is referenced
|
||||
@ -6615,17 +6623,23 @@ int sqlite3BtreeSchemaLocked(Btree *p){
|
||||
return (queryTableLock(p, MASTER_ROOT, READ_LOCK)!=SQLITE_OK);
|
||||
}
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
/*
|
||||
** Obtain a lock on the table whose root page is iTab. The
|
||||
** lock is a write lock if isWritelock is true or a read lock
|
||||
** if it is false.
|
||||
*/
|
||||
int sqlite3BtreeLockTable(Btree *p, int iTab, u8 isWriteLock){
|
||||
int rc = SQLITE_OK;
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
u8 lockType = (isWriteLock?WRITE_LOCK:READ_LOCK);
|
||||
rc = queryTableLock(p, iTab, lockType);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = lockTable(p, iTab, lockType);
|
||||
}
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The following debugging interface has to be in this file (rather
|
||||
@ -6640,6 +6654,7 @@ int sqlite3_shared_cache_report(
|
||||
int objc,
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
#ifndef SQLITE_OMIT_SHARED_CACHE
|
||||
const ThreadData *pTd = sqlite3ThreadDataReadOnly();
|
||||
if( pTd->useSharedData ){
|
||||
BtShared *pBt;
|
||||
@ -6651,6 +6666,7 @@ int sqlite3_shared_cache_report(
|
||||
}
|
||||
Tcl_SetObjResult(interp, pRet);
|
||||
}
|
||||
#endif
|
||||
return TCL_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
** COMMIT
|
||||
** ROLLBACK
|
||||
**
|
||||
** $Id: build.c,v 1.388 2006/02/18 16:36:45 drh Exp $
|
||||
** $Id: build.c,v 1.394 2006/05/11 23:14:59 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -45,26 +45,28 @@ void sqlite3BeginParse(Parse *pParse, int explainFlag){
|
||||
** codeTableLocks() functions.
|
||||
*/
|
||||
struct TableLock {
|
||||
int iDb;
|
||||
int iTab;
|
||||
u8 isWriteLock;
|
||||
const char *zName;
|
||||
int iDb; /* The database containing the table to be locked */
|
||||
int iTab; /* The root page of the table to be locked */
|
||||
u8 isWriteLock; /* True for write lock. False for a read lock */
|
||||
const char *zName; /* Name of the table */
|
||||
};
|
||||
|
||||
/*
|
||||
** Have the compiled statement lock the table with rootpage iTab in database
|
||||
** iDb at the shared-cache level when executed. The isWriteLock argument
|
||||
** is zero for a read-lock, or non-zero for a write-lock.
|
||||
** Record the fact that we want to lock a table at run-time.
|
||||
**
|
||||
** The zName parameter should point to the unqualified table name. This is
|
||||
** used to provide a more informative error message should the lock fail.
|
||||
** The table to be locked has root page iTab and is found in database iDb.
|
||||
** A read or a write lock can be taken depending on isWritelock.
|
||||
**
|
||||
** This routine just records the fact that the lock is desired. The
|
||||
** code to make the lock occur is generated by a later call to
|
||||
** codeTableLocks() which occurs during sqlite3FinishCoding().
|
||||
*/
|
||||
void sqlite3TableLock(
|
||||
Parse *pParse,
|
||||
int iDb,
|
||||
int iTab,
|
||||
u8 isWriteLock,
|
||||
const char *zName
|
||||
Parse *pParse, /* Parsing context */
|
||||
int iDb, /* Index of the database containing the table to lock */
|
||||
int iTab, /* Root page number of the table to be locked */
|
||||
u8 isWriteLock, /* True for a write lock */
|
||||
const char *zName /* Name of the table to be locked */
|
||||
){
|
||||
int i;
|
||||
int nBytes;
|
||||
@ -341,7 +343,7 @@ static void freeIndex(Index *p){
|
||||
** it is not unlinked from the Table that it indexes.
|
||||
** Unlinking from the Table must be done by the calling function.
|
||||
*/
|
||||
static void sqliteDeleteIndex(sqlite3 *db, Index *p){
|
||||
static void sqliteDeleteIndex(Index *p){
|
||||
Index *pOld;
|
||||
const char *zName = p->zName;
|
||||
|
||||
@ -510,7 +512,7 @@ void sqlite3DeleteTable(sqlite3 *db, Table *pTable){
|
||||
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
|
||||
pNext = pIndex->pNext;
|
||||
assert( pIndex->pSchema==pTable->pSchema );
|
||||
sqliteDeleteIndex(db, pIndex);
|
||||
sqliteDeleteIndex(pIndex);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
||||
@ -693,8 +695,7 @@ int sqlite3CheckObjectName(Parse *pParse, const char *zName){
|
||||
** Begin constructing a new table representation in memory. This is
|
||||
** the first of several action routines that get called in response
|
||||
** to a CREATE TABLE statement. In particular, this routine is called
|
||||
** after seeing tokens "CREATE" and "TABLE" and the table name. The
|
||||
** pStart token is the CREATE and pName is the table name. The isTemp
|
||||
** after seeing tokens "CREATE" and "TABLE" and the table name. The isTemp
|
||||
** flag is true if the table should be stored in the auxiliary database
|
||||
** file instead of in the main database file. This is normally the case
|
||||
** when the "TEMP" or "TEMPORARY" keyword occurs in between
|
||||
@ -708,7 +709,6 @@ int sqlite3CheckObjectName(Parse *pParse, const char *zName){
|
||||
*/
|
||||
void sqlite3StartTable(
|
||||
Parse *pParse, /* Parser context */
|
||||
Token *pStart, /* The "CREATE" token */
|
||||
Token *pName1, /* First part of the name of the table or view */
|
||||
Token *pName2, /* Second part of the name of the table or view */
|
||||
int isTemp, /* True if this is a TEMP table */
|
||||
@ -1587,7 +1587,7 @@ void sqlite3CreateView(
|
||||
sqlite3SelectDelete(pSelect);
|
||||
return;
|
||||
}
|
||||
sqlite3StartTable(pParse, pBegin, pName1, pName2, isTemp, 1, 0);
|
||||
sqlite3StartTable(pParse, pName1, pName2, isTemp, 1, 0);
|
||||
p = pParse->pNewTable;
|
||||
if( p==0 || pParse->nErr ){
|
||||
sqlite3SelectDelete(pSelect);
|
||||
@ -1730,6 +1730,17 @@ static void sqliteViewResetAll(sqlite3 *db, int idx){
|
||||
** used by SQLite when the btree layer moves a table root page. The
|
||||
** root-page of a table or index in database iDb has changed from iFrom
|
||||
** to iTo.
|
||||
**
|
||||
** Ticket #1728: The symbol table might still contain information
|
||||
** on tables and/or indices that are the process of being deleted.
|
||||
** If you are unlucky, one of those deleted indices or tables might
|
||||
** have the same rootpage number as the real table or index that is
|
||||
** being moved. So we cannot stop searching after the first match
|
||||
** because the first match might be for one of the deleted indices
|
||||
** or tables and not the table/index that is actually being moved.
|
||||
** We must continue looping until all tables and indices with
|
||||
** rootpage==iFrom have been converted to have a rootpage of iTo
|
||||
** in order to be certain that we got the right one.
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||
void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
|
||||
@ -1741,7 +1752,6 @@ void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
|
||||
Table *pTab = sqliteHashData(pElem);
|
||||
if( pTab->tnum==iFrom ){
|
||||
pTab->tnum = iTo;
|
||||
return;
|
||||
}
|
||||
}
|
||||
pHash = &pDb->pSchema->idxHash;
|
||||
@ -1749,10 +1759,8 @@ void sqlite3RootPageMoved(Db *pDb, int iFrom, int iTo){
|
||||
Index *pIdx = sqliteHashData(pElem);
|
||||
if( pIdx->tnum==iFrom ){
|
||||
pIdx->tnum = iTo;
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1928,7 +1936,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView, int noErr){
|
||||
while( pTrigger ){
|
||||
assert( pTrigger->pSchema==pTab->pSchema ||
|
||||
pTrigger->pSchema==db->aDb[1].pSchema );
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger, 1);
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger);
|
||||
pTrigger = pTrigger->pNext;
|
||||
}
|
||||
|
||||
@ -2633,8 +2641,12 @@ void sqlite3DefaultRowEst(Index *pIdx){
|
||||
int i;
|
||||
assert( a!=0 );
|
||||
a[0] = 1000000;
|
||||
for(i=pIdx->nColumn; i>=1; i--){
|
||||
a[i] = 10;
|
||||
for(i=pIdx->nColumn; i>=5; i--){
|
||||
a[i] = 5;
|
||||
}
|
||||
while( i>=1 ){
|
||||
a[i] = 11 - i;
|
||||
i--;
|
||||
}
|
||||
if( pIdx->onError!=OE_None ){
|
||||
a[pIdx->nColumn] = 1;
|
||||
@ -3021,7 +3033,7 @@ void sqlite3CodeVerifySchema(Parse *pParse, int iDb){
|
||||
if( iDb>=0 ){
|
||||
assert( iDb<db->nDb );
|
||||
assert( db->aDb[iDb].pBt!=0 || iDb==1 );
|
||||
assert( iDb<32 );
|
||||
assert( iDb<MAX_ATTACHED+2 );
|
||||
mask = 1<<iDb;
|
||||
if( (pParse->cookieMask & mask)==0 ){
|
||||
pParse->cookieMask |= mask;
|
||||
@ -3113,7 +3125,7 @@ static void reindexDatabases(Parse *pParse, char const *zColl){
|
||||
Table *pTab; /* A table in the database */
|
||||
|
||||
for(iDb=0, pDb=db->aDb; iDb<db->nDb; iDb++, pDb++){
|
||||
if( pDb==0 ) continue;
|
||||
assert( pDb!=0 );
|
||||
for(k=sqliteHashFirst(&pDb->pSchema->tblHash); k; k=sqliteHashNext(k)){
|
||||
pTab = (Table*)sqliteHashData(k);
|
||||
reindexTable(pParse, pTab, zColl);
|
||||
|
||||
@ -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.4 2006-02-22 20:47:51 brettw%gmail.com Exp $
|
||||
** $Id: callback.c,v 1.5 2006-05-22 17:48:14 brettw%gmail.com Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
@ -178,9 +178,11 @@ static CollSeq *findCollSeqEntry(
|
||||
** return the pColl pointer to be deleted (because it wasn't added
|
||||
** to the hash table).
|
||||
*/
|
||||
assert( !pDel ||
|
||||
(sqlite3MallocFailed() && pDel==pColl) );
|
||||
sqliteFree(pDel);
|
||||
assert( !pDel || (sqlite3MallocFailed() && pDel==pColl) );
|
||||
if( pDel ){
|
||||
sqliteFree(pDel);
|
||||
pColl = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pColl;
|
||||
@ -312,3 +314,54 @@ FuncDef *sqlite3FindFunction(
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all resources held by the schema structure. The void* argument points
|
||||
** at a Schema struct. This function does not call sqliteFree() on the
|
||||
** pointer itself, it just cleans up subsiduary resources (i.e. the contents
|
||||
** of the schema hash tables).
|
||||
*/
|
||||
void sqlite3SchemaFree(void *p){
|
||||
Hash temp1;
|
||||
Hash temp2;
|
||||
HashElem *pElem;
|
||||
Schema *pSchema = (Schema *)p;
|
||||
|
||||
temp1 = pSchema->tblHash;
|
||||
temp2 = pSchema->trigHash;
|
||||
sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashClear(&pSchema->aFKey);
|
||||
sqlite3HashClear(&pSchema->idxHash);
|
||||
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
|
||||
sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
|
||||
}
|
||||
sqlite3HashClear(&temp2);
|
||||
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
|
||||
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
|
||||
Table *pTab = sqliteHashData(pElem);
|
||||
sqlite3DeleteTable(0, pTab);
|
||||
}
|
||||
sqlite3HashClear(&temp1);
|
||||
pSchema->pSeqTab = 0;
|
||||
pSchema->flags &= ~DB_SchemaLoaded;
|
||||
}
|
||||
|
||||
/*
|
||||
** Find and return the schema associated with a BTree. Create
|
||||
** a new one if necessary.
|
||||
*/
|
||||
Schema *sqlite3SchemaGet(Btree *pBt){
|
||||
Schema * p;
|
||||
if( pBt ){
|
||||
p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree);
|
||||
}else{
|
||||
p = (Schema *)sqliteMalloc(sizeof(Schema));
|
||||
}
|
||||
if( p && 0==p->file_format ){
|
||||
sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
** separating it out, the code will be automatically omitted from
|
||||
** static links that do not use it.
|
||||
**
|
||||
** $Id: complete.c,v 1.3 2006-02-22 20:47:51 brettw%gmail.com Exp $
|
||||
** $Id: complete.c,v 1.4 2006-05-22 17:48:14 brettw%gmail.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#ifndef SQLITE_OMIT_COMPLETE
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** in order to generate code for DELETE FROM statements.
|
||||
**
|
||||
** $Id: delete.c,v 1.121 2006/02/10 02:27:43 danielk1977 Exp $
|
||||
** $Id: delete.c,v 1.122 2006/02/24 02:53:50 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -382,7 +382,7 @@ void sqlite3GenerateRowDelete(
|
||||
){
|
||||
int addr;
|
||||
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
|
||||
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
|
||||
sqlite3GenerateRowIndexDelete(v, pTab, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
|
||||
if( count ){
|
||||
sqlite3VdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
|
||||
@ -407,7 +407,6 @@ void sqlite3GenerateRowDelete(
|
||||
** deleted.
|
||||
*/
|
||||
void sqlite3GenerateRowIndexDelete(
|
||||
sqlite3 *db, /* The database containing the index */
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
Table *pTab, /* Table containing the row to be deleted */
|
||||
int iCur, /* Cursor number for the table */
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are not a part of the official
|
||||
** SQLite API. These routines are unsupported.
|
||||
**
|
||||
** $Id: experimental.c,v 1.3 2006-02-22 20:47:51 brettw%gmail.com Exp $
|
||||
** $Id: experimental.c,v 1.4 2006-05-22 17:48:14 brettw%gmail.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This file contains routines used for analyzing expressions and
|
||||
** for generating VDBE code that evaluates expressions in SQLite.
|
||||
**
|
||||
** $Id: expr.c,v 1.254 2006/02/10 07:07:15 danielk1977 Exp $
|
||||
** $Id: expr.c,v 1.257 2006/03/17 13:56:34 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -841,11 +841,13 @@ static int lookupName(
|
||||
|
||||
if( pSrcList ){
|
||||
for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){
|
||||
Table *pTab = pItem->pTab;
|
||||
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
Table *pTab;
|
||||
int iDb;
|
||||
Column *pCol;
|
||||
|
||||
if( pTab==0 ) continue;
|
||||
pTab = pItem->pTab;
|
||||
assert( pTab!=0 );
|
||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||
assert( pTab->nCol>0 );
|
||||
if( zTab ){
|
||||
if( pItem->zAlias ){
|
||||
@ -1379,11 +1381,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||
** expression we need to rerun this code each time.
|
||||
*/
|
||||
if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){
|
||||
VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1);
|
||||
int j;
|
||||
for(j=0; j<3; j++){
|
||||
aOp[j].opcode = OP_Noop;
|
||||
}
|
||||
sqlite3VdbeChangeToNoop(v, testAddr-1, 3);
|
||||
testAddr = 0;
|
||||
}
|
||||
|
||||
@ -1692,7 +1690,9 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||
#ifndef SQLITE_OMIT_SUBQUERY
|
||||
case TK_EXISTS:
|
||||
case TK_SELECT: {
|
||||
sqlite3CodeSubselect(pParse, pExpr);
|
||||
if( pExpr->iColumn==0 ){
|
||||
sqlite3CodeSubselect(pParse, pExpr);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
|
||||
VdbeComment((v, "# load subquery result"));
|
||||
break;
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||
** All other code has file scope.
|
||||
**
|
||||
** $Id: func.c,v 1.122 2006/02/11 17:34:00 drh Exp $
|
||||
** $Id: func.c,v 1.128 2006/05/11 13:25:39 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -121,7 +121,13 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
switch( sqlite3_value_type(argv[0]) ){
|
||||
case SQLITE_INTEGER: {
|
||||
i64 iVal = sqlite3_value_int64(argv[0]);
|
||||
if( iVal<0 ) iVal = iVal * -1;
|
||||
if( iVal<0 ){
|
||||
if( (iVal<<1)==0 ){
|
||||
sqlite3_result_error(context, "integer overflow", -1);
|
||||
return;
|
||||
}
|
||||
iVal = -iVal;
|
||||
}
|
||||
sqlite3_result_int64(context, iVal);
|
||||
break;
|
||||
}
|
||||
@ -131,7 +137,7 @@ static void absFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
}
|
||||
default: {
|
||||
double rVal = sqlite3_value_double(argv[0]);
|
||||
if( rVal<0 ) rVal = rVal * -1.0;
|
||||
if( rVal<0 ) rVal = -rVal;
|
||||
sqlite3_result_double(context, rVal);
|
||||
break;
|
||||
}
|
||||
@ -195,10 +201,11 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
if( n>30 ) n = 30;
|
||||
if( n<0 ) n = 0;
|
||||
}
|
||||
if( SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
|
||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
|
||||
r = sqlite3_value_double(argv[0]);
|
||||
sqlite3_snprintf(sizeof(zBuf),zBuf,"%.*f",n,r);
|
||||
sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
|
||||
sqlite3AtoF(zBuf, &r);
|
||||
sqlite3_result_double(context, r);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -258,9 +265,11 @@ static void randomFunc(
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int r;
|
||||
sqlite_int64 r;
|
||||
sqlite3Randomness(sizeof(r), &r);
|
||||
sqlite3_result_int(context, r);
|
||||
if( (r<<1)==0 ) r = 0; /* Prevent 0x8000.... as the result so that we */
|
||||
/* can always do abs() of the result */
|
||||
sqlite3_result_int64(context, r);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -831,16 +840,8 @@ struct SumCtx {
|
||||
** that it returns NULL if it sums over no inputs. TOTAL returns
|
||||
** 0.0 in that case. In addition, TOTAL always returns a float where
|
||||
** SUM might return an integer if it never encounters a floating point
|
||||
** value.
|
||||
**
|
||||
** I am told that SUM() should raise an exception if it encounters
|
||||
** a integer overflow. But after pondering this, I decided that
|
||||
** behavior leads to brittle programs. So instead, I have coded
|
||||
** SUM() to revert to using floating point if it encounters an
|
||||
** integer overflow. The answer may not be exact, but it will be
|
||||
** close. If the SUM() function returns an integer, the value is
|
||||
** exact. If SUM() returns a floating point value, it means the
|
||||
** value might be approximated.
|
||||
** value. TOTAL never fails, but SUM might through an exception if
|
||||
** it overflows an integer.
|
||||
*/
|
||||
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
SumCtx *p;
|
||||
@ -1071,7 +1072,7 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
||||
}
|
||||
sqlite3RegisterDateTimeFunctions(db);
|
||||
#ifdef SQLITE_SSE
|
||||
sqlite3SseFunctions(db);
|
||||
(void)sqlite3SseFunctions(db);
|
||||
#endif
|
||||
#ifdef SQLITE_CASE_SENSITIVE_LIKE
|
||||
sqlite3RegisterLikeFunctions(db, 1);
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle INSERT statements in SQLite.
|
||||
**
|
||||
** $Id: insert.c,v 1.161 2006/02/10 02:27:43 danielk1977 Exp $
|
||||
** $Id: insert.c,v 1.164 2006/03/15 16:26:10 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -269,7 +269,7 @@ void sqlite3Insert(
|
||||
if( sqlite3IsReadOnly(pParse, pTab, triggers_exist) ){
|
||||
goto insert_cleanup;
|
||||
}
|
||||
if( pTab==0 ) goto insert_cleanup;
|
||||
assert( pTab!=0 );
|
||||
|
||||
/* If pTab is really a view, make sure it has been initialized.
|
||||
*/
|
||||
@ -874,7 +874,13 @@ void sqlite3GenerateConstraintChecks(
|
||||
sqlite3ExprIfTrue(pParse, pTab->pCheck, allOk, 1);
|
||||
assert( pParse->ckOffset==nCol );
|
||||
pParse->ckOffset = 0;
|
||||
sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, OE_Abort);
|
||||
onError = overrideError!=OE_Default ? overrideError : OE_Abort;
|
||||
if( onError==OE_Ignore || onError==OE_Replace ){
|
||||
sqlite3VdbeAddOp(v, OP_Pop, nCol+1+hasTwoRowids, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, ignoreDest);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
|
||||
}
|
||||
sqlite3VdbeResolveLabel(v, allOk);
|
||||
}
|
||||
#endif /* !defined(SQLITE_OMIT_CHECK) */
|
||||
@ -911,7 +917,7 @@ void sqlite3GenerateConstraintChecks(
|
||||
break;
|
||||
}
|
||||
case OE_Replace: {
|
||||
sqlite3GenerateRowIndexDelete(pParse->db, v, pTab, base, 0);
|
||||
sqlite3GenerateRowIndexDelete(v, pTab, base, 0);
|
||||
if( isUpdate ){
|
||||
sqlite3VdbeAddOp(v, OP_Dup, nCol+hasTwoRowids, 1);
|
||||
sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
|
||||
|
||||
@ -83,8 +83,8 @@ static int keywordCode(const char *z, int n){
|
||||
};
|
||||
int h, i;
|
||||
if( n<2 ) return TK_ID;
|
||||
h = ((sqlite3UpperToLower[((unsigned char*)z)[0]]*4) ^
|
||||
(sqlite3UpperToLower[((unsigned char*)z)[n-1]]*3) ^
|
||||
h = ((charMap(z[0])*4) ^
|
||||
(charMap(z[n-1])*3) ^
|
||||
n) % 127;
|
||||
for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
|
||||
if( aLen[i]==n && sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: legacy.c,v 1.13 2006/01/23 13:14:55 drh Exp $
|
||||
** $Id: legacy.c,v 1.14 2006/03/06 20:55:46 drh Exp $
|
||||
*/
|
||||
|
||||
#include "sqliteInt.h"
|
||||
@ -54,8 +54,8 @@ int sqlite3_exec(
|
||||
|
||||
pStmt = 0;
|
||||
rc = sqlite3_prepare(db, zSql, -1, &pStmt, &zLeftover);
|
||||
assert( rc==SQLITE_OK || pStmt==0 );
|
||||
if( rc!=SQLITE_OK ){
|
||||
if( pStmt ) sqlite3_finalize(pStmt);
|
||||
continue;
|
||||
}
|
||||
if( !pStmt ){
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
** other files are for internal use by SQLite and should not be
|
||||
** accessed by users of the library.
|
||||
**
|
||||
** $Id: main.c,v 1.335 2006/02/16 18:16:37 drh Exp $
|
||||
** $Id: main.c,v 1.339 2006/03/16 16:19:56 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -109,7 +109,10 @@ int sqlite3_close(sqlite3 *db){
|
||||
}
|
||||
|
||||
#ifdef SQLITE_SSE
|
||||
sqlite3_finalize(db->pFetch);
|
||||
{
|
||||
extern void sqlite3SseCleanup(sqlite3*);
|
||||
sqlite3SseCleanup(db);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If there are any outstanding VMs, return SQLITE_BUSY. */
|
||||
@ -250,7 +253,7 @@ static int sqliteDefaultBusyCallback(
|
||||
void *ptr, /* Database connection */
|
||||
int count /* Number of times table has been busy */
|
||||
){
|
||||
#if SQLITE_MIN_SLEEP_MS==1
|
||||
#if OS_WIN || (defined(HAVE_USLEEP) && HAVE_USLEEP)
|
||||
static const u8 delays[] =
|
||||
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 100 };
|
||||
static const u8 totals[] =
|
||||
@ -846,15 +849,13 @@ static int openDatabase(
|
||||
db->magic = SQLITE_MAGIC_CLOSED;
|
||||
goto opendb_out;
|
||||
}
|
||||
#ifndef SQLITE_OMIT_PARSER
|
||||
db->aDb[0].pSchema = sqlite3SchemaGet(db->aDb[0].pBt);
|
||||
db->aDb[1].pSchema = sqlite3SchemaGet(0);
|
||||
#endif
|
||||
|
||||
if( db->aDb[0].pSchema ){
|
||||
ENC(db) = SQLITE_UTF8;
|
||||
}
|
||||
|
||||
|
||||
/* The default safety_level for the main database is 'full'; for the temp
|
||||
** database it is 'NONE'. This matches the pager layer defaults.
|
||||
*/
|
||||
|
||||
@ -27,19 +27,12 @@
|
||||
# if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__) || defined(__BORLANDC__)
|
||||
# define OS_WIN 1
|
||||
# define OS_UNIX 0
|
||||
# define OS_OS2 0
|
||||
# elif defined(_EMX_) || defined(_OS2) || defined(OS2) || defined(OS_OS2)
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 0
|
||||
# define OS_OS2 1
|
||||
# else
|
||||
# define OS_WIN 0
|
||||
# define OS_UNIX 1
|
||||
# define OS_OS2 0
|
||||
# endif
|
||||
# else
|
||||
# define OS_UNIX 0
|
||||
# define OS_OS2 0
|
||||
# endif
|
||||
#else
|
||||
# ifndef OS_WIN
|
||||
@ -54,14 +47,6 @@
|
||||
#if OS_WIN
|
||||
# include <windows.h>
|
||||
# define SQLITE_TEMPNAME_SIZE (MAX_PATH+50)
|
||||
#elif OS_OS2
|
||||
# define INCL_DOSDATETIME
|
||||
# define INCL_DOSFILEMGR
|
||||
# define INCL_DOSERRORS
|
||||
# define INCL_DOSMISC
|
||||
# define INCL_DOSPROCESS
|
||||
# include <os2.h>
|
||||
# define SQLITE_TEMPNAME_SIZE (CCHMAXPATHCOMP)
|
||||
#else
|
||||
# define SQLITE_TEMPNAME_SIZE 200
|
||||
#endif
|
||||
@ -87,7 +72,7 @@
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Define the interfaces for Unix, Windows and OS/2.
|
||||
** Define the interfaces for Unix and for Windows.
|
||||
*/
|
||||
#if OS_UNIX
|
||||
#define sqlite3OsOpenReadWrite sqlite3UnixOpenReadWrite
|
||||
@ -133,28 +118,6 @@
|
||||
#define sqlite3OsFree sqlite3GenericFree
|
||||
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
|
||||
#endif
|
||||
#if OS_OS2
|
||||
#define sqlite3OsOpenReadWrite sqlite3Os2OpenReadWrite
|
||||
#define sqlite3OsOpenExclusive sqlite3Os2OpenExclusive
|
||||
#define sqlite3OsOpenReadOnly sqlite3Os2OpenReadOnly
|
||||
#define sqlite3OsDelete sqlite3Os2Delete
|
||||
#define sqlite3OsFileExists sqlite3Os2FileExists
|
||||
#define sqlite3OsFullPathname sqlite3Os2FullPathname
|
||||
#define sqlite3OsIsDirWritable sqlite3Os2IsDirWritable
|
||||
#define sqlite3OsSyncDirectory sqlite3Os2SyncDirectory
|
||||
#define sqlite3OsTempFileName sqlite3Os2TempFileName
|
||||
#define sqlite3OsRandomSeed sqlite3Os2RandomSeed
|
||||
#define sqlite3OsSleep sqlite3Os2Sleep
|
||||
#define sqlite3OsCurrentTime sqlite3Os2CurrentTime
|
||||
#define sqlite3OsEnterMutex sqlite3Os2EnterMutex
|
||||
#define sqlite3OsLeaveMutex sqlite3Os2LeaveMutex
|
||||
#define sqlite3OsInMutex sqlite3Os2InMutex
|
||||
#define sqlite3OsThreadSpecificData sqlite3Os2ThreadSpecificData
|
||||
#define sqlite3OsMalloc sqlite3GenericMalloc
|
||||
#define sqlite3OsRealloc sqlite3GenericRealloc
|
||||
#define sqlite3OsFree sqlite3GenericFree
|
||||
#define sqlite3OsAllocationSize sqlite3GenericAllocationSize
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If using an alternative OS interface, then we must have an "os_other.h"
|
||||
|
||||
@ -80,6 +80,7 @@ struct unixFile {
|
||||
unsigned char isOpen; /* True if needs to be closed */
|
||||
unsigned char fullSync; /* Use F_FULLSYNC if available */
|
||||
int dirfd; /* File descriptor for the directory */
|
||||
i64 offset; /* Seek offset */
|
||||
#ifdef SQLITE_UNIX_THREADS
|
||||
pthread_t tid; /* The thread that "owns" this OsFile */
|
||||
#endif
|
||||
@ -751,9 +752,6 @@ int sqlite3UnixOpenExclusive(const char *zFilename, OsFile **pId, int delFlag){
|
||||
|
||||
CRASH_TEST_OVERRIDE(sqlite3CrashOpenExclusive, zFilename, pId, delFlag);
|
||||
assert( 0==*pId );
|
||||
if( access(zFilename, 0)==0 ){
|
||||
return SQLITE_CANTOPEN;
|
||||
}
|
||||
f.h = open(zFilename,
|
||||
O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_LARGEFILE|O_BINARY,
|
||||
SQLITE_DEFAULT_FILE_PERMISSIONS);
|
||||
@ -904,6 +902,24 @@ int sqlite3UnixIsDirWritable(char *zBuf){
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
** Seek to the offset in id->offset then read cnt bytes into pBuf.
|
||||
** Return the number of bytes actually read. Update the offset.
|
||||
*/
|
||||
static int seekAndRead(unixFile *id, void *pBuf, int cnt){
|
||||
int got;
|
||||
#ifdef USE_PREAD
|
||||
got = pread(id->h, pBuf, cnt, id->offset);
|
||||
#else
|
||||
lseek(id->h, id->offset, SEEK_SET);
|
||||
got = read(id->h, pBuf, cnt);
|
||||
#endif
|
||||
if( got>0 ){
|
||||
id->offset += got;
|
||||
}
|
||||
return got;
|
||||
}
|
||||
|
||||
/*
|
||||
** Read data from a file into a buffer. Return SQLITE_OK if all
|
||||
** bytes were read successfully and SQLITE_IOERR if anything goes
|
||||
@ -914,7 +930,7 @@ static int unixRead(OsFile *id, void *pBuf, int amt){
|
||||
assert( id );
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
TIMER_START;
|
||||
got = read(((unixFile*)id)->h, pBuf, amt);
|
||||
got = seekAndRead((unixFile*)id, pBuf, amt);
|
||||
TIMER_END;
|
||||
TRACE5("READ %-3d %5d %7d %d\n", ((unixFile*)id)->h, got,
|
||||
last_page, TIMER_ELAPSED);
|
||||
@ -927,6 +943,25 @@ static int unixRead(OsFile *id, void *pBuf, int amt){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Seek to the offset in id->offset then read cnt bytes into pBuf.
|
||||
** Return the number of bytes actually read. Update the offset.
|
||||
*/
|
||||
static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){
|
||||
int got;
|
||||
#ifdef USE_PREAD
|
||||
got = pwrite(id->h, pBuf, cnt, id->offset);
|
||||
#else
|
||||
lseek(id->h, id->offset, SEEK_SET);
|
||||
got = write(id->h, pBuf, cnt);
|
||||
#endif
|
||||
if( got>0 ){
|
||||
id->offset += got;
|
||||
}
|
||||
return got;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Write data from a buffer into a file. Return SQLITE_OK on success
|
||||
** or some other error code on failure.
|
||||
@ -938,7 +973,7 @@ static int unixWrite(OsFile *id, const void *pBuf, int amt){
|
||||
SimulateIOError(SQLITE_IOERR);
|
||||
SimulateDiskfullError;
|
||||
TIMER_START;
|
||||
while( amt>0 && (wrote = write(((unixFile*)id)->h, pBuf, amt))>0 ){
|
||||
while( amt>0 && (wrote = seekAndWrite((unixFile*)id, pBuf, amt))>0 ){
|
||||
amt -= wrote;
|
||||
pBuf = &((char*)pBuf)[wrote];
|
||||
}
|
||||
@ -961,7 +996,7 @@ static int unixSeek(OsFile *id, i64 offset){
|
||||
#ifdef SQLITE_TEST
|
||||
if( offset ) SimulateDiskfullError
|
||||
#endif
|
||||
lseek(((unixFile*)id)->h, offset, SEEK_SET);
|
||||
((unixFile*)id)->offset = offset;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
@ -1635,6 +1670,7 @@ static int allocateUnixFile(unixFile *pInit, OsFile **pId){
|
||||
pInit->dirfd = -1;
|
||||
pInit->fullSync = 0;
|
||||
pInit->locktype = 0;
|
||||
pInit->offset = 0;
|
||||
SET_THREADID(pInit);
|
||||
pNew = sqlite3ThreadSafeMalloc( sizeof(unixFile) );
|
||||
if( pNew==0 ){
|
||||
|
||||
@ -128,19 +128,19 @@ int sqlite3_os_type = 0;
|
||||
** is obtained from sqliteMalloc.
|
||||
*/
|
||||
static WCHAR *utf8ToUnicode(const char *zFilename){
|
||||
int nByte;
|
||||
int nChar;
|
||||
WCHAR *zWideFilename;
|
||||
|
||||
if( !isNT() ){
|
||||
return 0;
|
||||
}
|
||||
nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0)*sizeof(WCHAR);
|
||||
zWideFilename = sqliteMalloc( nByte*sizeof(zWideFilename[0]) );
|
||||
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0);
|
||||
zWideFilename = sqliteMalloc( nChar*sizeof(zWideFilename[0]) );
|
||||
if( zWideFilename==0 ){
|
||||
return 0;
|
||||
}
|
||||
nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nByte);
|
||||
if( nByte==0 ){
|
||||
nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar);
|
||||
if( nChar==0 ){
|
||||
sqliteFree(zWideFilename);
|
||||
zWideFilename = 0;
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
** file simultaneously, or one process from reading the database while
|
||||
** another is writing.
|
||||
**
|
||||
** @(#) $Id: pager.c,v 1.258 2006/02/11 01:25:51 drh Exp $
|
||||
** @(#) $Id: pager.c,v 1.268 2006/05/07 17:49:39 drh Exp $
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_DISKIO
|
||||
#include "sqliteInt.h"
|
||||
@ -52,8 +52,8 @@
|
||||
** associated file-descriptor is returned. FILEHANDLEID() takes an OsFile
|
||||
** struct as it's argument.
|
||||
*/
|
||||
#define PAGERID(p) FILEHANDLEID(&(p)->fd)
|
||||
#define FILEHANDLEID(fd) (sqlite3OsFileHandle(&fd))
|
||||
#define PAGERID(p) ((int)(p->fd))
|
||||
#define FILEHANDLEID(fd) ((int)fd)
|
||||
|
||||
/*
|
||||
** The page cache as a whole is always in one of the following
|
||||
@ -161,7 +161,8 @@ struct PgHdr {
|
||||
u8 needSync; /* Sync journal before writing this page */
|
||||
u8 alwaysRollback; /* Disable dont_rollback() for this page */
|
||||
short int nRef; /* Number of users of this page */
|
||||
PgHdr *pDirty; /* Dirty pages sorted by PgHdr.pgno */
|
||||
PgHdr *pDirty, *pPrevDirty; /* Dirty pages sorted by PgHdr.pgno */
|
||||
u32 notUsed; /* Buffer space */
|
||||
#ifdef SQLITE_CHECK_PAGES
|
||||
u32 pageHash;
|
||||
#endif
|
||||
@ -190,9 +191,11 @@ struct PgHistory {
|
||||
** A macro used for invoking the codec if there is one
|
||||
*/
|
||||
#ifdef SQLITE_HAS_CODEC
|
||||
# define CODEC(P,D,N,X) if( P->xCodec ){ P->xCodec(P->pCodecArg,D,N,X); }
|
||||
# define CODEC1(P,D,N,X) if( P->xCodec!=0 ){ P->xCodec(P->pCodecArg,D,N,X); }
|
||||
# define CODEC2(P,D,N,X) ((char*)(P->xCodec!=0?P->xCodec(P->pCodecArg,D,N,X):D))
|
||||
#else
|
||||
# define CODEC(P,D,N,X)
|
||||
# define CODEC1(P,D,N,X) /* NO-OP */
|
||||
# define CODEC2(P,D,N,X) ((char*)D)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -205,24 +208,6 @@ struct PgHistory {
|
||||
#define PGHDR_TO_HIST(P,PGR) \
|
||||
((PgHistory*)&((char*)(&(P)[1]))[(PGR)->pageSize+(PGR)->nExtra])
|
||||
|
||||
/*
|
||||
** How big to make the hash table used for locating in-memory pages
|
||||
** by page number. This macro looks a little silly, but is evaluated
|
||||
** at compile-time, not run-time (at least for gcc this is true).
|
||||
*/
|
||||
#define N_PG_HASH (\
|
||||
(MAX_PAGES>1024)?2048: \
|
||||
(MAX_PAGES>512)?1024: \
|
||||
(MAX_PAGES>256)?512: \
|
||||
(MAX_PAGES>128)?256: \
|
||||
(MAX_PAGES>64)?128:64 \
|
||||
)
|
||||
|
||||
/*
|
||||
** Hash a page number
|
||||
*/
|
||||
#define pager_hash(PN) ((PN)&(N_PG_HASH-1))
|
||||
|
||||
/*
|
||||
** A open page cache is an instance of the following structure.
|
||||
**
|
||||
@ -278,6 +263,7 @@ struct Pager {
|
||||
PgHdr *pFirstSynced; /* First free page with PgHdr.needSync==0 */
|
||||
PgHdr *pAll; /* List of all pages */
|
||||
PgHdr *pStmt; /* List of pages in the statement subjournal */
|
||||
PgHdr *pDirty; /* List of all dirty pages */
|
||||
i64 journalOff; /* Current byte offset in the journal file */
|
||||
i64 journalHdr; /* Byte offset to previous journal header */
|
||||
i64 stmtHdrOff; /* First journal header written this statement */
|
||||
@ -290,9 +276,10 @@ struct Pager {
|
||||
#endif
|
||||
void (*xDestructor)(void*,int); /* Call this routine when freeing pages */
|
||||
void (*xReiniter)(void*,int); /* Call this routine when reloading pages */
|
||||
void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
|
||||
void *(*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
|
||||
void *pCodecArg; /* First argument to xCodec() */
|
||||
PgHdr *aHash[N_PG_HASH]; /* Hash table to map page number to PgHdr */
|
||||
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
|
||||
@ -399,6 +386,33 @@ static const unsigned char aJournalMagic[] = {
|
||||
# define REFINFO(X)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Change the size of the pager hash table to N. N must be a power
|
||||
** of two.
|
||||
*/
|
||||
static void pager_resize_hash_table(Pager *pPager, int N){
|
||||
PgHdr **aHash, *pPg;
|
||||
assert( N>0 && (N&(N-1))==0 );
|
||||
aHash = sqliteMalloc( sizeof(aHash[0])*N );
|
||||
if( aHash==0 ){
|
||||
/* Failure to rehash is not an error. It is only a performance hit. */
|
||||
return;
|
||||
}
|
||||
sqliteFree(pPager->aHash);
|
||||
pPager->nHash = N;
|
||||
pPager->aHash = aHash;
|
||||
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
|
||||
int h = pPg->pgno & (N-1);
|
||||
pPg->pNextHash = aHash[h];
|
||||
if( aHash[h] ){
|
||||
aHash[h]->pPrevHash = pPg;
|
||||
}
|
||||
aHash[h] = pPg;
|
||||
pPg->pPrevHash = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a 32-bit integer from the given file descriptor. Store the integer
|
||||
** that is read in *pRes. Return SQLITE_OK if everything worked, or an
|
||||
@ -435,16 +449,6 @@ static int write32bits(OsFile *fd, u32 val){
|
||||
return sqlite3OsWrite(fd, ac, 4);
|
||||
}
|
||||
|
||||
/*
|
||||
** Write the 32-bit integer 'val' into the page identified by page header
|
||||
** 'p' at offset 'offset'.
|
||||
*/
|
||||
static void store32bits(u32 val, PgHdr *p, int offset){
|
||||
char *ac;
|
||||
ac = &((char*)PGHDR_TO_DATA(p))[offset];
|
||||
put32bits(ac, val);
|
||||
}
|
||||
|
||||
/*
|
||||
** Read a 32-bit integer at offset 'offset' from the page identified by
|
||||
** page header 'p'.
|
||||
@ -828,7 +832,9 @@ static void page_remove_from_stmt_list(PgHdr *pPg){
|
||||
** a pointer to the page or NULL if not found.
|
||||
*/
|
||||
static PgHdr *pager_lookup(Pager *pPager, Pgno pgno){
|
||||
PgHdr *p = pPager->aHash[pager_hash(pgno)];
|
||||
PgHdr *p;
|
||||
if( pPager->aHash==0 ) return 0;
|
||||
p = pPager->aHash[pgno & (pPager->nHash-1)];
|
||||
while( p && p->pgno!=pgno ){
|
||||
p = p->pNextHash;
|
||||
}
|
||||
@ -852,8 +858,10 @@ static void pager_reset(Pager *pPager){
|
||||
pPager->pFirstSynced = 0;
|
||||
pPager->pLast = 0;
|
||||
pPager->pAll = 0;
|
||||
memset(pPager->aHash, 0, sizeof(pPager->aHash));
|
||||
pPager->nHash = 0;
|
||||
sqliteFree(pPager->aHash);
|
||||
pPager->nPage = 0;
|
||||
pPager->aHash = 0;
|
||||
if( pPager->state>=PAGER_RESERVED ){
|
||||
sqlite3pager_rollback(pPager);
|
||||
}
|
||||
@ -900,6 +908,7 @@ static int pager_unwritelock(Pager *pPager){
|
||||
pPg->pageHash = pager_pagehash(pPg);
|
||||
#endif
|
||||
}
|
||||
pPager->pDirty = 0;
|
||||
pPager->dirtyCache = 0;
|
||||
pPager->nRec = 0;
|
||||
}else{
|
||||
@ -935,7 +944,7 @@ static int pager_unwritelock(Pager *pPager){
|
||||
** only the middle sector is corrupt, we will still have a reasonable
|
||||
** chance of failing the checksum and thus detecting the problem.
|
||||
*/
|
||||
static u32 pager_cksum(Pager *pPager, Pgno pgno, const u8 *aData){
|
||||
static u32 pager_cksum(Pager *pPager, const u8 *aData){
|
||||
u32 cksum = pPager->cksumInit;
|
||||
int i = pPager->pageSize-200;
|
||||
while( i>0 ){
|
||||
@ -945,6 +954,9 @@ static u32 pager_cksum(Pager *pPager, Pgno pgno, const u8 *aData){
|
||||
return cksum;
|
||||
}
|
||||
|
||||
/* Forward declaration */
|
||||
static void makeClean(PgHdr*);
|
||||
|
||||
/*
|
||||
** Read a single page from the journal file opened on file descriptor
|
||||
** jfd. Playback this one page.
|
||||
@ -987,7 +999,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
|
||||
rc = read32bits(jfd, &cksum);
|
||||
if( rc ) return rc;
|
||||
pPager->journalOff += 4;
|
||||
if( pager_cksum(pPager, pgno, aData)!=cksum ){
|
||||
if( pager_cksum(pPager, aData)!=cksum ){
|
||||
return SQLITE_DONE;
|
||||
}
|
||||
}
|
||||
@ -1022,7 +1034,9 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize);
|
||||
}
|
||||
if( pPg ) pPg->dirty = 0;
|
||||
if( pPg ){
|
||||
makeClean(pPg);
|
||||
}
|
||||
}
|
||||
if( pPg ){
|
||||
/* No page should ever be explicitly rolled back that is in use, except
|
||||
@ -1041,7 +1055,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
|
||||
#ifdef SQLITE_CHECK_PAGES
|
||||
pPg->pageHash = pager_pagehash(pPg);
|
||||
#endif
|
||||
CODEC(pPager, pData, pPg->pgno, 3);
|
||||
CODEC1(pPager, pData, pPg->pgno, 3);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@ -1154,7 +1168,7 @@ static int pager_reload_cache(Pager *pPager){
|
||||
}
|
||||
TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||
if( rc ) break;
|
||||
CODEC(pPager, zBuf, pPg->pgno, 2);
|
||||
CODEC1(pPager, zBuf, pPg->pgno, 2);
|
||||
}else{
|
||||
memset(zBuf, 0, pPager->pageSize);
|
||||
}
|
||||
@ -1172,6 +1186,7 @@ static int pager_reload_cache(Pager *pPager){
|
||||
pPg->pageHash = pager_pagehash(pPg);
|
||||
#endif
|
||||
}
|
||||
pPager->pDirty = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1310,9 +1325,6 @@ static int pager_playback(Pager *pPager){
|
||||
pPager->dbSize = mxPg;
|
||||
}
|
||||
|
||||
/* rc = sqlite3OsSeek(pPager->jfd, JOURNAL_HDR_SZ(pPager)); */
|
||||
if( rc!=SQLITE_OK ) goto end_playback;
|
||||
|
||||
/* Copy original pages out of the journal and back into the database file.
|
||||
*/
|
||||
for(i=0; i<nRec; i++){
|
||||
@ -1328,13 +1340,8 @@ static int pager_playback(Pager *pPager){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Pages that have been written to the journal but never synced
|
||||
** where not restored by the loop above. We have to restore those
|
||||
** pages by reading them back from the original database.
|
||||
*/
|
||||
assert( rc==SQLITE_OK );
|
||||
pager_reload_cache(pPager);
|
||||
/*NOTREACHED*/
|
||||
assert( 0 );
|
||||
|
||||
end_playback:
|
||||
if( rc==SQLITE_OK ){
|
||||
@ -1821,12 +1828,26 @@ int sqlite3pager_pagecount(Pager *pPager){
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_MEMORYDB
|
||||
/*
|
||||
** Clear a PgHistory block
|
||||
*/
|
||||
static void clearHistory(PgHistory *pHist){
|
||||
sqliteFree(pHist->pOrig);
|
||||
sqliteFree(pHist->pStmt);
|
||||
pHist->pOrig = 0;
|
||||
pHist->pStmt = 0;
|
||||
}
|
||||
#else
|
||||
#define clearHistory(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Forward declaration
|
||||
*/
|
||||
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
|
||||
@ -1842,14 +1863,16 @@ static void unlinkHashChain(Pager *pPager, PgHdr *pPg){
|
||||
pPg->pNextHash->pPrevHash = pPg->pPrevHash;
|
||||
}
|
||||
if( pPg->pPrevHash ){
|
||||
assert( pPager->aHash[pager_hash(pPg->pgno)]!=pPg );
|
||||
assert( pPager->aHash[pPg->pgno & (pPager->nHash-1)]!=pPg );
|
||||
pPg->pPrevHash->pNextHash = pPg->pNextHash;
|
||||
}else{
|
||||
int h = pager_hash(pPg->pgno);
|
||||
int h = pPg->pgno & (pPager->nHash-1);
|
||||
assert( pPager->aHash[h]==pPg );
|
||||
pPager->aHash[h] = pPg->pNextHash;
|
||||
}
|
||||
|
||||
if( MEMDB ){
|
||||
clearHistory(PGHDR_TO_HIST(pPg, pPager));
|
||||
}
|
||||
pPg->pgno = 0;
|
||||
pPg->pNextHash = pPg->pPrevHash = 0;
|
||||
}
|
||||
@ -1908,6 +1931,7 @@ static void memoryTruncate(Pager *pPager){
|
||||
}else{
|
||||
*ppPg = pPg->pNextAll;
|
||||
unlinkPage(pPg);
|
||||
makeClean(pPg);
|
||||
sqliteFree(pPg);
|
||||
pPager->nPage--;
|
||||
}
|
||||
@ -2070,11 +2094,11 @@ int sqlite3pager_close(Pager *pPager){
|
||||
pTsd->pPager = pPager->pNext;
|
||||
}else{
|
||||
Pager *pTmp;
|
||||
for(pTmp = pTsd->pPager; pTmp->pNext!=pPager; pTmp=pTmp->pNext);
|
||||
for(pTmp = pTsd->pPager; pTmp->pNext!=pPager; pTmp=pTmp->pNext){}
|
||||
pTmp->pNext = pPager->pNext;
|
||||
}
|
||||
#endif
|
||||
|
||||
sqliteFree(pPager->aHash);
|
||||
sqliteFree(pPager);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -2279,11 +2303,9 @@ static int pager_write_pagelist(PgHdr *pList){
|
||||
** any such pages to the file.
|
||||
*/
|
||||
if( pList->pgno<=pPager->dbSize ){
|
||||
CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
|
||||
char *pData = CODEC2(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
|
||||
TRACE3("STORE %d page %d\n", PAGERID(pPager), pList->pgno);
|
||||
rc = sqlite3OsWrite(pPager->fd, PGHDR_TO_DATA(pList),
|
||||
pPager->pageSize);
|
||||
CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
|
||||
rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize);
|
||||
TEST_INCR(pPager->nWrite);
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
@ -2307,15 +2329,7 @@ static int pager_write_pagelist(PgHdr *pList){
|
||||
** collected even if they are still in use.
|
||||
*/
|
||||
static PgHdr *pager_get_all_dirty_pages(Pager *pPager){
|
||||
PgHdr *p, *pList;
|
||||
pList = 0;
|
||||
for(p=pPager->pAll; p; p=p->pNextAll){
|
||||
if( p->dirty ){
|
||||
p->pDirty = pList;
|
||||
pList = p;
|
||||
}
|
||||
}
|
||||
return pList;
|
||||
return pPager->pDirty;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2390,6 +2404,8 @@ static int pager_recycle(Pager *pPager, int syncOk, PgHdr **ppPg){
|
||||
if( pPg->dirty ){
|
||||
int rc;
|
||||
assert( pPg->needSync==0 );
|
||||
makeClean(pPg);
|
||||
pPg->dirty = 1;
|
||||
pPg->pDirty = 0;
|
||||
rc = pager_write_pagelist( pPg );
|
||||
if( rc!=SQLITE_OK ){
|
||||
@ -2477,7 +2493,7 @@ int sqlite3pager_release_memory(int nReq){
|
||||
if( pPg==p->pAll ){
|
||||
p->pAll = pPg->pNextAll;
|
||||
}else{
|
||||
for( pTmp=p->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll );
|
||||
for( pTmp=p->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ){}
|
||||
pTmp->pNextAll = pPg->pNextAll;
|
||||
}
|
||||
nReleased += sqliteAllocSize(pPg);
|
||||
@ -2629,12 +2645,18 @@ int sqlite3pager_get2(Pager *pPager, Pgno pgno, void **ppPage,
|
||||
}
|
||||
}
|
||||
if( pPg==0 ){
|
||||
//printf("CACHE MISS %d\n", pgno);
|
||||
/* The requested page is not in the page cache. */
|
||||
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) );
|
||||
@ -2676,7 +2698,7 @@ int sqlite3pager_get2(Pager *pPager, Pgno pgno, void **ppPage,
|
||||
}else{
|
||||
page_remove_from_stmt_list(pPg);
|
||||
}
|
||||
pPg->dirty = 0;
|
||||
makeClean(pPg);
|
||||
pPg->nRef = 1;
|
||||
REFINFO(pPg);
|
||||
|
||||
@ -2699,7 +2721,7 @@ int sqlite3pager_get2(Pager *pPager, Pgno pgno, void **ppPage,
|
||||
if (pDataToFill) {
|
||||
/* Just copy from the given memory */
|
||||
memcpy(PGHDR_TO_DATA(pPg), pDataToFill, pPager->pageSize);
|
||||
CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
|
||||
CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
|
||||
} else {
|
||||
/* Load from disk */
|
||||
assert( MEMDB==0 );
|
||||
@ -2709,7 +2731,7 @@ int sqlite3pager_get2(Pager *pPager, Pgno pgno, void **ppPage,
|
||||
pPager->pageSize);
|
||||
}
|
||||
TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||
CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
|
||||
CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
|
||||
if( rc!=SQLITE_OK ){
|
||||
i64 fileSize;
|
||||
int rc2 = sqlite3OsFileSize(pPager->fd, &fileSize);
|
||||
@ -2730,7 +2752,7 @@ int sqlite3pager_get2(Pager *pPager, Pgno pgno, void **ppPage,
|
||||
}
|
||||
|
||||
/* Link the page into the page hash table */
|
||||
h = pager_hash(pgno);
|
||||
h = pgno & (pPager->nHash-1);
|
||||
pPg->pNextHash = pPager->aHash[h];
|
||||
pPager->aHash[h] = pPg;
|
||||
if( pPg->pNextHash ){
|
||||
@ -2742,7 +2764,6 @@ int sqlite3pager_get2(Pager *pPager, Pgno pgno, void **ppPage,
|
||||
pPg->pageHash = pager_pagehash(pPg);
|
||||
#endif
|
||||
}else{
|
||||
//printf("hit %d\n", pgno);
|
||||
/* The requested page is in the page cache. */
|
||||
TEST_INCR(pPager->nHit);
|
||||
page_ref(pPg);
|
||||
@ -2960,6 +2981,42 @@ int sqlite3pager_begin(void *pData, int exFlag){
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** Make a page dirty. Set its dirty flag and add it to the dirty
|
||||
** page list.
|
||||
*/
|
||||
static void makeDirty(PgHdr *pPg){
|
||||
if( pPg->dirty==0 ){
|
||||
Pager *pPager = pPg->pPager;
|
||||
pPg->dirty = 1;
|
||||
pPg->pDirty = pPager->pDirty;
|
||||
if( pPager->pDirty ){
|
||||
pPager->pDirty->pPrevDirty = pPg;
|
||||
}
|
||||
pPg->pPrevDirty = 0;
|
||||
pPager->pDirty = pPg;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Make a page clean. Clear its dirty bit and remove it from the
|
||||
** dirty page list.
|
||||
*/
|
||||
static void makeClean(PgHdr *pPg){
|
||||
if( pPg->dirty ){
|
||||
pPg->dirty = 0;
|
||||
if( pPg->pDirty ){
|
||||
pPg->pDirty->pPrevDirty = pPg->pPrevDirty;
|
||||
}
|
||||
if( pPg->pPrevDirty ){
|
||||
pPg->pPrevDirty->pDirty = pPg->pDirty;
|
||||
}else{
|
||||
pPg->pPager->pDirty = pPg->pDirty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Mark a data page as writeable. The page is written into the journal
|
||||
** if it is not there already. This routine must be called before making
|
||||
@ -2998,7 +3055,7 @@ int sqlite3pager_write(void *pData){
|
||||
/* Mark the page as dirty. If the page has already been written
|
||||
** to the journal then we can return right away.
|
||||
*/
|
||||
pPg->dirty = 1;
|
||||
makeDirty(pPg);
|
||||
if( pPg->inJournal && (pPg->inStmt || pPager->stmtInUse==0) ){
|
||||
pPager->dirtyCache = 1;
|
||||
}else{
|
||||
@ -3030,7 +3087,6 @@ int sqlite3pager_write(void *pData){
|
||||
if( !pPg->inJournal && (pPager->useJournal || MEMDB) ){
|
||||
if( (int)pPg->pgno <= pPager->origDbSize ){
|
||||
int szPg;
|
||||
u32 saved;
|
||||
if( MEMDB ){
|
||||
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
|
||||
TRACE3("JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||
@ -3040,24 +3096,25 @@ int sqlite3pager_write(void *pData){
|
||||
memcpy(pHist->pOrig, PGHDR_TO_DATA(pPg), pPager->pageSize);
|
||||
}
|
||||
}else{
|
||||
u32 cksum;
|
||||
u32 cksum, saved;
|
||||
char *pData2, *pEnd;
|
||||
/* We should never write to the journal file the page that
|
||||
** contains the database locks. The following assert verifies
|
||||
** that we do not. */
|
||||
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
|
||||
CODEC(pPager, pData, pPg->pgno, 7);
|
||||
cksum = pager_cksum(pPager, pPg->pgno, pData);
|
||||
saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
|
||||
store32bits(cksum, pPg, pPager->pageSize);
|
||||
pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
|
||||
cksum = pager_cksum(pPager, (u8*)pData2);
|
||||
pEnd = pData2 + pPager->pageSize;
|
||||
pData2 -= 4;
|
||||
saved = *(u32*)pEnd;
|
||||
put32bits(pEnd, cksum);
|
||||
szPg = pPager->pageSize+8;
|
||||
store32bits(pPg->pgno, pPg, -4);
|
||||
|
||||
rc = sqlite3OsWrite(pPager->jfd, &((char*)pData)[-4], szPg);
|
||||
put32bits(pData2, pPg->pgno);
|
||||
rc = sqlite3OsWrite(pPager->jfd, pData2, szPg);
|
||||
pPager->journalOff += szPg;
|
||||
TRACE4("JOURNAL %d page %d needSync=%d\n",
|
||||
PAGERID(pPager), pPg->pgno, pPg->needSync);
|
||||
CODEC(pPager, pData, pPg->pgno, 0);
|
||||
*(u32*)PGHDR_TO_EXTRA(pPg, pPager) = saved;
|
||||
*(u32*)pEnd = saved;
|
||||
|
||||
/* An error has occured writing to the journal file. The
|
||||
** transaction will be rolled back by the layer above.
|
||||
@ -3102,12 +3159,10 @@ int sqlite3pager_write(void *pData){
|
||||
}
|
||||
TRACE3("STMT-JOURNAL %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||
}else{
|
||||
store32bits(pPg->pgno, pPg, -4);
|
||||
CODEC(pPager, pData, pPg->pgno, 7);
|
||||
rc = sqlite3OsWrite(pPager->stfd,((char*)pData)-4,
|
||||
pPager->pageSize+4);
|
||||
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);
|
||||
CODEC(pPager, pData, pPg->pgno, 0);
|
||||
if( rc!=SQLITE_OK ){
|
||||
return rc;
|
||||
}
|
||||
@ -3193,8 +3248,9 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
|
||||
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 && pPg->dirty && !pPager->stmtInUse ){
|
||||
if( pPg->dirty && !pPager->stmtInUse ){
|
||||
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.
|
||||
@ -3206,7 +3262,7 @@ void sqlite3pager_dont_write(Pager *pPager, Pgno pgno){
|
||||
*/
|
||||
}else{
|
||||
TRACE3("DONT_WRITE page %d of %d\n", pgno, PAGERID(pPager));
|
||||
pPg->dirty = 0;
|
||||
makeClean(pPg);
|
||||
#ifdef SQLITE_CHECK_PAGES
|
||||
pPg->pageHash = pager_pagehash(pPg);
|
||||
#endif
|
||||
@ -3245,20 +3301,6 @@ void sqlite3pager_dont_rollback(void *pData){
|
||||
}
|
||||
|
||||
|
||||
#ifndef SQLITE_OMIT_MEMORYDB
|
||||
/*
|
||||
** Clear a PgHistory block
|
||||
*/
|
||||
static void clearHistory(PgHistory *pHist){
|
||||
sqliteFree(pHist->pOrig);
|
||||
sqliteFree(pHist->pStmt);
|
||||
pHist->pOrig = 0;
|
||||
pHist->pStmt = 0;
|
||||
}
|
||||
#else
|
||||
#define clearHistory(x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Commit all changes to the database and release the write lock.
|
||||
**
|
||||
@ -3284,9 +3326,11 @@ int sqlite3pager_commit(Pager *pPager){
|
||||
pPg->dirty = 0;
|
||||
pPg->inJournal = 0;
|
||||
pPg->inStmt = 0;
|
||||
pPg->needSync = 0;
|
||||
pPg->pPrevStmt = pPg->pNextStmt = 0;
|
||||
pPg = pPg->pDirty;
|
||||
}
|
||||
pPager->pDirty = 0;
|
||||
#ifndef NDEBUG
|
||||
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
|
||||
PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);
|
||||
@ -3354,12 +3398,11 @@ int sqlite3pager_rollback(Pager *pPager){
|
||||
p->inJournal = 0;
|
||||
p->inStmt = 0;
|
||||
p->pPrevStmt = p->pNextStmt = 0;
|
||||
|
||||
if( pPager->xReiniter ){
|
||||
pPager->xReiniter(PGHDR_TO_DATA(p), pPager->pageSize);
|
||||
}
|
||||
|
||||
}
|
||||
pPager->pDirty = 0;
|
||||
pPager->pStmt = 0;
|
||||
pPager->dbSize = pPager->origDbSize;
|
||||
memoryTruncate(pPager);
|
||||
@ -3579,7 +3622,7 @@ int sqlite3pager_nosync(Pager *pPager){
|
||||
*/
|
||||
void sqlite3pager_set_codec(
|
||||
Pager *pPager,
|
||||
void (*xCodec)(void*,void*,Pgno,int),
|
||||
void *(*xCodec)(void*,void*,Pgno,int),
|
||||
void *pCodecArg
|
||||
){
|
||||
pPager->xCodec = xCodec;
|
||||
@ -3608,7 +3651,7 @@ static int pager_incr_changecounter(Pager *pPager){
|
||||
|
||||
/* Increment the value just read and write it back to byte 24. */
|
||||
change_counter++;
|
||||
store32bits(change_counter, pPgHdr, 24);
|
||||
put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
|
||||
|
||||
/* Release the page reference. */
|
||||
sqlite3pager_unref(pPage);
|
||||
@ -3698,6 +3741,8 @@ int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
|
||||
}
|
||||
|
||||
pPager->state = PAGER_SYNCED;
|
||||
}else if( MEMDB && nTrunc!=0 ){
|
||||
rc = sqlite3pager_truncate(pPager, nTrunc);
|
||||
}
|
||||
|
||||
sync_exit:
|
||||
@ -3752,7 +3797,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
|
||||
if( pPgOld ){
|
||||
assert( pPgOld->nRef==0 );
|
||||
unlinkHashChain(pPager, pPgOld);
|
||||
pPgOld->dirty = 0;
|
||||
makeClean(pPgOld);
|
||||
if( pPgOld->needSync ){
|
||||
assert( pPgOld->inJournal );
|
||||
pPg->inJournal = 1;
|
||||
@ -3763,7 +3808,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
|
||||
|
||||
/* Change the page number for pPg and insert it into the new hash-chain. */
|
||||
pPg->pgno = pgno;
|
||||
h = pager_hash(pgno);
|
||||
h = pgno & (pPager->nHash-1);
|
||||
if( pPager->aHash[h] ){
|
||||
assert( pPager->aHash[h]->pPrevHash==0 );
|
||||
pPager->aHash[h]->pPrevHash = pPg;
|
||||
@ -3772,7 +3817,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
|
||||
pPager->aHash[h] = pPg;
|
||||
pPg->pPrevHash = 0;
|
||||
|
||||
pPg->dirty = 1;
|
||||
makeDirty(pPg);
|
||||
pPager->dirtyCache = 1;
|
||||
|
||||
if( needSyncPgno ){
|
||||
@ -3793,7 +3838,7 @@ int sqlite3pager_movepage(Pager *pPager, void *pData, Pgno pgno){
|
||||
pPager->needSync = 1;
|
||||
DATA_TO_PGHDR(pNeedSync)->needSync = 1;
|
||||
DATA_TO_PGHDR(pNeedSync)->inJournal = 1;
|
||||
DATA_TO_PGHDR(pNeedSync)->dirty = 1;
|
||||
makeDirty(DATA_TO_PGHDR(pNeedSync));
|
||||
sqlite3pager_unref(pNeedSync);
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
** subsystem. The page cache subsystem reads and writes a file a page
|
||||
** at a time and provides a journal for rollback.
|
||||
**
|
||||
** @(#) $Id: pager.h,v 1.49 2006/02/11 01:25:51 drh Exp $
|
||||
** @(#) $Id: pager.h,v 1.50 2006/03/06 18:23:17 drh Exp $
|
||||
*/
|
||||
|
||||
#ifndef _PAGER_H_
|
||||
@ -105,7 +105,7 @@ 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*);
|
||||
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);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** This file contains code used to implement the PRAGMA command.
|
||||
**
|
||||
** $Id: pragma.c,v 1.119 2006/02/17 12:25:16 danielk1977 Exp $
|
||||
** $Id: pragma.c,v 1.120 2006/03/03 21:20:17 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -485,7 +485,7 @@ void sqlite3Pragma(
|
||||
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 : "numeric", 0);
|
||||
pCol->zType ? pCol->zType : "", 0);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pCol->notNull, 0);
|
||||
sqlite3ExprCode(pParse, pCol->pDflt);
|
||||
sqlite3VdbeAddOp(v, OP_Integer, pCol->isPrimKey, 0);
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
** interface, and routines that contribute to loading the database schema
|
||||
** from disk.
|
||||
**
|
||||
** $Id: prepare.c,v 1.4 2006-02-22 20:47:51 brettw%gmail.com Exp $
|
||||
** $Id: prepare.c,v 1.5 2006-05-22 17:48:14 brettw%gmail.com Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -74,6 +74,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **azColName){
|
||||
db->init.newTnum = atoi(argv[1]);
|
||||
rc = sqlite3_exec(db, argv[2], 0, 0, &zErr);
|
||||
db->init.iDb = 0;
|
||||
assert( rc!=SQLITE_OK || zErr==0 );
|
||||
if( SQLITE_OK!=rc ){
|
||||
if( rc==SQLITE_NOMEM ){
|
||||
sqlite3FailedMalloc();
|
||||
@ -409,57 +410,6 @@ static int schemaIsValid(sqlite3 *db){
|
||||
return allOk;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free all resources held by the schema structure. The void* argument points
|
||||
** at a Schema struct. This function does not call sqliteFree() on the
|
||||
** pointer itself, it just cleans up subsiduary resources (i.e. the contents
|
||||
** of the schema hash tables).
|
||||
*/
|
||||
void sqlite3SchemaFree(void *p){
|
||||
Hash temp1;
|
||||
Hash temp2;
|
||||
HashElem *pElem;
|
||||
Schema *pSchema = (Schema *)p;
|
||||
|
||||
temp1 = pSchema->tblHash;
|
||||
temp2 = pSchema->trigHash;
|
||||
sqlite3HashInit(&pSchema->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashClear(&pSchema->aFKey);
|
||||
sqlite3HashClear(&pSchema->idxHash);
|
||||
for(pElem=sqliteHashFirst(&temp2); pElem; pElem=sqliteHashNext(pElem)){
|
||||
sqlite3DeleteTrigger((Trigger*)sqliteHashData(pElem));
|
||||
}
|
||||
sqlite3HashClear(&temp2);
|
||||
sqlite3HashInit(&pSchema->tblHash, SQLITE_HASH_STRING, 0);
|
||||
for(pElem=sqliteHashFirst(&temp1); pElem; pElem=sqliteHashNext(pElem)){
|
||||
Table *pTab = sqliteHashData(pElem);
|
||||
sqlite3DeleteTable(0, pTab);
|
||||
}
|
||||
sqlite3HashClear(&temp1);
|
||||
pSchema->pSeqTab = 0;
|
||||
pSchema->flags &= ~DB_SchemaLoaded;
|
||||
}
|
||||
|
||||
/*
|
||||
** Find and return the schema associated with a BTree. Create
|
||||
** a new one if necessary.
|
||||
*/
|
||||
Schema *sqlite3SchemaGet(Btree *pBt){
|
||||
Schema * p;
|
||||
if( pBt ){
|
||||
p = (Schema *)sqlite3BtreeSchema(pBt,sizeof(Schema),sqlite3SchemaFree);
|
||||
}else{
|
||||
p = (Schema *)sqliteMalloc(sizeof(Schema));
|
||||
}
|
||||
if( p && 0==p->file_format ){
|
||||
sqlite3HashInit(&p->tblHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->idxHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->trigHash, SQLITE_HASH_STRING, 0);
|
||||
sqlite3HashInit(&p->aFKey, SQLITE_HASH_STRING, 1);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
** Convert a schema pointer into the iDb index that indicates
|
||||
** which database file in db->aDb[] the schema refers to.
|
||||
|
||||
@ -65,15 +65,14 @@
|
||||
#define etDYNSTRING 7 /* Dynamically allocated strings. %z */
|
||||
#define etPERCENT 8 /* Percent symbol. %% */
|
||||
#define etCHARX 9 /* Characters. %c */
|
||||
#define etERROR 10 /* Used to indicate no such conversion type */
|
||||
/* The rest are extensions, not normally found in printf() */
|
||||
#define etCHARLIT 11 /* Literal characters. %' */
|
||||
#define etSQLESCAPE 12 /* Strings with '\'' doubled. %q */
|
||||
#define etSQLESCAPE2 13 /* Strings with '\'' doubled and enclosed in '',
|
||||
#define etCHARLIT 10 /* Literal characters. %' */
|
||||
#define etSQLESCAPE 11 /* Strings with '\'' doubled. %q */
|
||||
#define etSQLESCAPE2 12 /* Strings with '\'' doubled and enclosed in '',
|
||||
NULL pointers replaced by SQL NULL. %Q */
|
||||
#define etTOKEN 14 /* a pointer to a Token structure */
|
||||
#define etSRCLIST 15 /* a pointer to a SrcList */
|
||||
#define etPOINTER 16 /* The %p conversion */
|
||||
#define etTOKEN 13 /* a pointer to a Token structure */
|
||||
#define etSRCLIST 14 /* a pointer to a SrcList */
|
||||
#define etPOINTER 15 /* The %p conversion */
|
||||
|
||||
|
||||
/*
|
||||
@ -225,7 +224,7 @@ static int vxprintf(
|
||||
etByte flag_long; /* True if "l" flag is present */
|
||||
etByte flag_longlong; /* True if the "ll" flag is present */
|
||||
etByte done; /* Loop termination flag */
|
||||
UINT64_TYPE longvalue; /* Value for integer types */
|
||||
sqlite_uint64 longvalue; /* Value for integer types */
|
||||
LONGDOUBLE_TYPE realvalue; /* Value for real types */
|
||||
const et_info *infop; /* Pointer to the appropriate info structure */
|
||||
char buf[etBUFSIZE]; /* Conversion buffer */
|
||||
@ -329,7 +328,6 @@ static int vxprintf(
|
||||
}
|
||||
/* Fetch the info entry for the field */
|
||||
infop = 0;
|
||||
xtype = etERROR;
|
||||
for(idx=0; idx<etNINFO; idx++){
|
||||
if( c==fmtinfo[idx].fmttype ){
|
||||
infop = &fmtinfo[idx];
|
||||
@ -340,6 +338,10 @@ static int vxprintf(
|
||||
}
|
||||
}
|
||||
zExtra = 0;
|
||||
if( infop==0 ){
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Limit the precision to prevent overflowing buf[] during conversion */
|
||||
if( precision>etBUFSIZE-40 && (infop->flags & FLAG_STRING)==0 ){
|
||||
@ -444,7 +446,7 @@ static int vxprintf(
|
||||
for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
|
||||
#else
|
||||
/* It makes more sense to use 0.5 */
|
||||
for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);
|
||||
for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1){}
|
||||
#endif
|
||||
if( xtype==etFLOAT ) realvalue += rounder;
|
||||
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
|
||||
@ -621,7 +623,8 @@ static int vxprintf(
|
||||
if( needQuote ) bufpt[j++] = '\'';
|
||||
bufpt[j] = 0;
|
||||
length = j;
|
||||
if( precision>=0 && precision<length ) length = precision;
|
||||
/* The precision is ignored on %q and %Q */
|
||||
/* if( precision>=0 && precision<length ) length = precision; */
|
||||
break;
|
||||
}
|
||||
case etTOKEN: {
|
||||
@ -645,15 +648,6 @@ static int vxprintf(
|
||||
length = width = 0;
|
||||
break;
|
||||
}
|
||||
case etERROR:
|
||||
buf[0] = '%';
|
||||
buf[1] = c;
|
||||
errorflag = 0;
|
||||
idx = 1+(c!=0);
|
||||
(*func)(arg,"%",idx);
|
||||
count += idx;
|
||||
if( c==0 ) fmt--;
|
||||
break;
|
||||
}/* End switch over the format type */
|
||||
/*
|
||||
** The text of the conversion is pointed to by "bufpt" and is
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.304 2006/02/10 07:07:16 danielk1977 Exp $
|
||||
** $Id: select.c,v 1.313 2006/04/26 17:39:34 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -411,22 +411,18 @@ static void codeOffset(
|
||||
** seen combinations of the N values. A new entry is made in iTab
|
||||
** if the current N values are new.
|
||||
**
|
||||
** A jump to addrRepeat is made and the K values are popped from the
|
||||
** A jump to addrRepeat is made and the N+1 values are popped from the
|
||||
** stack if the top N elements are not distinct.
|
||||
*/
|
||||
static void codeDistinct(
|
||||
Vdbe *v, /* Generate code into this VM */
|
||||
int iTab, /* A sorting index used to test for distinctness */
|
||||
int addrRepeat, /* Jump to here if not distinct */
|
||||
int N, /* The top N elements of the stack must be distinct */
|
||||
int K /* Pop K elements from the stack if indistinct */
|
||||
int N /* The top N elements of the stack must be distinct */
|
||||
){
|
||||
#if NULL_ALWAYS_DISTINCT
|
||||
sqlite3VdbeAddOp(v, OP_IsNull, -N, sqlite3VdbeCurrentAddr(v)+6);
|
||||
#endif
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, -N, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, K, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pop, N+1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Goto, 0, addrRepeat);
|
||||
VdbeComment((v, "# skip indistinct records"));
|
||||
sqlite3VdbeAddOp(v, OP_IdxInsert, iTab, 0);
|
||||
@ -487,8 +483,9 @@ static int selectInnerLoop(
|
||||
** part of the result.
|
||||
*/
|
||||
if( hasDistinct ){
|
||||
int n = pEList->nExpr;
|
||||
codeDistinct(v, distinct, iContinue, n, n+1);
|
||||
assert( pEList!=0 );
|
||||
assert( pEList->nExpr==nColumn );
|
||||
codeDistinct(v, distinct, iContinue, nColumn);
|
||||
if( pOrderBy==0 ){
|
||||
codeOffset(v, p, iContinue, nColumn);
|
||||
}
|
||||
@ -500,7 +497,7 @@ static int selectInnerLoop(
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_COMPOUND_SELECT
|
||||
case SRT_Union: {
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
|
||||
sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
|
||||
if( aff ){
|
||||
sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
|
||||
}
|
||||
@ -514,7 +511,7 @@ static int selectInnerLoop(
|
||||
*/
|
||||
case SRT_Except: {
|
||||
int addr;
|
||||
addr = sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT);
|
||||
addr = sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0);
|
||||
sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC);
|
||||
sqlite3VdbeAddOp(v, OP_NotFound, iParm, addr+3);
|
||||
sqlite3VdbeAddOp(v, OP_Delete, iParm, 0);
|
||||
@ -680,7 +677,7 @@ static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
|
||||
** routine generates the code needed to do that.
|
||||
*/
|
||||
static void generateSortTail(
|
||||
Parse *pParse, /* The parsing context */
|
||||
Parse *pParse, /* Parsing context */
|
||||
Select *p, /* The SELECT statement */
|
||||
Vdbe *v, /* Generate code into this VDBE */
|
||||
int nColumn, /* Number of columns of data */
|
||||
@ -691,11 +688,20 @@ static void generateSortTail(
|
||||
int cont = sqlite3VdbeMakeLabel(v);
|
||||
int addr;
|
||||
int iTab;
|
||||
int pseudoTab;
|
||||
ExprList *pOrderBy = p->pOrderBy;
|
||||
|
||||
iTab = pOrderBy->iECursor;
|
||||
if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
|
||||
pseudoTab = pParse->nTab++;
|
||||
sqlite3VdbeAddOp(v, OP_OpenPseudo, pseudoTab, 0);
|
||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, pseudoTab, nColumn);
|
||||
}
|
||||
addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk);
|
||||
codeOffset(v, p, cont, 0);
|
||||
if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1);
|
||||
switch( eDest ){
|
||||
case SRT_Table:
|
||||
@ -725,17 +731,15 @@ static void generateSortTail(
|
||||
case SRT_Callback:
|
||||
case SRT_Subroutine: {
|
||||
int i;
|
||||
sqlite3VdbeAddOp(v, OP_Integer, p->pEList->nExpr, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Pull, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Insert, pseudoTab, 0);
|
||||
for(i=0; i<nColumn; i++){
|
||||
sqlite3VdbeAddOp(v, OP_Column, -1-i, i);
|
||||
sqlite3VdbeAddOp(v, OP_Column, pseudoTab, i);
|
||||
}
|
||||
if( eDest==SRT_Callback ){
|
||||
sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Pop, 2, 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -756,6 +760,10 @@ static void generateSortTail(
|
||||
sqlite3VdbeResolveLabel(v, cont);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iTab, addr);
|
||||
sqlite3VdbeResolveLabel(v, brk);
|
||||
if( eDest==SRT_Callback || eDest==SRT_Subroutine ){
|
||||
sqlite3VdbeAddOp(v, OP_Close, pseudoTab, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@ -797,6 +805,7 @@ static const char *columnType(
|
||||
assert( pExpr->op!=TK_AS );
|
||||
|
||||
switch( pExpr->op ){
|
||||
case TK_AGG_COLUMN:
|
||||
case TK_COLUMN: {
|
||||
/* The expression is a column. Locate the table the column is being
|
||||
** extracted from in NameContext.pSrcList. This table may be real
|
||||
@ -1039,6 +1048,7 @@ Table *sqlite3ResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
|
||||
ExprList *pEList;
|
||||
Column *aCol, *pCol;
|
||||
|
||||
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
|
||||
if( prepSelectStmt(pParse, pSelect) ){
|
||||
return 0;
|
||||
}
|
||||
@ -1535,20 +1545,6 @@ static void createSortingIndex(Parse *pParse, Select *p, ExprList *pOrderBy){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The opcode at addr is an OP_OpenVirtual that created a sorting
|
||||
** index tha we ended up not needing. This routine changes that
|
||||
** opcode to OP_Noop.
|
||||
*/
|
||||
static void uncreateSortingIndex(Parse *pParse, int addr){
|
||||
Vdbe *v = pParse->pVdbe;
|
||||
VdbeOp *pOp = sqlite3VdbeGetOp(v, addr);
|
||||
sqlite3VdbeChangeP3(v, addr, 0, 0);
|
||||
pOp->opcode = OP_Noop;
|
||||
pOp->p1 = 0;
|
||||
pOp->p2 = 0;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_COMPOUND_SELECT
|
||||
/*
|
||||
** Return the appropriate collating sequence for the iCol-th column of
|
||||
@ -1771,7 +1767,9 @@ static int multiSelect(
|
||||
int iCont, iBreak, iStart;
|
||||
assert( p->pEList );
|
||||
if( eDest==SRT_Callback ){
|
||||
generateColumnNames(pParse, 0, p->pEList);
|
||||
Select *pFirst = p;
|
||||
while( pFirst->pPrior ) pFirst = pFirst->pPrior;
|
||||
generateColumnNames(pParse, 0, pFirst->pEList);
|
||||
}
|
||||
iBreak = sqlite3VdbeMakeLabel(v);
|
||||
iCont = sqlite3VdbeMakeLabel(v);
|
||||
@ -1847,7 +1845,9 @@ static int multiSelect(
|
||||
*/
|
||||
assert( p->pEList );
|
||||
if( eDest==SRT_Callback ){
|
||||
generateColumnNames(pParse, 0, p->pEList);
|
||||
Select *pFirst = p;
|
||||
while( pFirst->pPrior ) pFirst = pFirst->pPrior;
|
||||
generateColumnNames(pParse, 0, pFirst->pEList);
|
||||
}
|
||||
iBreak = sqlite3VdbeMakeLabel(v);
|
||||
iCont = sqlite3VdbeMakeLabel(v);
|
||||
@ -2117,7 +2117,6 @@ static void substSelect(Select *p, int iTable, ExprList *pEList){
|
||||
** the subquery before this routine runs.
|
||||
*/
|
||||
static int flattenSubquery(
|
||||
Parse *pParse, /* The parsing context */
|
||||
Select *p, /* The parent or outer SELECT statement */
|
||||
int iFrom, /* Index in p->pSrc->a[] of the inner subquery */
|
||||
int isAgg, /* True if outer SELECT uses aggregate functions */
|
||||
@ -2245,7 +2244,6 @@ static int flattenSubquery(
|
||||
** We look at every expression in the outer query and every place we see
|
||||
** "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
|
||||
*/
|
||||
substExprList(p->pEList, iParent, pSub->pEList);
|
||||
pList = p->pEList;
|
||||
for(i=0; i<pList->nExpr; i++){
|
||||
Expr *pExpr;
|
||||
@ -2253,6 +2251,7 @@ static int flattenSubquery(
|
||||
pList->a[i].zName = sqliteStrNDup((char*)pExpr->span.z, pExpr->span.n);
|
||||
}
|
||||
}
|
||||
substExprList(p->pEList, iParent, pSub->pEList);
|
||||
if( isAgg ){
|
||||
substExprList(p->pGroupBy, iParent, pSub->pEList);
|
||||
substExpr(p->pHaving, iParent, pSub->pEList);
|
||||
@ -2487,11 +2486,6 @@ static int processOrderGroupBy(
|
||||
if( sqlite3ExprResolveNames(pNC, pE) ){
|
||||
return 1;
|
||||
}
|
||||
if( sqlite3ExprIsConstant(pE) ){
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"%s BY terms must not be non-integer constants", zType);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -2683,13 +2677,14 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
|
||||
if( pF->iDistinct>=0 ){
|
||||
addrNext = sqlite3VdbeMakeLabel(v);
|
||||
assert( nArg==1 );
|
||||
codeDistinct(v, pF->iDistinct, addrNext, 1, 2);
|
||||
codeDistinct(v, pF->iDistinct, addrNext, 1);
|
||||
}
|
||||
if( pF->pFunc->needCollSeq ){
|
||||
CollSeq *pColl = 0;
|
||||
struct ExprList_item *pItem;
|
||||
int j;
|
||||
for(j=0, pItem=pList->a; !pColl && j<pList->nExpr; j++, pItem++){
|
||||
assert( pList!=0 ); /* pList!=0 if pF->pFunc->needCollSeq is true */
|
||||
for(j=0, pItem=pList->a; !pColl && j<nArg; j++, pItem++){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
|
||||
}
|
||||
if( !pColl ){
|
||||
@ -2902,7 +2897,7 @@ int sqlite3Select(
|
||||
*/
|
||||
#ifndef SQLITE_OMIT_VIEW
|
||||
if( pParent && pParentAgg &&
|
||||
flattenSubquery(pParse, pParent, parentTab, *pParentAgg, isAgg) ){
|
||||
flattenSubquery(pParent, parentTab, *pParentAgg, isAgg) ){
|
||||
if( isAgg ) *pParentAgg = 1;
|
||||
goto select_end;
|
||||
}
|
||||
@ -2937,17 +2932,17 @@ int sqlite3Select(
|
||||
addrSortIndex = -1;
|
||||
}
|
||||
|
||||
/* Set the limiter.
|
||||
*/
|
||||
iEnd = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, iEnd);
|
||||
|
||||
/* If the output is destined for a temporary table, open that table.
|
||||
*/
|
||||
if( eDest==SRT_VirtualTab ){
|
||||
sqlite3VdbeAddOp(v, OP_OpenVirtual, iParm, pEList->nExpr);
|
||||
}
|
||||
|
||||
/* Set the limiter.
|
||||
*/
|
||||
iEnd = sqlite3VdbeMakeLabel(v);
|
||||
computeLimitRegisters(pParse, p, iEnd);
|
||||
|
||||
/* Open a virtual index to use for the distinct set.
|
||||
*/
|
||||
if( isDistinct ){
|
||||
@ -2973,7 +2968,7 @@ int sqlite3Select(
|
||||
** into an OP_Noop.
|
||||
*/
|
||||
if( addrSortIndex>=0 && pOrderBy==0 ){
|
||||
uncreateSortingIndex(pParse, addrSortIndex);
|
||||
sqlite3VdbeChangeToNoop(v, addrSortIndex, 1);
|
||||
p->addrOpenVirt[2] = -1;
|
||||
}
|
||||
|
||||
@ -3219,7 +3214,7 @@ int sqlite3Select(
|
||||
sqlite3VdbeAddOp(v, OP_Next, sAggInfo.sortingIdx, addrTopOfLoop);
|
||||
}else{
|
||||
sqlite3WhereEnd(pWInfo);
|
||||
uncreateSortingIndex(pParse, addrSortingIdx);
|
||||
sqlite3VdbeChangeToNoop(v, addrSortingIdx, 1);
|
||||
}
|
||||
|
||||
/* Output the final row of result
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This file contains code to implement the "sqlite" command line
|
||||
** utility for accessing SQLite databases.
|
||||
**
|
||||
** $Id: shell.c,v 1.133 2006/01/31 19:31:44 drh Exp $
|
||||
** $Id: shell.c,v 1.136 2006/05/10 14:39:14 drh Exp $
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -62,7 +62,7 @@ static sqlite3 *db = 0;
|
||||
/*
|
||||
** True if an interrupt (Control-C) has been received.
|
||||
*/
|
||||
static int seenInterrupt = 0;
|
||||
static volatile int seenInterrupt = 0;
|
||||
|
||||
/*
|
||||
** This is the name of our program. It is set in main(), used
|
||||
@ -1074,7 +1074,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
return 0;
|
||||
}
|
||||
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
|
||||
if( azCol==0 ) return 0;
|
||||
if( azCol==0 ){
|
||||
fclose(in);
|
||||
return 0;
|
||||
}
|
||||
sqlite3_exec(p->db, "BEGIN", 0, 0, 0);
|
||||
zCommit = "COMMIT";
|
||||
while( (zLine = local_getline(0, in))!=0 ){
|
||||
@ -1371,6 +1374,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||
|
||||
if( c=='w' && strncmp(azArg[0], "width", n)==0 ){
|
||||
int j;
|
||||
assert( nArg<=ArraySize(azArg) );
|
||||
for(j=1; j<nArg && j<ArraySize(p->colWidth); j++){
|
||||
p->colWidth[j-1] = atoi(azArg[j]);
|
||||
}
|
||||
@ -1467,6 +1471,10 @@ static void process_input(struct callback_data *p, FILE *in){
|
||||
if( zLine[i]!=0 ){
|
||||
nSql = strlen(zLine);
|
||||
zSql = malloc( nSql+1 );
|
||||
if( zSql==0 ){
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
strcpy(zSql, zLine);
|
||||
}
|
||||
}else{
|
||||
@ -1486,7 +1494,7 @@ 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);
|
||||
/* if( in!=0 && !p->echoOn ) printf("%s\n",zSql); */
|
||||
if( zErrMsg!=0 ){
|
||||
printf("SQL error: %s\n", zErrMsg);
|
||||
sqlite3_free(zErrMsg);
|
||||
@ -1560,7 +1568,7 @@ static void process_sqliterc(
|
||||
){
|
||||
char *home_dir = NULL;
|
||||
const char *sqliterc = sqliterc_override;
|
||||
char *zBuf;
|
||||
char *zBuf = 0;
|
||||
FILE *in = NULL;
|
||||
|
||||
if (sqliterc == NULL) {
|
||||
@ -1586,6 +1594,7 @@ static void process_sqliterc(
|
||||
process_input(p,in);
|
||||
fclose(in);
|
||||
}
|
||||
free(zBuf);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This header file defines the interface that the SQLite library
|
||||
** presents to client programs.
|
||||
**
|
||||
** @(#) $Id: sqlite3.h,v 1.4 2006/02/22 20:47:51 brettw%gmail.com Exp $
|
||||
** @(#) $Id: sqlite.h.in,v 1.165 2006/04/04 01:54:55 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE3_H_
|
||||
#define _SQLITE3_H_
|
||||
@ -31,7 +31,7 @@ extern "C" {
|
||||
#ifdef SQLITE_VERSION
|
||||
# undef SQLITE_VERSION
|
||||
#endif
|
||||
#define SQLITE_VERSION "3.3.4"
|
||||
#define SQLITE_VERSION "3.3.5"
|
||||
|
||||
/*
|
||||
** The format of the version string is "X.Y.Z<trailing string>", where
|
||||
@ -48,7 +48,7 @@ extern "C" {
|
||||
#ifdef SQLITE_VERSION_NUMBER
|
||||
# undef SQLITE_VERSION_NUMBER
|
||||
#endif
|
||||
#define SQLITE_VERSION_NUMBER 3003004
|
||||
#define SQLITE_VERSION_NUMBER 3003005
|
||||
|
||||
/*
|
||||
** The version string is also compiled into the library so that a program
|
||||
@ -78,7 +78,10 @@ typedef struct sqlite3 sqlite3;
|
||||
** to do a typedef that for 64-bit integers that depends on what compiler
|
||||
** is being used.
|
||||
*/
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#ifdef SQLITE_INT64_TYPE
|
||||
typedef SQLITE_INT64_TYPE sqlite_int64;
|
||||
typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
|
||||
#elif defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
typedef __int64 sqlite_int64;
|
||||
typedef unsigned __int64 sqlite_uint64;
|
||||
#else
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** Internal interface definitions for SQLite.
|
||||
**
|
||||
** @(#) $Id: sqliteInt.h,v 1.486 2006/02/17 15:01:36 danielk1977 Exp $
|
||||
** @(#) $Id: sqliteInt.h,v 1.493 2006/04/04 01:54:55 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITEINT_H_
|
||||
#define _SQLITEINT_H_
|
||||
@ -112,18 +112,6 @@
|
||||
#define OMIT_TEMPDB 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
** If the following macro is set to 1, then NULL values are considered
|
||||
** distinct for the SELECT DISTINCT statement and for UNION or EXCEPT
|
||||
** compound queries. No other SQL database engine (among those tested)
|
||||
** works this way except for OCELOT. But the SQL92 spec implies that
|
||||
** this is how things should work.
|
||||
**
|
||||
** If the following macro is set to 0, then NULLs are indistinct for
|
||||
** SELECT DISTINCT and for UNION.
|
||||
*/
|
||||
#define NULL_ALWAYS_DISTINCT 0
|
||||
|
||||
/*
|
||||
** If the following macro is set to 1, then NULL values are considered
|
||||
** distinct when determining whether or not two entries are the same
|
||||
@ -179,6 +167,16 @@
|
||||
#define offsetof(STRUCTURE,FIELD) ((int)((char*)&((STRUCTURE*)0)->FIELD))
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Check to see if this machine uses EBCDIC. (Yes, believe it or
|
||||
** not, there are still machines out there that use EBCDIC.)
|
||||
*/
|
||||
#if 'A' == '\301'
|
||||
# define SQLITE_EBCDIC 1
|
||||
#else
|
||||
# define SQLITE_ASCII 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Integers of known sizes. These typedefs might change for architectures
|
||||
** where the sizes very. Preprocessor macros are available so that the
|
||||
@ -186,13 +184,6 @@
|
||||
**
|
||||
** cc '-DUINTPTR_TYPE=long long int' ...
|
||||
*/
|
||||
#ifndef UINT64_TYPE
|
||||
# if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
# define UINT64_TYPE unsigned __int64
|
||||
# else
|
||||
# define UINT64_TYPE unsigned long long int
|
||||
# endif
|
||||
#endif
|
||||
#ifndef UINT32_TYPE
|
||||
# define UINT32_TYPE unsigned int
|
||||
#endif
|
||||
@ -212,7 +203,7 @@
|
||||
# define LONGDOUBLE_TYPE long double
|
||||
#endif
|
||||
typedef sqlite_int64 i64; /* 8-byte signed integer */
|
||||
typedef UINT64_TYPE u64; /* 8-byte unsigned integer */
|
||||
typedef sqlite_uint64 u64; /* 8-byte unsigned integer */
|
||||
typedef UINT32_TYPE u32; /* 4-byte unsigned integer */
|
||||
typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
|
||||
typedef INT16_TYPE i16; /* 2-byte signed integer */
|
||||
@ -510,6 +501,9 @@ struct sqlite3 {
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
** A macro to discover the encoding of a database.
|
||||
*/
|
||||
#define ENC(db) ((db)->aDb[0].pSchema->enc)
|
||||
|
||||
/*
|
||||
@ -1383,8 +1377,8 @@ struct TriggerStep {
|
||||
ExprList *pExprList; /* Valid for UPDATE statements and sometimes
|
||||
INSERT steps (when pSelect == 0) */
|
||||
IdList *pIdList; /* Valid for INSERT statements only */
|
||||
|
||||
TriggerStep * pNext; /* Next in the link-list */
|
||||
TriggerStep *pNext; /* Next in the link-list */
|
||||
TriggerStep *pLast; /* Last element in link-list. Valid for 1st elem only */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -1519,7 +1513,7 @@ void sqlite3RollbackInternalChanges(sqlite3*);
|
||||
void sqlite3CommitInternalChanges(sqlite3*);
|
||||
Table *sqlite3ResultSetOfSelect(Parse*,char*,Select*);
|
||||
void sqlite3OpenMasterTable(Parse *, int);
|
||||
void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int,int);
|
||||
void sqlite3StartTable(Parse*,Token*,Token*,int,int,int);
|
||||
void sqlite3AddColumn(Parse*,Token*);
|
||||
void sqlite3AddNotNull(Parse*, int);
|
||||
void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int, int);
|
||||
@ -1575,7 +1569,7 @@ Table *sqlite3LocateTable(Parse*,const char*, const char*);
|
||||
Index *sqlite3FindIndex(sqlite3*,const char*, const char*);
|
||||
void sqlite3UnlinkAndDeleteTable(sqlite3*,int,const char*);
|
||||
void sqlite3UnlinkAndDeleteIndex(sqlite3*,int,const char*);
|
||||
void sqlite3Vacuum(Parse*, Token*);
|
||||
void sqlite3Vacuum(Parse*);
|
||||
int sqlite3RunVacuum(char**, sqlite3*);
|
||||
char *sqlite3NameFromToken(Token*);
|
||||
int sqlite3ExprCheck(Parse*, Expr*, int, int*);
|
||||
@ -1596,7 +1590,7 @@ int sqlite3ExprIsConstantOrFunction(Expr*);
|
||||
int sqlite3ExprIsInteger(Expr*, int*);
|
||||
int sqlite3IsRowid(const char*);
|
||||
void sqlite3GenerateRowDelete(sqlite3*, Vdbe*, Table*, int, int);
|
||||
void sqlite3GenerateRowIndexDelete(sqlite3*, Vdbe*, Table*, int, char*);
|
||||
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);
|
||||
@ -1621,7 +1615,7 @@ void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
|
||||
int,Expr*,int);
|
||||
void sqlite3FinishTrigger(Parse*, TriggerStep*, Token*);
|
||||
void sqlite3DropTrigger(Parse*, SrcList*);
|
||||
void sqlite3DropTriggerPtr(Parse*, Trigger*, int);
|
||||
void sqlite3DropTriggerPtr(Parse*, Trigger*);
|
||||
int sqlite3TriggersExist(Parse*, Table*, int, ExprList*);
|
||||
int sqlite3CodeRowTrigger(Parse*, int, ExprList*, int, Table *, int, int,
|
||||
int, int);
|
||||
@ -1636,7 +1630,7 @@ void sqlite3ChangeCookie(sqlite3*, Vdbe*, int);
|
||||
#else
|
||||
# define sqlite3TriggersExist(A,B,C,D,E,F) 0
|
||||
# define sqlite3DeleteTrigger(A)
|
||||
# define sqlite3DropTriggerPtr(A,B,C)
|
||||
# define sqlite3DropTriggerPtr(A,B)
|
||||
# define sqlite3UnlinkAndDeleteTrigger(A,B,C)
|
||||
# define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I) 0
|
||||
#endif
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
*************************************************************************
|
||||
** A TCL Interface to SQLite
|
||||
**
|
||||
** $Id: tclsqlite.c,v 1.151 2006/02/10 02:27:43 danielk1977 Exp $
|
||||
** $Id: tclsqlite.c,v 1.156 2006/05/10 14:39:14 drh Exp $
|
||||
*/
|
||||
#ifndef NO_TCL /* Omit this whole file if TCL is unavailable */
|
||||
|
||||
@ -23,15 +23,6 @@
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
* Windows needs to know which symbols to export. Unix does not.
|
||||
* BUILD_sqlite should be undefined for Unix.
|
||||
*/
|
||||
|
||||
#ifdef BUILD_sqlite
|
||||
#undef TCL_STORAGE_CLASS
|
||||
#define TCL_STORAGE_CLASS DLLEXPORT
|
||||
#endif /* BUILD_sqlite */
|
||||
|
||||
#define NUM_PREPARED_STMTS 10
|
||||
#define MAX_PREPARED_STMTS 100
|
||||
@ -1094,9 +1085,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
|
||||
if( azCol==0 ) {
|
||||
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
|
||||
fclose(in);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
|
||||
(void)sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
|
||||
zCommit = "COMMIT";
|
||||
while( (zLine = local_getline(0, in))!=0 ){
|
||||
char *z;
|
||||
@ -1116,11 +1108,13 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
if( i+1!=nCol ){
|
||||
char *zErr;
|
||||
zErr = malloc(200 + strlen(zFile));
|
||||
sprintf(zErr,
|
||||
"Error: %s line %d: expected %d columns of data but found %d",
|
||||
zFile, lineno, nCol, i+1);
|
||||
Tcl_AppendResult(interp, zErr, 0);
|
||||
free(zErr);
|
||||
if( zErr ){
|
||||
sprintf(zErr,
|
||||
"Error: %s line %d: expected %d columns of data but found %d",
|
||||
zFile, lineno, nCol, i+1);
|
||||
Tcl_AppendResult(interp, zErr, 0);
|
||||
free(zErr);
|
||||
}
|
||||
zCommit = "ROLLBACK";
|
||||
break;
|
||||
}
|
||||
@ -1144,7 +1138,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
free(azCol);
|
||||
fclose(in);
|
||||
sqlite3_finalize(pStmt);
|
||||
sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
|
||||
(void)sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
|
||||
|
||||
if( zCommit[0] == 'C' ){
|
||||
/* success, set result as number of lines processed */
|
||||
@ -1855,7 +1849,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
}
|
||||
inTrans = !sqlite3_get_autocommit(pDb->db);
|
||||
if( !inTrans ){
|
||||
sqlite3_exec(pDb->db, zBegin, 0, 0, 0);
|
||||
(void)sqlite3_exec(pDb->db, zBegin, 0, 0, 0);
|
||||
}
|
||||
rc = Tcl_EvalObjEx(interp, pScript, 0);
|
||||
if( !inTrans ){
|
||||
@ -1865,7 +1859,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
} else {
|
||||
zEnd = "COMMIT";
|
||||
}
|
||||
sqlite3_exec(pDb->db, zEnd, 0, 0, 0);
|
||||
(void)sqlite3_exec(pDb->db, zEnd, 0, 0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2078,7 +2072,7 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||
** used to open a new SQLite database. See the DbMain() routine above
|
||||
** for additional information.
|
||||
*/
|
||||
EXTERN int Sqlite3_Init(Tcl_Interp *interp){
|
||||
extern int Sqlite3_Init(Tcl_Interp *interp){
|
||||
Tcl_InitStubs(interp, "8.4", 0);
|
||||
Tcl_CreateObjCommand(interp, "sqlite3", (Tcl_ObjCmdProc*)DbMain, 0, 0);
|
||||
Tcl_PkgProvide(interp, "sqlite3", PACKAGE_VERSION);
|
||||
@ -2086,15 +2080,15 @@ EXTERN int Sqlite3_Init(Tcl_Interp *interp){
|
||||
Tcl_PkgProvide(interp, "sqlite", PACKAGE_VERSION);
|
||||
return TCL_OK;
|
||||
}
|
||||
EXTERN int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
EXTERN int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
EXTERN int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
extern int Tclsqlite3_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
extern int Sqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
extern int Tclsqlite3_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
|
||||
#ifndef SQLITE_3_SUFFIX_ONLY
|
||||
EXTERN int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
EXTERN int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
EXTERN int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
EXTERN int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
extern int Sqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
extern int Tclsqlite_Init(Tcl_Interp *interp){ return Sqlite3_Init(interp); }
|
||||
extern int Sqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
extern int Tclsqlite_SafeInit(Tcl_Interp *interp){ return TCL_OK; }
|
||||
#endif
|
||||
|
||||
#ifdef TCLSH
|
||||
|
||||
@ -200,7 +200,7 @@
|
||||
** Only compile the code in this file on UNIX with a THREADSAFE build
|
||||
** and only if the SQLITE_SERVER macro is defined.
|
||||
*/
|
||||
#ifdef SQLITE_SERVER
|
||||
#if defined(SQLITE_SERVER) && !defined(SQLITE_OMIT_SHARED_CACHE)
|
||||
#if defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE
|
||||
|
||||
/*
|
||||
|
||||
@ -15,13 +15,46 @@
|
||||
** individual tokens and sends those tokens one-by-one over to the
|
||||
** parser for analysis.
|
||||
**
|
||||
** $Id: tokenize.c,v 1.117 2006/02/09 22:24:41 drh Exp $
|
||||
** $Id: tokenize.c,v 1.118 2006/04/04 01:54:55 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
** The charMap() macro maps alphabetic characters into their
|
||||
** lower-case ASCII equivalent. On ASCII machines, this is just
|
||||
** an upper-to-lower case map. On EBCDIC machines we also need
|
||||
** to adjust the encoding. Only alphabetic characters and underscores
|
||||
** need to be translated.
|
||||
*/
|
||||
#ifdef SQLITE_ASCII
|
||||
# define charMap(X) sqlite3UpperToLower[(unsigned char)X]
|
||||
#endif
|
||||
#ifdef SQLITE_EBCDIC
|
||||
# define charMap(X) ebcdicToAscii[(unsigned char)X]
|
||||
const unsigned char ebcdicToAscii[] = {
|
||||
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 3x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 4x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 5x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, /* 6x */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 7x */
|
||||
0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* 8x */
|
||||
0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* 9x */
|
||||
0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ax */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */
|
||||
0, 97, 98, 99,100,101,102,103,104,105, 0, 0, 0, 0, 0, 0, /* Cx */
|
||||
0,106,107,108,109,110,111,112,113,114, 0, 0, 0, 0, 0, 0, /* Dx */
|
||||
0, 0,115,116,117,118,119,120,121,122, 0, 0, 0, 0, 0, 0, /* Ex */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Fx */
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
** The sqlite3KeywordCode function looks up an identifier to determine if
|
||||
** it is a keyword. If it is a keyword, the token code of that keyword is
|
||||
@ -37,24 +70,22 @@
|
||||
|
||||
|
||||
/*
|
||||
** If X is a character that can be used in an identifier and
|
||||
** X&0x80==0 then sqlite3IsIdChar[X] will be 1. If X&0x80==0x80 then
|
||||
** X is always an identifier character. (Hence all UTF-8
|
||||
** characters can be part of an identifier). sqlite3IsIdChar[X] will
|
||||
** be 0 for every character in the lower 128 ASCII characters
|
||||
** that cannot be used as part of an identifier.
|
||||
** If X is a character that can be used in an identifier then
|
||||
** IdChar(X) will be true. Otherwise it is false.
|
||||
**
|
||||
** In this implementation, an identifier can be a string of
|
||||
** alphabetic characters, digits, and "_" plus any character
|
||||
** with the high-order bit set. The latter rule means that
|
||||
** any sequence of UTF-8 characters or characters taken from
|
||||
** an extended ISO8859 character set can form an identifier.
|
||||
** For ASCII, any character with the high-order bit set is
|
||||
** allowed in an identifier. For 7-bit characters,
|
||||
** sqlite3IsIdChar[X] must be 1.
|
||||
**
|
||||
** For EBCDIC, the rules are more complex but have the same
|
||||
** end result.
|
||||
**
|
||||
** Ticket #1066. the SQL standard does not allow '$' in the
|
||||
** middle of identfiers. But many SQL implementations do.
|
||||
** SQLite will allow '$' in identifiers for compatibility.
|
||||
** But the feature is undocumented.
|
||||
*/
|
||||
#ifdef SQLITE_ASCII
|
||||
const char sqlite3IsIdChar[] = {
|
||||
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
|
||||
0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */
|
||||
@ -64,8 +95,27 @@ const char sqlite3IsIdChar[] = {
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */
|
||||
};
|
||||
|
||||
#define IdChar(C) (((c=C)&0x80)!=0 || (c>0x1f && sqlite3IsIdChar[c-0x20]))
|
||||
#endif
|
||||
#ifdef SQLITE_EBCDIC
|
||||
const char sqlite3IsIdChar[] = {
|
||||
/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 4x */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, /* 5x */
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, /* 6x */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, /* 7x */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, /* 8x */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, /* 9x */
|
||||
1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, /* Ax */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* Bx */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Cx */
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Dx */
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, /* Ex */
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, /* Fx */
|
||||
};
|
||||
#define IdChar(C) (((c=C)>=0x42 && sqlite3IsIdChar[c-0x40]))
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
** Return the length of the token that begins at z[0].
|
||||
|
||||
@ -60,9 +60,11 @@ void sqlite3BeginTrigger(
|
||||
DbFixer sFix;
|
||||
int iTabDb;
|
||||
|
||||
assert( pName1!=0 ); /* pName1->z might be NULL, but not pName1 itself */
|
||||
assert( pName2!=0 );
|
||||
if( isTemp ){
|
||||
/* If TEMP was specified, then the trigger name may not be qualified. */
|
||||
if( pName2 && pName2->n>0 ){
|
||||
if( pName2->n>0 ){
|
||||
sqlite3ErrorMsg(pParse, "temporary trigger may not have qualified name");
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
@ -108,7 +110,7 @@ void sqlite3BeginTrigger(
|
||||
if( !zName || SQLITE_OK!=sqlite3CheckObjectName(pParse, zName) ){
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,pName->n+1) ){
|
||||
if( sqlite3HashFind(&(db->aDb[iDb].pSchema->trigHash), zName,strlen(zName)) ){
|
||||
sqlite3ErrorMsg(pParse, "trigger %T already exists", pName);
|
||||
goto trigger_cleanup;
|
||||
}
|
||||
@ -255,7 +257,7 @@ void sqlite3FinishTrigger(
|
||||
Table *pTab;
|
||||
Trigger *pDel;
|
||||
pDel = sqlite3HashInsert(&db->aDb[iDb].pSchema->trigHash,
|
||||
pTrig->name, strlen(pTrig->name)+1, pTrig);
|
||||
pTrig->name, strlen(pTrig->name), pTrig);
|
||||
if( pDel ){
|
||||
assert( sqlite3MallocFailed() && pDel==pTrig );
|
||||
goto triggerfinish_cleanup;
|
||||
@ -453,14 +455,14 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){
|
||||
for(i=OMIT_TEMPDB; i<db->nDb; i++){
|
||||
int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */
|
||||
if( zDb && sqlite3StrICmp(db->aDb[j].zName, zDb) ) continue;
|
||||
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName+1);
|
||||
pTrigger = sqlite3HashFind(&(db->aDb[j].pSchema->trigHash), zName, nName);
|
||||
if( pTrigger ) break;
|
||||
}
|
||||
if( !pTrigger ){
|
||||
sqlite3ErrorMsg(pParse, "no such trigger: %S", pName, 0);
|
||||
goto drop_trigger_cleanup;
|
||||
}
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger, 0);
|
||||
sqlite3DropTriggerPtr(pParse, pTrigger);
|
||||
|
||||
drop_trigger_cleanup:
|
||||
sqlite3SrcListDelete(pName);
|
||||
@ -470,18 +472,16 @@ drop_trigger_cleanup:
|
||||
** Return a pointer to the Table structure for the table that a trigger
|
||||
** is set on.
|
||||
*/
|
||||
static Table *tableOfTrigger(sqlite3 *db, Trigger *pTrigger){
|
||||
static Table *tableOfTrigger(Trigger *pTrigger){
|
||||
int n = strlen(pTrigger->table) + 1;
|
||||
return sqlite3HashFind(&pTrigger->pTabSchema->tblHash, pTrigger->table, n);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Drop a trigger given a pointer to that trigger. If nested is false,
|
||||
** then also generate code to remove the trigger from the SQLITE_MASTER
|
||||
** table.
|
||||
** Drop a trigger given a pointer to that trigger.
|
||||
*/
|
||||
void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
|
||||
void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger){
|
||||
Table *pTable;
|
||||
Vdbe *v;
|
||||
sqlite3 *db = pParse->db;
|
||||
@ -489,8 +489,8 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
|
||||
|
||||
iDb = sqlite3SchemaToIndex(pParse->db, pTrigger->pSchema);
|
||||
assert( iDb>=0 && iDb<db->nDb );
|
||||
pTable = tableOfTrigger(db, pTrigger);
|
||||
assert(pTable);
|
||||
pTable = tableOfTrigger(pTrigger);
|
||||
assert( pTable );
|
||||
assert( pTable->pSchema==pTrigger->pSchema || iDb==1 );
|
||||
#ifndef SQLITE_OMIT_AUTHORIZATION
|
||||
{
|
||||
@ -507,7 +507,8 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
|
||||
|
||||
/* Generate code to destroy the database record of the trigger.
|
||||
*/
|
||||
if( pTable!=0 && (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||
assert( pTable!=0 );
|
||||
if( (v = sqlite3GetVdbe(pParse))!=0 ){
|
||||
int base;
|
||||
static const VdbeOpList dropTrigger[] = {
|
||||
{ OP_Rewind, 0, ADDR(9), 0},
|
||||
@ -537,9 +538,10 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
|
||||
void sqlite3UnlinkAndDeleteTrigger(sqlite3 *db, int iDb, const char *zName){
|
||||
Trigger *pTrigger;
|
||||
int nName = strlen(zName);
|
||||
pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash), zName, nName+1, 0);
|
||||
pTrigger = sqlite3HashInsert(&(db->aDb[iDb].pSchema->trigHash),
|
||||
zName, nName, 0);
|
||||
if( pTrigger ){
|
||||
Table *pTable = tableOfTrigger(db, pTrigger);
|
||||
Table *pTable = tableOfTrigger(pTrigger);
|
||||
assert( pTable!=0 );
|
||||
if( pTable->pTrigger == pTrigger ){
|
||||
pTable->pTrigger = pTrigger->pNext;
|
||||
@ -597,14 +599,7 @@ int sqlite3TriggersExist(
|
||||
|
||||
while( pTrigger ){
|
||||
if( pTrigger->op==op && checkColumnOverLap(pTrigger->pColumns, pChanges) ){
|
||||
TriggerStack *ss;
|
||||
ss = pParse->trigStack;
|
||||
while( ss && ss->pTrigger!=pTab->pTrigger ){
|
||||
ss = ss->pNext;
|
||||
}
|
||||
if( ss==0 ){
|
||||
mask |= pTrigger->tr_tm;
|
||||
}
|
||||
mask |= pTrigger->tr_tm;
|
||||
}
|
||||
pTrigger = pTrigger->pNext;
|
||||
}
|
||||
@ -761,10 +756,17 @@ int sqlite3CodeRowTrigger(
|
||||
(op!=TK_UPDATE||!p->pColumns||checkColumnOverLap(p->pColumns,pChanges))
|
||||
){
|
||||
TriggerStack *pS; /* Pointer to trigger-stack entry */
|
||||
for(pS=pParse->trigStack; pS && p!=pS->pTrigger; pS=pS->pNext);
|
||||
for(pS=pParse->trigStack; pS && p!=pS->pTrigger; pS=pS->pNext){}
|
||||
if( !pS ){
|
||||
fire_this = 1;
|
||||
}
|
||||
#if 0 /* Give no warning for recursive triggers. Just do not do them */
|
||||
else{
|
||||
sqlite3ErrorMsg(pParse, "recursive triggers not supported (%s)",
|
||||
p->name);
|
||||
return SQLITE_ERROR;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if( fire_this ){
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle UPDATE statements.
|
||||
**
|
||||
** $Id: update.c,v 1.122 2006/02/10 02:27:43 danielk1977 Exp $
|
||||
** $Id: update.c,v 1.123 2006/02/24 02:53:50 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -431,7 +431,7 @@ void sqlite3Update(
|
||||
|
||||
/* Delete the old indices for the current record.
|
||||
*/
|
||||
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, aIdxUsed);
|
||||
sqlite3GenerateRowIndexDelete(v, pTab, iCur, aIdxUsed);
|
||||
|
||||
/* If changing the record number, delete the old record.
|
||||
*/
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
** This file contains routines used to translate between UTF-8,
|
||||
** UTF-16, UTF-16BE, and UTF-16LE.
|
||||
**
|
||||
** $Id: utf.c,v 1.37 2006/01/24 10:58:22 danielk1977 Exp $
|
||||
** $Id: utf.c,v 1.39 2006/04/16 12:05:03 drh Exp $
|
||||
**
|
||||
** Notes on UTF-8:
|
||||
**
|
||||
@ -255,7 +255,7 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
|
||||
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
|
||||
{
|
||||
char zBuf[100];
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf);
|
||||
fprintf(stderr, "INPUT: %s\n", zBuf);
|
||||
}
|
||||
#endif
|
||||
@ -287,11 +287,11 @@ int sqlite3VdbeMemTranslate(Mem *pMem, u8 desiredEnc){
|
||||
/* Set len to the maximum number of bytes required in the output buffer. */
|
||||
if( desiredEnc==SQLITE_UTF8 ){
|
||||
/* When converting from UTF-16, the maximum growth results from
|
||||
** translating a 2-byte character to a 3-byte UTF-8 character (i.e.
|
||||
** code-point 0xFFFC). A single byte is required for the output string
|
||||
** translating a 2-byte character to a 4-byte UTF-8 character.
|
||||
** A single byte is required for the output string
|
||||
** nul-terminator.
|
||||
*/
|
||||
len = (pMem->n/2) * 3 + 1;
|
||||
len = pMem->n * 2 + 1;
|
||||
}else{
|
||||
/* When converting from UTF-8 to UTF-16 the maximum growth is caused
|
||||
** when a 1-byte UTF-8 character is translated into a 2-byte UTF-16
|
||||
@ -371,7 +371,7 @@ translate_out:
|
||||
#if defined(TRANSLATE_TRACE) && defined(SQLITE_DEBUG)
|
||||
{
|
||||
char zBuf[100];
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf, 100);
|
||||
sqlite3VdbeMemPrettyPrint(pMem, zBuf);
|
||||
fprintf(stderr, "OUTPUT: %s\n", zBuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.185 2006/02/14 10:48:39 danielk1977 Exp $
|
||||
** $Id: util.c,v 1.189 2006/04/08 19:14:53 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -476,8 +476,9 @@ static int OSSIZEOF(void *p){
|
||||
** pointer to the space allocated for the application to use.
|
||||
*/
|
||||
static void OSFREE(void *pFree){
|
||||
u32 *p; /* Pointer to the OS-layer allocation */
|
||||
sqlite3OsEnterMutex();
|
||||
u32 *p = (u32 *)getOsPointer(pFree); /* p points to Os level allocation */
|
||||
p = (u32 *)getOsPointer(pFree);
|
||||
checkGuards(p);
|
||||
unlinkAlloc(p);
|
||||
memset(pFree, 0x55, OSSIZEOF(pFree));
|
||||
@ -547,7 +548,7 @@ static int enforceSoftLimit(int n){
|
||||
}
|
||||
assert( pTsd->nAlloc>=0 );
|
||||
if( n>0 && pTsd->nSoftHeapLimit>0 ){
|
||||
while( pTsd->nAlloc+n>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) );
|
||||
while( pTsd->nAlloc+n>pTsd->nSoftHeapLimit && sqlite3_release_memory(n) ){}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@ -586,7 +587,7 @@ static void updateMemoryUsedCount(int n){
|
||||
void *sqlite3MallocRaw(int n, int doMemManage){
|
||||
void *p = 0;
|
||||
if( n>0 && !sqlite3MallocFailed() && (!doMemManage || enforceSoftLimit(n)) ){
|
||||
while( (p = OSMALLOC(n))==0 && sqlite3_release_memory(n) );
|
||||
while( (p = OSMALLOC(n))==0 && sqlite3_release_memory(n) ){}
|
||||
if( !p ){
|
||||
sqlite3FailedMalloc();
|
||||
OSMALLOC_FAILED();
|
||||
@ -615,7 +616,7 @@ void *sqlite3Realloc(void *p, int n){
|
||||
int origSize = OSSIZEOF(p);
|
||||
#endif
|
||||
if( enforceSoftLimit(n - origSize) ){
|
||||
while( (np = OSREALLOC(p, n))==0 && sqlite3_release_memory(n) );
|
||||
while( (np = OSREALLOC(p, n))==0 && sqlite3_release_memory(n) ){}
|
||||
if( !np ){
|
||||
sqlite3FailedMalloc();
|
||||
OSMALLOC_FAILED();
|
||||
@ -883,6 +884,7 @@ void sqlite3Dequote(char *z){
|
||||
** lower-case character.
|
||||
*/
|
||||
const unsigned char sqlite3UpperToLower[] = {
|
||||
#ifdef SQLITE_ASCII
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
|
||||
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
|
||||
@ -898,6 +900,25 @@ const unsigned char sqlite3UpperToLower[] = {
|
||||
216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
|
||||
234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
|
||||
252,253,254,255
|
||||
#endif
|
||||
#ifdef SQLITE_EBCDIC
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 0x */
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 1x */
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, /* 2x */
|
||||
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, /* 3x */
|
||||
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, /* 4x */
|
||||
80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, /* 5x */
|
||||
96, 97, 66, 67, 68, 69, 70, 71, 72, 73,106,107,108,109,110,111, /* 6x */
|
||||
112, 81, 82, 83, 84, 85, 86, 87, 88, 89,122,123,124,125,126,127, /* 7x */
|
||||
128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, /* 8x */
|
||||
144,145,146,147,148,149,150,151,152,153,154,155,156,157,156,159, /* 9x */
|
||||
160,161,162,163,164,165,166,167,168,169,170,171,140,141,142,175, /* Ax */
|
||||
176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, /* Bx */
|
||||
192,129,130,131,132,133,134,135,136,137,202,203,204,205,206,207, /* Cx */
|
||||
208,145,146,147,148,149,150,151,152,153,218,219,220,221,222,223, /* Dx */
|
||||
224,225,162,163,164,165,166,167,168,169,232,203,204,205,206,207, /* Ex */
|
||||
239,240,241,242,243,244,245,246,247,248,249,219,220,221,222,255, /* Fx */
|
||||
#endif
|
||||
};
|
||||
#define UpperToLower sqlite3UpperToLower
|
||||
|
||||
@ -971,6 +992,7 @@ int sqlite3AtoF(const char *z, double *pResult){
|
||||
int sign = 1;
|
||||
const char *zBegin = z;
|
||||
LONGDOUBLE_TYPE v1 = 0.0;
|
||||
while( isspace(*z) ) z++;
|
||||
if( *z=='-' ){
|
||||
sign = -1;
|
||||
z++;
|
||||
@ -1038,6 +1060,7 @@ int sqlite3atoi64(const char *zNum, i64 *pNum){
|
||||
i64 v = 0;
|
||||
int neg;
|
||||
int i, c;
|
||||
while( isspace(*zNum) ) zNum++;
|
||||
if( *zNum=='-' ){
|
||||
neg = 1;
|
||||
zNum++;
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
** Most of the code in this file may be omitted by defining the
|
||||
** SQLITE_OMIT_VACUUM macro.
|
||||
**
|
||||
** $Id: vacuum.c,v 1.58 2006/01/18 16:51:36 danielk1977 Exp $
|
||||
** $Id: vacuum.c,v 1.59 2006/02/24 02:53:50 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "vdbeInt.h"
|
||||
@ -43,7 +43,7 @@ static int execSql(sqlite3 *db, const char *zSql){
|
||||
if( SQLITE_OK!=sqlite3_prepare(db, zSql, -1, &pStmt, 0) ){
|
||||
return sqlite3_errcode(db);
|
||||
}
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) );
|
||||
while( SQLITE_ROW==sqlite3_step(pStmt) ){}
|
||||
return sqlite3_finalize(pStmt);
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ static int execExecSql(sqlite3 *db, const char *zSql){
|
||||
** with 2.0.0, SQLite no longer uses GDBM so this command has
|
||||
** become a no-op.
|
||||
*/
|
||||
void sqlite3Vacuum(Parse *pParse, Token *pTableName){
|
||||
void sqlite3Vacuum(Parse *pParse){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
if( v ){
|
||||
sqlite3VdbeAddOp(v, OP_Vacuum, 0, 0);
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
** in this file for details. If in doubt, do not deviate from existing
|
||||
** commenting and indentation practices when changing or adding code.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.543 2006/02/10 14:02:07 drh Exp $
|
||||
** $Id: vdbe.c,v 1.548 2006/03/22 22:10:08 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -280,7 +280,7 @@ void sqlite3ValueApplyAffinity(sqlite3_value *pVal, u8 affinity, u8 enc){
|
||||
** Write a nice string representation of the contents of cell pMem
|
||||
** into buffer zBuf, length nBuf.
|
||||
*/
|
||||
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf){
|
||||
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf){
|
||||
char *zCsr = zBuf;
|
||||
int f = pMem->flags;
|
||||
|
||||
@ -1871,13 +1871,6 @@ case OP_SetNumColumns: { /* no-push */
|
||||
** If the KeyAsData opcode has previously executed on this cursor, then the
|
||||
** field might be extracted from the key rather than the data.
|
||||
**
|
||||
** If P1 is negative, then the record is stored on the stack rather than in
|
||||
** a table. For P1==-1, the top of the stack is used. For P1==-2, the
|
||||
** next on the stack is used. And so forth. The value pushed is always
|
||||
** just a pointer into the record which is stored further down on the
|
||||
** stack. The column value is not copied. The number of columns in the
|
||||
** record is stored on the stack just above the record itself.
|
||||
**
|
||||
** If the column contains fewer than P2 fields, then push a NULL. Or
|
||||
** if P3 is of type P3_MEM, then push the P3 value. The P3 value will
|
||||
** be default value for a column that has been added using the ALTER TABLE
|
||||
@ -1909,31 +1902,19 @@ case OP_Column: {
|
||||
** bytes in the record.
|
||||
**
|
||||
** zRec is set to be the complete text of the record if it is available.
|
||||
** The complete record text is always available for pseudo-tables and
|
||||
** when we are decoded a record from the stack. If the record is stored
|
||||
** in a cursor, the complete record text might be available in the
|
||||
** pC->aRow cache. Or it might not be. If the data is unavailable,
|
||||
** zRec is set to NULL.
|
||||
** The complete record text is always available for pseudo-tables
|
||||
** If the record is stored in a cursor, the complete record text
|
||||
** might be available in the pC->aRow cache. Or it might not be.
|
||||
** If the data is unavailable, zRec is set to NULL.
|
||||
**
|
||||
** We also compute the number of columns in the record. For cursors,
|
||||
** the number of columns is stored in the Cursor.nField element. For
|
||||
** records on the stack, the next entry down on the stack is an integer
|
||||
** which is the number of records.
|
||||
*/
|
||||
assert( p1<0 || p->apCsr[p1]!=0 );
|
||||
if( p1<0 ){
|
||||
/* Take the record off of the stack */
|
||||
Mem *pRec = &pTos[p1];
|
||||
Mem *pCnt = &pRec[-1];
|
||||
assert( pRec>=p->aStack );
|
||||
assert( pRec->flags & MEM_Blob );
|
||||
payloadSize = pRec->n;
|
||||
zRec = pRec->z;
|
||||
assert( pCnt>=p->aStack );
|
||||
assert( pCnt->flags & MEM_Int );
|
||||
nField = pCnt->i;
|
||||
pCrsr = 0;
|
||||
}else if( (pC = p->apCsr[p1])->pCursor!=0 ){
|
||||
pC = p->apCsr[p1];
|
||||
assert( pC!=0 );
|
||||
if( pC->pCursor!=0 ){
|
||||
/* The record is stored in a B-Tree */
|
||||
rc = sqlite3VdbeCursorMoveto(pC);
|
||||
if( rc ) goto abort_due_to_error;
|
||||
@ -1952,7 +1933,6 @@ case OP_Column: {
|
||||
sqlite3BtreeDataSize(pCrsr, &payloadSize);
|
||||
}
|
||||
nField = pC->nField;
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
}else if( pC->pseudoTable ){
|
||||
/* The record is the sole entry of a pseudo-table */
|
||||
payloadSize = pC->nData;
|
||||
@ -1961,7 +1941,6 @@ case OP_Column: {
|
||||
assert( payloadSize==0 || zRec!=0 );
|
||||
nField = pC->nField;
|
||||
pCrsr = 0;
|
||||
#endif
|
||||
}else{
|
||||
zRec = 0;
|
||||
payloadSize = 0;
|
||||
@ -1989,15 +1968,17 @@ case OP_Column: {
|
||||
u32 offset; /* Offset into the data */
|
||||
int szHdrSz; /* Size of the header size field at start of record */
|
||||
int avail; /* Number of bytes of available data */
|
||||
if( pC && pC->aType ){
|
||||
aType = pC->aType;
|
||||
}else{
|
||||
aType = sqliteMallocRaw( 2*nField*sizeof(aType) );
|
||||
|
||||
aType = pC->aType;
|
||||
if( aType==0 ){
|
||||
pC->aType = aType = sqliteMallocRaw( 2*nField*sizeof(aType) );
|
||||
}
|
||||
aOffset = &aType[nField];
|
||||
if( aType==0 ){
|
||||
goto no_mem;
|
||||
}
|
||||
pC->aOffset = aOffset = &aType[nField];
|
||||
pC->payloadSize = payloadSize;
|
||||
pC->cacheStatus = p->cacheCtr;
|
||||
|
||||
/* Figure out how many bytes are in the header */
|
||||
if( zRec ){
|
||||
@ -2070,15 +2051,6 @@ case OP_Column: {
|
||||
rc = SQLITE_CORRUPT_BKPT;
|
||||
goto op_column_out;
|
||||
}
|
||||
|
||||
/* Remember all aType and aColumn information if we have a cursor
|
||||
** to remember it in. */
|
||||
if( pC ){
|
||||
pC->payloadSize = payloadSize;
|
||||
pC->aType = aType;
|
||||
pC->aOffset = aOffset;
|
||||
pC->cacheStatus = p->cacheCtr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the column information. If aOffset[p2] is non-zero, then
|
||||
@ -2111,7 +2083,7 @@ case OP_Column: {
|
||||
|
||||
/* If we dynamically allocated space to hold the data (in the
|
||||
** sqlite3VdbeMemFromBtree() call above) then transfer control of that
|
||||
** dynamically allocated space over to the pTos structure rather.
|
||||
** dynamically allocated space over to the pTos structure.
|
||||
** This prevents a memory copy.
|
||||
*/
|
||||
if( (sMem.flags & MEM_Dyn)!=0 ){
|
||||
@ -2128,10 +2100,6 @@ case OP_Column: {
|
||||
rc = sqlite3VdbeMemMakeWriteable(pTos);
|
||||
|
||||
op_column_out:
|
||||
/* Release the aType[] memory if we are not dealing with cursor */
|
||||
if( !pC || !pC->aType ){
|
||||
sqliteFree(aType);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2722,7 +2690,6 @@ case OP_OpenVirtual: { /* no-push */
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
/* Opcode: OpenPseudo P1 * *
|
||||
**
|
||||
** Open a new cursor that points to a fake table that contains a single
|
||||
@ -2731,7 +2698,9 @@ case OP_OpenVirtual: { /* no-push */
|
||||
** closed.
|
||||
**
|
||||
** A pseudo-table created by this opcode is useful for holding the
|
||||
** NEW or OLD tables in a trigger.
|
||||
** NEW or OLD tables in a trigger. Also used to hold the a single
|
||||
** row output from the sorter so that the row can be decomposed into
|
||||
** individual columns using the OP_Column opcode.
|
||||
*/
|
||||
case OP_OpenPseudo: { /* no-push */
|
||||
int i = pOp->p1;
|
||||
@ -2746,7 +2715,6 @@ case OP_OpenPseudo: { /* no-push */
|
||||
pCx->isIndex = 0;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Opcode: Close P1 * *
|
||||
**
|
||||
@ -3013,7 +2981,7 @@ case OP_IsUnique: { /* no-push */
|
||||
zKey = pNos->z;
|
||||
nKey = pNos->n;
|
||||
|
||||
szRowid = sqlite3VdbeIdxRowidLen(nKey, (u8*)zKey);
|
||||
szRowid = sqlite3VdbeIdxRowidLen((u8*)zKey);
|
||||
len = nKey-szRowid;
|
||||
|
||||
/* Search for an entry in P1 where all but the last four bytes match K.
|
||||
@ -3320,7 +3288,6 @@ case OP_Insert: { /* no-push */
|
||||
}else{
|
||||
assert( pTos->flags & (MEM_Blob|MEM_Str) );
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
if( pC->pseudoTable ){
|
||||
sqliteFree(pC->pData);
|
||||
pC->iKey = iKey;
|
||||
@ -3337,11 +3304,8 @@ case OP_Insert: { /* no-push */
|
||||
}
|
||||
pC->nullRow = 0;
|
||||
}else{
|
||||
#endif
|
||||
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey, pTos->z, pTos->n);
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
}
|
||||
#endif
|
||||
|
||||
pC->rowidIsValid = 0;
|
||||
pC->deferredMoveto = 0;
|
||||
@ -3498,12 +3462,10 @@ case OP_RowData: {
|
||||
}else{
|
||||
sqlite3BtreeData(pCrsr, 0, n, pTos->z);
|
||||
}
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
}else if( pC->pseudoTable ){
|
||||
pTos->n = pC->nData;
|
||||
pTos->z = pC->pData;
|
||||
pTos->flags = MEM_Blob|MEM_Ephem;
|
||||
#endif
|
||||
}else{
|
||||
pTos->flags = MEM_Null;
|
||||
}
|
||||
@ -4071,7 +4033,7 @@ case OP_ParseSchema: { /* no-push */
|
||||
break;
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_ANALYZE
|
||||
#if !defined(SQLITE_OMIT_ANALYZE) && !defined(SQLITE_OMIT_PARSER)
|
||||
/* Opcode: LoadAnalysis P1 * *
|
||||
**
|
||||
** Read the sqlite_stat1 table for database P1 and load the content
|
||||
@ -4084,7 +4046,7 @@ case OP_LoadAnalysis: { /* no-push */
|
||||
sqlite3AnalysisLoad(db, iDb);
|
||||
break;
|
||||
}
|
||||
#endif /* SQLITE_OMIT_ANALYZE */
|
||||
#endif /* !defined(SQLITE_OMIT_ANALYZE) && !defined(SQLITE_OMIT_PARSER) */
|
||||
|
||||
/* Opcode: DropTable P1 * P3
|
||||
**
|
||||
@ -4536,7 +4498,7 @@ case OP_Expire: { /* no-push */
|
||||
** Obtain a lock on a particular table. This instruction is only used when
|
||||
** the shared-cache feature is enabled.
|
||||
**
|
||||
** If P1 is not negative, then it is the index of the index of the database
|
||||
** If P1 is not negative, then it is the index of the database
|
||||
** in sqlite3.aDb[] and a read-lock is required. If P1 is negative, a
|
||||
** write-lock is required. In this case the index of the database is the
|
||||
** absolute value of P1 minus one (iDb = abs(P1) - 1;) and a write-lock is
|
||||
@ -4600,7 +4562,7 @@ default: {
|
||||
#ifndef NDEBUG
|
||||
/* Sanity checking on the top element of the stack */
|
||||
if( pTos>=p->aStack ){
|
||||
sqlite3VdbeMemSanity(pTos, encoding);
|
||||
sqlite3VdbeMemSanity(pTos);
|
||||
}
|
||||
assert( pc>=-1 && pc<p->nOp );
|
||||
#ifdef SQLITE_DEBUG
|
||||
@ -4619,7 +4581,7 @@ default: {
|
||||
fprintf(p->trace, " r:%g", pTos[i].r);
|
||||
}else{
|
||||
char zBuf[100];
|
||||
sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf, 100);
|
||||
sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf);
|
||||
fprintf(p->trace, " ");
|
||||
fprintf(p->trace, "%s", zBuf);
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
** or VDBE. The VDBE implements an abstract machine that runs a
|
||||
** simple program to access and modify the underlying database.
|
||||
**
|
||||
** $Id: vdbe.h,v 1.101 2006/02/10 03:06:10 danielk1977 Exp $
|
||||
** $Id: vdbe.h,v 1.102 2006/03/17 13:56:34 drh Exp $
|
||||
*/
|
||||
#ifndef _SQLITE_VDBE_H_
|
||||
#define _SQLITE_VDBE_H_
|
||||
@ -117,6 +117,7 @@ int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
|
||||
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
||||
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
||||
void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
||||
void sqlite3VdbeChangeToNoop(Vdbe*, int addr, int N);
|
||||
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
|
||||
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
||||
int sqlite3VdbeMakeLabel(Vdbe*);
|
||||
|
||||
@ -317,6 +317,10 @@ struct Vdbe {
|
||||
u8 minWriteFileFormat; /* Minimum file format for writable database files */
|
||||
int nChange; /* Number of db changes made since last reset */
|
||||
i64 startTime; /* Time when query started - used for profiling */
|
||||
#ifdef SQLITE_SSE
|
||||
int fetchId; /* Statement number used by sqlite3_fetch_statement */
|
||||
int lru; /* Counter used for LRU cache replacement */
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@ -350,7 +354,7 @@ int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*);
|
||||
int sqlite3VdbeIdxRowid(BtCursor *, i64 *);
|
||||
int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*);
|
||||
int sqlite3VdbeRecordCompare(void*,int,const void*,int, const void*);
|
||||
int sqlite3VdbeIdxRowidLen(int,const u8*);
|
||||
int sqlite3VdbeIdxRowidLen(const u8*);
|
||||
int sqlite3VdbeExec(Vdbe*);
|
||||
int sqlite3VdbeList(Vdbe*);
|
||||
int sqlite3VdbeHalt(Vdbe*);
|
||||
@ -376,11 +380,11 @@ int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
|
||||
void sqlite3VdbeMemRelease(Mem *p);
|
||||
int sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
||||
#ifndef NDEBUG
|
||||
void sqlite3VdbeMemSanity(Mem*, u8);
|
||||
void sqlite3VdbeMemSanity(Mem*);
|
||||
int sqlite3VdbeOpcodeNoPush(u8);
|
||||
#endif
|
||||
int sqlite3VdbeMemTranslate(Mem*, u8);
|
||||
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf, int nBuf);
|
||||
void sqlite3VdbeMemPrettyPrint(Mem *pMem, char *zBuf);
|
||||
int sqlite3VdbeMemHandleBom(Mem *pMem);
|
||||
void sqlite3VdbeFifoInit(Fifo*);
|
||||
int sqlite3VdbeFifoPush(Fifo*, i64);
|
||||
|
||||
@ -107,9 +107,11 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
||||
i = p->nOp;
|
||||
p->nOp++;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
resizeOpArray(p, i+1);
|
||||
if( sqlite3MallocFailed() ){
|
||||
return 0;
|
||||
if( p->nOpAlloc<=i ){
|
||||
resizeOpArray(p, i+1);
|
||||
if( sqlite3MallocFailed() ){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
pOp = &p->aOp[i];
|
||||
pOp->opcode = op;
|
||||
@ -202,11 +204,11 @@ static int opcodeNoPush(u8 op){
|
||||
** IEEE floats.
|
||||
*/
|
||||
static const u32 masks[5] = {
|
||||
NOPUSH_MASK_0 + (NOPUSH_MASK_1<<16),
|
||||
NOPUSH_MASK_2 + (NOPUSH_MASK_3<<16),
|
||||
NOPUSH_MASK_4 + (NOPUSH_MASK_5<<16),
|
||||
NOPUSH_MASK_6 + (NOPUSH_MASK_7<<16),
|
||||
NOPUSH_MASK_8 + (NOPUSH_MASK_9<<16)
|
||||
NOPUSH_MASK_0 + (((unsigned)NOPUSH_MASK_1)<<16),
|
||||
NOPUSH_MASK_2 + (((unsigned)NOPUSH_MASK_3)<<16),
|
||||
NOPUSH_MASK_4 + (((unsigned)NOPUSH_MASK_5)<<16),
|
||||
NOPUSH_MASK_6 + (((unsigned)NOPUSH_MASK_7)<<16),
|
||||
NOPUSH_MASK_8 + (((unsigned)NOPUSH_MASK_9)<<16)
|
||||
};
|
||||
assert( op<32*5 );
|
||||
return (masks[op>>5] & (1<<(op&0x1F)));
|
||||
@ -340,7 +342,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
|
||||
** few minor changes to the program.
|
||||
*/
|
||||
void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( p==0 || p->magic==VDBE_MAGIC_INIT );
|
||||
if( p && addr>=0 && p->nOp>addr && p->aOp ){
|
||||
p->aOp[addr].p1 = val;
|
||||
}
|
||||
@ -352,14 +354,14 @@ void sqlite3VdbeChangeP1(Vdbe *p, int addr, int val){
|
||||
*/
|
||||
void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
|
||||
assert( val>=0 );
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( p==0 || p->magic==VDBE_MAGIC_INIT );
|
||||
if( p && addr>=0 && p->nOp>addr && p->aOp ){
|
||||
p->aOp[addr].p2 = val;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Change teh P2 operand of instruction addr so that it points to
|
||||
** Change the P2 operand of instruction addr so that it points to
|
||||
** the address of the next instruction to be coded.
|
||||
*/
|
||||
void sqlite3VdbeJumpHere(Vdbe *p, int addr){
|
||||
@ -393,6 +395,19 @@ static void freeP3(int p3type, void *p3){
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Change N opcodes starting at addr to No-ops.
|
||||
*/
|
||||
void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){
|
||||
VdbeOp *pOp = &p->aOp[addr];
|
||||
while( N-- ){
|
||||
freeP3(pOp->p3type, pOp->p3);
|
||||
memset(pOp, 0, sizeof(pOp[0]));
|
||||
pOp->opcode = OP_Noop;
|
||||
pOp++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Change the value of the P3 operand for a specific instruction.
|
||||
** This routine is useful when a large program is loaded from a
|
||||
@ -420,7 +435,7 @@ static void freeP3(int p3type, void *p3){
|
||||
*/
|
||||
void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
||||
Op *pOp;
|
||||
assert( p->magic==VDBE_MAGIC_INIT );
|
||||
assert( p==0 || p->magic==VDBE_MAGIC_INIT );
|
||||
if( p==0 || p->aOp==0 || sqlite3MallocFailed() ){
|
||||
if (n != P3_KEYINFO) {
|
||||
freeP3(n, (void*)*(char**)&zP3);
|
||||
@ -656,8 +671,9 @@ int sqlite3VdbeList(
|
||||
pMem->type = SQLITE_INTEGER;
|
||||
pMem++;
|
||||
|
||||
pMem->flags = MEM_Short|MEM_Str|MEM_Term; /* P3 */
|
||||
pMem->flags = MEM_Ephem|MEM_Str|MEM_Term; /* P3 */
|
||||
pMem->z = displayP3(pOp, pMem->zShort, sizeof(pMem->zShort));
|
||||
pMem->n = strlen(pMem->z);
|
||||
pMem->type = SQLITE_TEXT;
|
||||
pMem->enc = SQLITE_UTF8;
|
||||
|
||||
@ -1841,7 +1857,7 @@ int sqlite3VdbeRecordCompare(
|
||||
** an integer rowid). This routine returns the number of bytes in
|
||||
** that integer.
|
||||
*/
|
||||
int sqlite3VdbeIdxRowidLen(int nKey, const u8 *aKey){
|
||||
int sqlite3VdbeIdxRowidLen(const u8 *aKey){
|
||||
u32 szHdr; /* Size of the header */
|
||||
u32 typeRowid; /* Serial type of the rowid */
|
||||
|
||||
@ -1911,7 +1927,7 @@ int sqlite3VdbeIdxKeyCompare(
|
||||
if( rc ){
|
||||
return rc;
|
||||
}
|
||||
lenRowid = sqlite3VdbeIdxRowidLen(m.n, (u8*)m.z);
|
||||
lenRowid = sqlite3VdbeIdxRowidLen((u8*)m.z);
|
||||
*res = sqlite3VdbeRecordCompare(pC->pKeyInfo, m.n-lenRowid, m.z, nKey, pKey);
|
||||
sqlite3VdbeMemRelease(&m);
|
||||
return SQLITE_OK;
|
||||
|
||||
@ -711,7 +711,7 @@ int sqlite3VdbeMemFromBtree(
|
||||
** Perform various checks on the memory cell pMem. An assert() will
|
||||
** fail if pMem is internally inconsistent.
|
||||
*/
|
||||
void sqlite3VdbeMemSanity(Mem *pMem, u8 db_enc){
|
||||
void sqlite3VdbeMemSanity(Mem *pMem){
|
||||
int flags = pMem->flags;
|
||||
assert( flags!=0 ); /* Must define some type */
|
||||
if( pMem->flags & (MEM_Str|MEM_Blob) ){
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
** so is applicable. Because this module is responsible for selecting
|
||||
** indices, you might also think of this module as the "query optimizer".
|
||||
**
|
||||
** $Id: where.c,v 1.204 2006/02/01 02:45:02 drh Exp $
|
||||
** $Id: where.c,v 1.208 2006/05/11 13:26:26 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -771,8 +771,7 @@ or_not_possible:
|
||||
static int isSortingIndex(
|
||||
Parse *pParse, /* Parsing context */
|
||||
Index *pIdx, /* The index we are testing */
|
||||
Table *pTab, /* The table to be sorted */
|
||||
int base, /* Cursor number for pTab */
|
||||
int base, /* Cursor number for the table to be sorted */
|
||||
ExprList *pOrderBy, /* The ORDER BY clause */
|
||||
int nEqCol, /* Number of index columns with == constraints */
|
||||
int *pbRev /* Set to 1 if ORDER BY is DESC */
|
||||
@ -927,6 +926,22 @@ static double bestIndex(
|
||||
|
||||
TRACE(("bestIndex: tbl=%s notReady=%x\n", pSrc->pTab->zName, notReady));
|
||||
lowestCost = SQLITE_BIG_DBL;
|
||||
pProbe = pSrc->pTab->pIndex;
|
||||
|
||||
/* If the table has no indices and there are no terms in the where
|
||||
** clause that refer to the ROWID, then we will never be able to do
|
||||
** anything other than a full table scan on this table. We might as
|
||||
** well put it first in the join order. That way, perhaps it can be
|
||||
** referenced by other tables in the join.
|
||||
*/
|
||||
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)) ){
|
||||
*pFlags = 0;
|
||||
*ppIndex = 0;
|
||||
*pnEq = 0;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
/* Check for a rowid=EXPR or rowid IN (...) constraints
|
||||
*/
|
||||
@ -959,7 +974,6 @@ static double bestIndex(
|
||||
/* 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.
|
||||
*/
|
||||
pProbe = pSrc->pTab->pIndex;
|
||||
cost = pProbe ? pProbe->aiRowEst[0] : 1000000;
|
||||
TRACE(("... table scan base cost: %.9g\n", cost));
|
||||
flags = WHERE_ROWID_RANGE;
|
||||
@ -1020,7 +1034,7 @@ static double bestIndex(
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
flags |= WHERE_COLUMN_IN;
|
||||
if( pExpr->pSelect!=0 ){
|
||||
inMultiplier *= 100;
|
||||
inMultiplier *= 25;
|
||||
}else if( pExpr->pList!=0 ){
|
||||
inMultiplier *= pExpr->pList->nExpr + 1;
|
||||
}
|
||||
@ -1057,7 +1071,7 @@ static double bestIndex(
|
||||
*/
|
||||
if( pOrderBy ){
|
||||
if( (flags & WHERE_COLUMN_IN)==0 &&
|
||||
isSortingIndex(pParse,pProbe,pSrc->pTab,iCur,pOrderBy,nEq,&rev) ){
|
||||
isSortingIndex(pParse,pProbe,iCur,pOrderBy,nEq,&rev) ){
|
||||
if( flags==0 ){
|
||||
flags = WHERE_COLUMN_RANGE;
|
||||
}
|
||||
@ -1210,17 +1224,16 @@ static void codeEqualityTerm(
|
||||
|
||||
sqlite3CodeSubselect(pParse, pX);
|
||||
iTab = pX->iTable;
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iTab, 0);
|
||||
VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
|
||||
pLevel->nIn++;
|
||||
sqliteReallocOrFree((void**)&pLevel->aInLoop,
|
||||
sizeof(pLevel->aInLoop[0])*3*pLevel->nIn);
|
||||
sizeof(pLevel->aInLoop[0])*2*pLevel->nIn);
|
||||
aIn = pLevel->aInLoop;
|
||||
if( aIn ){
|
||||
aIn += pLevel->nIn*3 - 3;
|
||||
aIn[0] = OP_Next;
|
||||
aIn[1] = iTab;
|
||||
aIn[2] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
|
||||
aIn += pLevel->nIn*2 - 2;
|
||||
aIn[0] = iTab;
|
||||
aIn[1] = sqlite3VdbeAddOp(v, OP_Column, iTab, 0);
|
||||
}else{
|
||||
pLevel->nIn = 0;
|
||||
}
|
||||
@ -1579,6 +1592,9 @@ WhereInfo *sqlite3WhereBegin(
|
||||
}else if( pLevel->flags & (WHERE_ROWID_EQ|WHERE_ROWID_RANGE) ){
|
||||
zMsg = sqlite3MPrintf("%z USING PRIMARY KEY", zMsg);
|
||||
}
|
||||
if( pLevel->flags & WHERE_ORDERBY ){
|
||||
zMsg = sqlite3MPrintf("%z ORDER BY", zMsg);
|
||||
}
|
||||
sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC);
|
||||
}
|
||||
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||
@ -1591,7 +1607,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||
if( pTab->nCol<(sizeof(Bitmask)*8) ){
|
||||
Bitmask b = pTabItem->colUsed;
|
||||
int n = 0;
|
||||
for(; b; b=b>>1, n++);
|
||||
for(; b; b=b>>1, n++){}
|
||||
sqlite3VdbeChangeP2(v, sqlite3VdbeCurrentAddr(v)-1, n);
|
||||
assert( n<=pTab->nCol );
|
||||
}
|
||||
@ -2042,8 +2058,9 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||
if( pLevel->nIn ){
|
||||
int *a;
|
||||
int j;
|
||||
for(j=pLevel->nIn, a=&pLevel->aInLoop[j*3-3]; j>0; j--, a-=3){
|
||||
sqlite3VdbeAddOp(v, a[0], a[1], a[2]);
|
||||
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);
|
||||
}
|
||||
sqliteFree(pLevel->aInLoop);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user