Upgrade bundled library to 2.8.14 + misc fixes

(http://www.sqlite.org/cvstrac/chngview?cn=1742)
This commit is contained in:
Wez Furlong 2004-07-10 12:27:51 +00:00
parent cd732f1a3f
commit e563b4eafa
43 changed files with 5953 additions and 5559 deletions

View file

@ -23,12 +23,15 @@
** The pFilename and pDbname arguments are the tokens that define the
** filename and dbname in the ATTACH statement.
*/
void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname){
void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname, Token *pKey){
Db *aNew;
int rc, i;
char *zFile, *zName;
sqlite *db;
Vdbe *v;
v = sqliteGetVdbe(pParse);
sqliteVdbeAddOp(v, OP_Halt, 0, 0);
if( pParse->explain ) return;
db = pParse->db;
if( db->file_format<4 ){
@ -88,6 +91,22 @@ void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname){
if( rc ){
sqliteErrorMsg(pParse, "unable to open database: %s", zFile);
}
#if SQLITE_HAS_CODEC
{
extern int sqliteCodecAttach(sqlite*, int, void*, int);
char *zKey = 0;
int nKey;
if( pKey && pKey->z && pKey->n ){
sqliteSetNString(&zKey, pKey->z, pKey->n, 0);
sqliteDequote(zKey);
nKey = strlen(zKey);
}else{
zKey = 0;
nKey = 0;
}
sqliteCodecAttach(db, db->nDb-1, zKey, nKey);
}
#endif
sqliteFree(zFile);
db->flags &= ~SQLITE_Initialized;
if( pParse->nErr ) return;
@ -117,13 +136,18 @@ void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname){
void sqliteDetach(Parse *pParse, Token *pDbname){
int i;
sqlite *db;
Vdbe *v;
Db *pDb;
v = sqliteGetVdbe(pParse);
sqliteVdbeAddOp(v, OP_Halt, 0, 0);
if( pParse->explain ) return;
db = pParse->db;
for(i=0; i<db->nDb; i++){
if( db->aDb[i].pBt==0 || db->aDb[i].zName==0 ) continue;
if( strlen(db->aDb[i].zName)!=pDbname->n ) continue;
if( sqliteStrNICmp(db->aDb[i].zName, pDbname->z, pDbname->n)==0 ) break;
pDb = &db->aDb[i];
if( pDb->pBt==0 || pDb->zName==0 ) continue;
if( strlen(pDb->zName)!=pDbname->n ) continue;
if( sqliteStrNICmp(pDb->zName, pDbname->z, pDbname->n)==0 ) break;
}
if( i>=db->nDb ){
sqliteErrorMsg(pParse, "no such database: %T", pDbname);
@ -138,10 +162,11 @@ void sqliteDetach(Parse *pParse, Token *pDbname){
return;
}
#endif /* SQLITE_OMIT_AUTHORIZATION */
sqliteBtreeClose(db->aDb[i].pBt);
db->aDb[i].pBt = 0;
sqliteFree(db->aDb[i].zName);
sqliteBtreeClose(pDb->pBt);
pDb->pBt = 0;
sqliteFree(pDb->zName);
sqliteResetInternalSchema(db, i);
if( pDb->pAux && pDb->xFreeAux ) pDb->xFreeAux(pDb->pAux);
db->nDb--;
if( i<db->nDb ){
db->aDb[i] = db->aDb[db->nDb];

View file

@ -85,12 +85,9 @@ int sqlite_set_authorizer(
** user-supplied authorization function returned an illegal value.
*/
static void sqliteAuthBadReturnCode(Parse *pParse, int rc){
char zBuf[20];
sprintf(zBuf, "(%d)", rc);
sqliteSetString(&pParse->zErrMsg, "illegal return value ", zBuf,
" from the authorization function - should be SQLITE_OK, "
"SQLITE_IGNORE, or SQLITE_DENY", (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse, "illegal return value (%d) from the "
"authorization function - should be SQLITE_OK, SQLITE_IGNORE, "
"or SQLITE_DENY", rc);
pParse->rc = SQLITE_MISUSE;
}
@ -150,13 +147,11 @@ void sqliteAuthRead(
pExpr->op = TK_NULL;
}else if( rc==SQLITE_DENY ){
if( db->nDb>2 || pExpr->iDb!=0 ){
sqliteSetString(&pParse->zErrMsg,"access to ", zDBase, ".",
pTab->zName, ".", zCol, " is prohibited", (char*)0);
sqliteErrorMsg(pParse, "access to %s.%s.%s is prohibited",
zDBase, pTab->zName, zCol);
}else{
sqliteSetString(&pParse->zErrMsg,"access to ", pTab->zName, ".",
zCol, " is prohibited", (char*)0);
sqliteErrorMsg(pParse, "access to %s.%s is prohibited", pTab->zName,zCol);
}
pParse->nErr++;
pParse->rc = SQLITE_AUTH;
}else if( rc!=SQLITE_OK ){
sqliteAuthBadReturnCode(pParse, rc);
@ -179,14 +174,13 @@ int sqliteAuthCheck(
sqlite *db = pParse->db;
int rc;
if( db->xAuth==0 ){
if( db->init.busy || db->xAuth==0 ){
return SQLITE_OK;
}
rc = db->xAuth(db->pAuthArg, code, zArg1, zArg2, zArg3, pParse->zAuthContext);
if( rc==SQLITE_DENY ){
sqliteSetString(&pParse->zErrMsg, "not authorized", (char*)0);
sqliteErrorMsg(pParse, "not authorized");
pParse->rc = SQLITE_AUTH;
pParse->nErr++;
}else if( rc!=SQLITE_OK && rc!=SQLITE_IGNORE ){
rc = SQLITE_DENY;
sqliteAuthBadReturnCode(pParse, rc);

View file

@ -210,13 +210,13 @@ struct CellHdr {
** The maximum number of database entries that can be held in a single
** page of the database.
*/
#define MX_CELL ((SQLITE_PAGE_SIZE-sizeof(PageHdr))/MIN_CELL_SIZE)
#define MX_CELL ((SQLITE_USABLE_SIZE-sizeof(PageHdr))/MIN_CELL_SIZE)
/*
** The amount of usable space on a single page of the BTree. This is the
** page size minus the overhead of the page header.
*/
#define USABLE_SPACE (SQLITE_PAGE_SIZE - sizeof(PageHdr))
#define USABLE_SPACE (SQLITE_USABLE_SIZE - sizeof(PageHdr))
/*
** The maximum amount of payload (in bytes) that can be stored locally for
@ -261,7 +261,7 @@ struct FreeBlk {
/*
** The number of bytes of payload that will fit on a single overflow page.
*/
#define OVERFLOW_SIZE (SQLITE_PAGE_SIZE-sizeof(Pgno))
#define OVERFLOW_SIZE (SQLITE_USABLE_SIZE-sizeof(Pgno))
/*
** When the key and data for a single entry in the BTree will not fit in
@ -319,7 +319,7 @@ struct FreelistInfo {
** The pageDestructor() routine handles that chore.
*/
struct MemPage {
union {
union u_page_data {
char aDisk[SQLITE_PAGE_SIZE]; /* Page data stored on disk */
PageHdr hdr; /* Overlay page header */
} u;
@ -338,7 +338,7 @@ struct MemPage {
** to the end. EXTRA_SIZE is the number of bytes of space needed to hold
** that extra information.
*/
#define EXTRA_SIZE (sizeof(MemPage)-SQLITE_PAGE_SIZE)
#define EXTRA_SIZE (sizeof(MemPage)-sizeof(union u_page_data))
/*
** Everything we need to know about an open database
@ -421,7 +421,7 @@ static int cellSize(Btree *pBt, Cell *pCell){
static void defragmentPage(Btree *pBt, MemPage *pPage){
int pc, i, n;
FreeBlk *pFBlk;
char newPage[SQLITE_PAGE_SIZE];
char newPage[SQLITE_USABLE_SIZE];
assert( sqlitepager_iswriteable(pPage) );
assert( pPage->isInit );
@ -434,7 +434,7 @@ static void defragmentPage(Btree *pBt, MemPage *pPage){
/* This routine should never be called on an overfull page. The
** following asserts verify that constraint. */
assert( Addr(pCell) > Addr(pPage) );
assert( Addr(pCell) < Addr(pPage) + SQLITE_PAGE_SIZE );
assert( Addr(pCell) < Addr(pPage) + SQLITE_USABLE_SIZE );
n = cellSize(pBt, pCell);
pCell->h.iNext = SWAB16(pBt, pc + n);
@ -442,16 +442,16 @@ static void defragmentPage(Btree *pBt, MemPage *pPage){
pPage->apCell[i] = (Cell*)&pPage->u.aDisk[pc];
pc += n;
}
assert( pPage->nFree==SQLITE_PAGE_SIZE-pc );
assert( pPage->nFree==SQLITE_USABLE_SIZE-pc );
memcpy(pPage->u.aDisk, newPage, pc);
if( pPage->nCell>0 ){
pPage->apCell[pPage->nCell-1]->h.iNext = 0;
}
pFBlk = (FreeBlk*)&pPage->u.aDisk[pc];
pFBlk->iSize = SWAB16(pBt, SQLITE_PAGE_SIZE - pc);
pFBlk->iSize = SWAB16(pBt, SQLITE_USABLE_SIZE - pc);
pFBlk->iNext = 0;
pPage->u.hdr.firstFree = SWAB16(pBt, pc);
memset(&pFBlk[1], 0, SQLITE_PAGE_SIZE - pc - sizeof(FreeBlk));
memset(&pFBlk[1], 0, SQLITE_USABLE_SIZE - pc - sizeof(FreeBlk));
}
/*
@ -483,7 +483,7 @@ static int allocateSpace(Btree *pBt, MemPage *pPage, int nByte){
pIdx = &pPage->u.hdr.firstFree;
p = (FreeBlk*)&pPage->u.aDisk[SWAB16(pBt, *pIdx)];
while( (iSize = SWAB16(pBt, p->iSize))<nByte ){
assert( cnt++ < SQLITE_PAGE_SIZE/4 );
assert( cnt++ < SQLITE_USABLE_SIZE/4 );
if( p->iNext==0 ){
defragmentPage(pBt, pPage);
pIdx = &pPage->u.hdr.firstFree;
@ -598,12 +598,12 @@ static int initPage(Bt *pBt, MemPage *pPage, Pgno pgnoThis, MemPage *pParent){
freeSpace = USABLE_SPACE;
idx = SWAB16(pBt, pPage->u.hdr.firstCell);
while( idx!=0 ){
if( idx>SQLITE_PAGE_SIZE-MIN_CELL_SIZE ) goto page_format_error;
if( idx>SQLITE_USABLE_SIZE-MIN_CELL_SIZE ) goto page_format_error;
if( idx<sizeof(PageHdr) ) goto page_format_error;
if( idx!=ROUNDUP(idx) ) goto page_format_error;
pCell = (Cell*)&pPage->u.aDisk[idx];
sz = cellSize(pBt, pCell);
if( idx+sz > SQLITE_PAGE_SIZE ) goto page_format_error;
if( idx+sz > SQLITE_USABLE_SIZE ) goto page_format_error;
freeSpace -= sz;
pPage->apCell[pPage->nCell++] = pCell;
idx = SWAB16(pBt, pCell->h.iNext);
@ -612,7 +612,7 @@ static int initPage(Bt *pBt, MemPage *pPage, Pgno pgnoThis, MemPage *pParent){
idx = SWAB16(pBt, pPage->u.hdr.firstFree);
while( idx!=0 ){
int iNext;
if( idx>SQLITE_PAGE_SIZE-sizeof(FreeBlk) ) goto page_format_error;
if( idx>SQLITE_USABLE_SIZE-sizeof(FreeBlk) ) goto page_format_error;
if( idx<sizeof(PageHdr) ) goto page_format_error;
pFBlk = (FreeBlk*)&pPage->u.aDisk[idx];
pPage->nFree += SWAB16(pBt, pFBlk->iSize);
@ -640,13 +640,13 @@ static void zeroPage(Btree *pBt, MemPage *pPage){
PageHdr *pHdr;
FreeBlk *pFBlk;
assert( sqlitepager_iswriteable(pPage) );
memset(pPage, 0, SQLITE_PAGE_SIZE);
memset(pPage, 0, SQLITE_USABLE_SIZE);
pHdr = &pPage->u.hdr;
pHdr->firstCell = 0;
pHdr->firstFree = SWAB16(pBt, sizeof(*pHdr));
pFBlk = (FreeBlk*)&pHdr[1];
pFBlk->iNext = 0;
pPage->nFree = SQLITE_PAGE_SIZE - sizeof(*pHdr);
pPage->nFree = SQLITE_USABLE_SIZE - sizeof(*pHdr);
pFBlk->iSize = SWAB16(pBt, pPage->nFree);
pPage->nCell = 0;
pPage->isOverfull = 0;
@ -697,7 +697,7 @@ int sqliteBtreeOpen(
assert( sizeof(PageHdr)==8 );
assert( sizeof(CellHdr)==12 );
assert( sizeof(FreeBlk)==4 );
assert( sizeof(OverflowPage)==SQLITE_PAGE_SIZE );
assert( sizeof(OverflowPage)==SQLITE_USABLE_SIZE );
assert( sizeof(FreelistInfo)==OVERFLOW_SIZE );
assert( sizeof(ptr)==sizeof(char*) );
assert( sizeof(uptr)==sizeof(ptr) );
@ -793,7 +793,7 @@ static int lockBtree(Btree *pBt){
PageOne *pP1 = pBt->page1;
if( strcmp(pP1->zMagic,zMagicHeader)!=0 ||
(pP1->iMagic!=MAGIC && swab32(pP1->iMagic)!=MAGIC) ){
rc = SQLITE_CORRUPT;
rc = SQLITE_NOTADB;
goto page1_init_failed;
}
pBt->needSwab = pP1->iMagic!=MAGIC;
@ -1031,10 +1031,15 @@ static int fileBtreeRollbackCkpt(Btree *pBt){
** root page of a b-tree. If it is not, then the cursor acquired
** will not work correctly.
*/
static int fileBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){
static
int fileBtreeCursor(Btree *pBt, int iTable, int wrFlag, BtCursor **ppCur){
int rc;
BtCursor *pCur, *pRing;
if( pBt->readOnly && wrFlag ){
*ppCur = 0;
return SQLITE_READONLY;
}
if( pBt->page1==0 ){
rc = lockBtree(pBt);
if( rc!=SQLITE_OK ){
@ -2082,7 +2087,7 @@ static void relinkCellList(Btree *pBt, MemPage *pPage){
pIdx = &pPage->u.hdr.firstCell;
for(i=0; i<pPage->nCell; i++){
int idx = Addr(pPage->apCell[i]) - Addr(pPage);
assert( idx>0 && idx<SQLITE_PAGE_SIZE );
assert( idx>0 && idx<SQLITE_USABLE_SIZE );
*pIdx = SWAB16(pBt, idx);
pIdx = &pPage->apCell[i]->h.iNext;
}
@ -2098,7 +2103,7 @@ static void relinkCellList(Btree *pBt, MemPage *pPage){
static void copyPage(MemPage *pTo, MemPage *pFrom){
uptr from, to;
int i;
memcpy(pTo->u.aDisk, pFrom->u.aDisk, SQLITE_PAGE_SIZE);
memcpy(pTo->u.aDisk, pFrom->u.aDisk, SQLITE_USABLE_SIZE);
pTo->pParent = 0;
pTo->isInit = 1;
pTo->nCell = pFrom->nCell;
@ -2108,7 +2113,7 @@ static void copyPage(MemPage *pTo, MemPage *pFrom){
from = Addr(pFrom);
for(i=0; i<pTo->nCell; i++){
uptr x = Addr(pFrom->apCell[i]);
if( x>from && x<from+SQLITE_PAGE_SIZE ){
if( x>from && x<from+SQLITE_USABLE_SIZE ){
*((uptr*)&pTo->apCell[i]) = x + to - from;
}else{
pTo->apCell[i] = pFrom->apCell[i];
@ -2203,7 +2208,7 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
** underfull.
*/
assert( sqlitepager_iswriteable(pPage) );
if( !pPage->isOverfull && pPage->nFree<SQLITE_PAGE_SIZE/2
if( !pPage->isOverfull && pPage->nFree<SQLITE_USABLE_SIZE/2
&& pPage->nCell>=2){
relinkCellList(pBt, pPage);
return SQLITE_OK;
@ -2229,7 +2234,7 @@ static int balance(Btree *pBt, MemPage *pPage, BtCursor *pCur){
pgnoChild = SWAB32(pBt, pPage->u.hdr.rightChild);
rc = sqlitepager_get(pBt->pPager, pgnoChild, (void**)&pChild);
if( rc ) return rc;
memcpy(pPage, pChild, SQLITE_PAGE_SIZE);
memcpy(pPage, pChild, SQLITE_USABLE_SIZE);
pPage->isInit = 0;
rc = initPage(pBt, pPage, sqlitepager_pagenumber(pPage), 0);
assert( rc==SQLITE_OK );
@ -2724,7 +2729,8 @@ static int fileBtreeDelete(BtCursor *pCur){
getTempCursor(pCur, &leafCur);
rc = fileBtreeNext(&leafCur, &notUsed);
if( rc!=SQLITE_OK ){
return SQLITE_CORRUPT;
if( rc!=SQLITE_NOMEM ) rc = SQLITE_CORRUPT;
return rc;
}
rc = sqlitepager_write(leafCur.pPage);
if( rc ) return rc;
@ -2907,7 +2913,7 @@ static int copyCell(Btree *pBtFrom, BTree *pBtTo, Cell *pCell){
if( rc==SQLITE_OK ){
rc = sqlitepager_write(pNew);
if( rc==SQLITE_OK ){
memcpy(pNew, pOvfl, SQLITE_PAGE_SIZE);
memcpy(pNew, pOvfl, SQLITE_USABLE_SIZE);
*pPrev = SWAB32(pBtTo, new);
if( pPrevPg ){
sqlitepager_unref(pPrevPg);
@ -2950,7 +2956,7 @@ static int copyDatabasePage(
rc = sqlitepager_write(pPage);
}
if( rc==SQLITE_OK ){
memcpy(pPage, pPageFrom, SQLITE_PAGE_SIZE);
memcpy(pPage, pPageFrom, SQLITE_USABLE_SIZE);
idx = SWAB16(pBt, pPage->u.hdr.firstCell);
while( idx>0 ){
pCell = (Cell*)&pPage->u.aDisk[idx];
@ -3040,7 +3046,7 @@ static int fileBtreePageDump(Btree *pBt, int pgno, int recursive){
if( recursive ) printf("PAGE %d:\n", pgno);
i = 0;
idx = SWAB16(pBt, pPage->u.hdr.firstCell);
while( idx>0 && idx<=SQLITE_PAGE_SIZE-MIN_CELL_SIZE ){
while( idx>0 && idx<=SQLITE_USABLE_SIZE-MIN_CELL_SIZE ){
Cell *pCell = (Cell*)&pPage->u.aDisk[idx];
int sz = cellSize(pBt, pCell);
sprintf(range,"%d..%d", idx, idx+sz-1);
@ -3070,7 +3076,7 @@ static int fileBtreePageDump(Btree *pBt, int pgno, int recursive){
nFree = 0;
i = 0;
idx = SWAB16(pBt, pPage->u.hdr.firstFree);
while( idx>0 && idx<SQLITE_PAGE_SIZE ){
while( idx>0 && idx<SQLITE_USABLE_SIZE ){
FreeBlk *p = (FreeBlk*)&pPage->u.aDisk[idx];
sprintf(range,"%d..%d", idx, idx+p->iSize-1);
nFree += SWAB16(pBt, p->iSize);
@ -3084,7 +3090,7 @@ static int fileBtreePageDump(Btree *pBt, int pgno, int recursive){
}
if( recursive && pPage->u.hdr.rightChild!=0 ){
idx = SWAB16(pBt, pPage->u.hdr.firstCell);
while( idx>0 && idx<SQLITE_PAGE_SIZE-MIN_CELL_SIZE ){
while( idx>0 && idx<SQLITE_USABLE_SIZE-MIN_CELL_SIZE ){
Cell *pCell = (Cell*)&pPage->u.aDisk[idx];
fileBtreePageDump(pBt, SWAB32(pBt, pCell->h.leftChild), 1);
idx = SWAB16(pBt, pCell->h.iNext);
@ -3129,7 +3135,7 @@ static int fileBtreeCursorDump(BtCursor *pCur, int *aResult){
aResult[4] = pPage->nFree;
cnt = 0;
idx = SWAB16(pBt, pPage->u.hdr.firstFree);
while( idx>0 && idx<SQLITE_PAGE_SIZE ){
while( idx>0 && idx<SQLITE_USABLE_SIZE ){
cnt++;
idx = SWAB16(pBt, ((FreeBlk*)&pPage->u.aDisk[idx])->iNext);
}
@ -3139,7 +3145,6 @@ static int fileBtreeCursorDump(BtCursor *pCur, int *aResult){
}
#endif
#ifdef SQLITE_TEST
/*
** Return the pager associated with a BTree. This routine is used for
** testing and debugging only.
@ -3147,7 +3152,6 @@ static int fileBtreeCursorDump(BtCursor *pCur, int *aResult){
static Pager *fileBtreePager(Btree *pBt){
return pBt->pPager;
}
#endif
/*
** This structure is passed around through all the sanity checking routines
@ -3293,7 +3297,7 @@ static int checkTreePage(
Btree *pBt;
char zMsg[100];
char zContext[100];
char hit[SQLITE_PAGE_SIZE];
char hit[SQLITE_USABLE_SIZE];
/* Check that the page exists
*/
@ -3369,19 +3373,19 @@ static int checkTreePage(
*/
memset(hit, 0, sizeof(hit));
memset(hit, 1, sizeof(PageHdr));
for(i=SWAB16(pBt, pPage->u.hdr.firstCell); i>0 && i<SQLITE_PAGE_SIZE; ){
for(i=SWAB16(pBt, pPage->u.hdr.firstCell); i>0 && i<SQLITE_USABLE_SIZE; ){
Cell *pCell = (Cell*)&pPage->u.aDisk[i];
int j;
for(j=i+cellSize(pBt, pCell)-1; j>=i; j--) hit[j]++;
i = SWAB16(pBt, pCell->h.iNext);
}
for(i=SWAB16(pBt,pPage->u.hdr.firstFree); i>0 && i<SQLITE_PAGE_SIZE; ){
for(i=SWAB16(pBt,pPage->u.hdr.firstFree); i>0 && i<SQLITE_USABLE_SIZE; ){
FreeBlk *pFBlk = (FreeBlk*)&pPage->u.aDisk[i];
int j;
for(j=i+SWAB16(pBt,pFBlk->iSize)-1; j>=i; j--) hit[j]++;
i = SWAB16(pBt,pFBlk->iNext);
}
for(i=0; i<SQLITE_PAGE_SIZE; i++){
for(i=0; i<SQLITE_USABLE_SIZE; i++){
if( hit[i]==0 ){
sprintf(zMsg, "Unused space at byte %d of page %d", i, iPage);
checkAppendMsg(pCheck, zMsg, 0);
@ -3396,9 +3400,9 @@ static int checkTreePage(
/* Check that free space is kept to a minimum
*/
#if 0
if( pParent && pParent->nCell>2 && pPage->nFree>3*SQLITE_PAGE_SIZE/4 ){
if( pParent && pParent->nCell>2 && pPage->nFree>3*SQLITE_USABLE_SIZE/4 ){
sprintf(zMsg, "free space (%d) greater than max (%d)", pPage->nFree,
SQLITE_PAGE_SIZE/3);
SQLITE_USABLE_SIZE/3);
checkAppendMsg(pCheck, zContext, zMsg);
}
#endif
@ -3500,7 +3504,7 @@ static int fileBtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
if( !pBtTo->inTrans || !pBtFrom->inTrans ) return SQLITE_ERROR;
if( pBtTo->needSwab!=pBtFrom->needSwab ) return SQLITE_ERROR;
if( pBtTo->pCursor ) return SQLITE_BUSY;
memcpy(pBtTo->page1, pBtFrom->page1, SQLITE_PAGE_SIZE);
memcpy(pBtTo->page1, pBtFrom->page1, SQLITE_USABLE_SIZE);
rc = sqlitepager_overwrite(pBtTo->pPager, 1, pBtFrom->page1);
nToPage = sqlitepager_pagecount(pBtTo->pPager);
nPage = sqlitepager_pagecount(pBtFrom->pPager);
@ -3555,9 +3559,9 @@ static BtOps sqliteBtreeOps = {
fileBtreeIntegrityCheck,
fileBtreeGetFilename,
fileBtreeCopyFile,
fileBtreePager,
#ifdef SQLITE_TEST
fileBtreePageDump,
fileBtreePager
#endif
};
static BtCursorOps sqliteBtreeCursorOps = {

View file

@ -57,9 +57,9 @@ struct BtOps {
char *(*IntegrityCheck)(Btree*, int*, int);
const char *(*GetFilename)(Btree*);
int (*Copyfile)(Btree*,Btree*);
struct Pager *(*Pager)(Btree*);
#ifdef SQLITE_TEST
int (*PageDump)(Btree*, int, int);
struct Pager *(*Pager)(Btree*);
#endif
};
@ -142,13 +142,13 @@ int sqliteRbtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree);
(btOps(pBt)->IntegrityCheck(pBt, aRoot, nRoot))
#define sqliteBtreeGetFilename(pBt) (btOps(pBt)->GetFilename(pBt))
#define sqliteBtreeCopyFile(pBt1, pBt2) (btOps(pBt1)->Copyfile(pBt1, pBt2))
#define sqliteBtreePager(pBt) (btOps(pBt)->Pager(pBt))
#ifdef SQLITE_TEST
#define sqliteBtreePageDump(pBt, pgno, recursive)\
(btOps(pBt)->PageDump(pBt, pgno, recursive))
#define sqliteBtreeCursorDump(pCur, aResult)\
(btCOps(pCur)->CursorDump(pCur, aResult))
#define sqliteBtreePager(pBt) (btOps(pBt)->Pager(pBt))
int btree_native_byte_order;
#endif /* SQLITE_TEST */

View file

@ -38,7 +38,7 @@ void sqliteBeginParse(Parse *pParse, int explainFlag){
sqlite *db = pParse->db;
int i;
pParse->explain = explainFlag;
if((db->flags & SQLITE_Initialized)==0 && pParse->initFlag==0 ){
if((db->flags & SQLITE_Initialized)==0 && db->init.busy==0 ){
int rc = sqliteInit(db, &pParse->zErrMsg);
if( rc!=SQLITE_OK ){
pParse->rc = rc;
@ -54,17 +54,6 @@ void sqliteBeginParse(Parse *pParse, int explainFlag){
pParse->nVar = 0;
}
/*
** This is a fake callback procedure used when sqlite_exec() is
** invoked with a NULL callback pointer. If we pass a NULL callback
** pointer into sqliteVdbeExec() it will return at every OP_Callback,
** which we do not want it to do. So we substitute a pointer to this
** procedure in place of the NULL.
*/
static int fakeCallback(void *NotUsed, int n, char **az1, char **az2){
return 0;
}
/*
** This routine is called after a single SQL statement has been
** parsed and we want to execute the VDBE code to implement
@ -76,36 +65,20 @@ static int fakeCallback(void *NotUsed, int n, char **az1, char **az2){
** no VDBE code was generated.
*/
void sqliteExec(Parse *pParse){
int rc = SQLITE_OK;
sqlite *db = pParse->db;
Vdbe *v = pParse->pVdbe;
int (*xCallback)(void*,int,char**,char**);
if( v==0 && (v = sqliteGetVdbe(pParse))!=0 ){
sqliteVdbeAddOp(v, OP_Halt, 0, 0);
}
if( sqlite_malloc_failed ) return;
xCallback = pParse->xCallback;
if( xCallback==0 && pParse->useCallback ) xCallback = fakeCallback;
if( v && pParse->nErr==0 ){
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
sqliteVdbeTrace(v, trace);
sqliteVdbeMakeReady(v, pParse->nVar, xCallback, pParse->pArg,
pParse->explain);
if( pParse->useCallback ){
if( pParse->explain ){
rc = sqliteVdbeList(v);
db->next_cookie = db->aDb[0].schema_cookie;
}else{
sqliteVdbeExec(v);
}
rc = sqliteVdbeFinalize(v, &pParse->zErrMsg);
if( rc ) pParse->nErr++;
pParse->pVdbe = 0;
pParse->rc = rc;
if( rc ) pParse->nErr++;
}else{
pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
}
sqliteVdbeMakeReady(v, pParse->nVar, pParse->explain);
pParse->rc = pParse->nErr ? SQLITE_ERROR : SQLITE_DONE;
pParse->colNamesSet = 0;
}else if( pParse->useCallback==0 ){
}else if( pParse->rc==SQLITE_OK ){
pParse->rc = SQLITE_ERROR;
}
pParse->nTab = 0;
@ -240,7 +213,7 @@ void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){
**
** If iDb<=0 then reset the internal schema tables for all database
** files. If iDb>=2 then reset the internal schema for only the
** single file indicates.
** single file indicated.
*/
void sqliteResetInternalSchema(sqlite *db, int iDb){
HashElem *pElem;
@ -280,10 +253,18 @@ void sqliteResetInternalSchema(sqlite *db, int iDb){
** schema hash tables and therefore do not have to make any changes
** to any of those tables.
*/
for(i=0; i<db->nDb; i++){
struct Db *pDb = &db->aDb[i];
if( pDb->pBt==0 ){
if( pDb->pAux && pDb->xFreeAux ) pDb->xFreeAux(pDb->pAux);
pDb->pAux = 0;
}
}
for(i=j=2; i<db->nDb; i++){
if( db->aDb[i].pBt==0 ){
sqliteFree(db->aDb[i].zName);
db->aDb[i].zName = 0;
struct Db *pDb = &db->aDb[i];
if( pDb->pBt==0 ){
sqliteFree(pDb->zName);
pDb->zName = 0;
continue;
}
if( j<i ){
@ -456,7 +437,7 @@ void sqliteStartTable(
pParse->sFirstToken = *pStart;
zName = sqliteTableNameFromToken(pName);
if( zName==0 ) return;
if( pParse->iDb==1 ) isTemp = 1;
if( db->init.iDb==1 ) isTemp = 1;
#ifndef SQLITE_OMIT_AUTHORIZATION
assert( (isTemp & 1)==isTemp );
{
@ -493,17 +474,16 @@ void sqliteStartTable(
if( isTemp && db->aDb[1].pBt==0 && !pParse->explain ){
int rc = sqliteBtreeFactory(db, 0, 0, MAX_PAGES, &db->aDb[1].pBt);
if( rc!=SQLITE_OK ){
sqliteSetString(&pParse->zErrMsg, "unable to open a temporary database "
"file for storing temporary tables", (char*)0);
sqliteErrorMsg(pParse, "unable to open a temporary database "
"file for storing temporary tables");
pParse->nErr++;
return;
}
if( db->flags & SQLITE_InTrans ){
rc = sqliteBtreeBeginTrans(db->aDb[1].pBt);
if( rc!=SQLITE_OK ){
sqliteSetNString(&pParse->zErrMsg, "unable to get a write lock on "
"the temporary database file", 0);
pParse->nErr++;
sqliteErrorMsg(pParse, "unable to get a write lock on "
"the temporary database file");
return;
}
}
@ -517,20 +497,16 @@ void sqliteStartTable(
** an existing temporary table, that is not an error.
*/
pTable = sqliteFindTable(db, zName, 0);
iDb = isTemp ? 1 : pParse->iDb;
if( pTable!=0 && (pTable->iDb==iDb || !pParse->initFlag) ){
sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n,
" already exists", 0, 0);
iDb = isTemp ? 1 : db->init.iDb;
if( pTable!=0 && (pTable->iDb==iDb || !db->init.busy) ){
sqliteErrorMsg(pParse, "table %T already exists", pName);
sqliteFree(zName);
pParse->nErr++;
return;
}
if( (pIdx = sqliteFindIndex(db, zName, 0))!=0 &&
(pIdx->iDb==0 || !pParse->initFlag) ){
sqliteSetString(&pParse->zErrMsg, "there is already an index named ",
zName, (char*)0);
(pIdx->iDb==0 || !db->init.busy) ){
sqliteErrorMsg(pParse, "there is already an index named %s", zName);
sqliteFree(zName);
pParse->nErr++;
return;
}
pTable = sqliteMalloc( sizeof(Table) );
@ -555,7 +531,7 @@ void sqliteStartTable(
** indices. Hence, the record number for the table must be allocated
** now.
*/
if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){
if( !db->init.busy && (v = sqliteGetVdbe(pParse))!=0 ){
sqliteBeginWriteOperation(pParse, 0, isTemp);
if( !isTemp ){
sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0);
@ -588,8 +564,7 @@ void sqliteAddColumn(Parse *pParse, Token *pName){
sqliteDequote(z);
for(i=0; i<p->nCol; i++){
if( sqliteStrICmp(z, p->aCol[i].zName)==0 ){
sqliteSetString(&pParse->zErrMsg, "duplicate column name: ", z, (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse, "duplicate column name: %s", z);
sqliteFree(z);
return;
}
@ -708,9 +683,8 @@ void sqliteAddPrimaryKey(Parse *pParse, IdList *pList, int onError){
int iCol = -1, i;
if( pTab==0 ) goto primary_key_exit;
if( pTab->hasPrimKey ){
sqliteSetString(&pParse->zErrMsg, "table \"", pTab->zName,
"\" has more than one primary key", (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse,
"table \"%s\" has more than one primary key", pTab->zName);
goto primary_key_exit;
}
pTab->hasPrimKey = 1;
@ -753,34 +727,16 @@ primary_key_exit:
*/
int sqliteCollateType(const char *zType, int nType){
int i;
for(i=0; i<nType-1; i++){
switch( zType[i] ){
case 'b':
case 'B': {
if( i<nType-3 && sqliteStrNICmp(&zType[i],"blob",4)==0 ){
return SQLITE_SO_TEXT;
}
break;
}
case 'c':
case 'C': {
if( i<nType-3 && (sqliteStrNICmp(&zType[i],"char",4)==0 ||
sqliteStrNICmp(&zType[i],"clob",4)==0)
){
return SQLITE_SO_TEXT;
}
break;
}
case 'x':
case 'X': {
if( i>=2 && sqliteStrNICmp(&zType[i-2],"text",4)==0 ){
return SQLITE_SO_TEXT;
}
break;
}
default: {
break;
}
for(i=0; i<nType-3; i++){
int c = *(zType++) | 0x60;
if( (c=='b' || c=='c') && sqliteStrNICmp(zType, "lob", 3)==0 ){
return SQLITE_SO_TEXT;
}
if( c=='c' && sqliteStrNICmp(zType, "har", 3)==0 ){
return SQLITE_SO_TEXT;
}
if( c=='t' && sqliteStrNICmp(zType, "ext", 3)==0 ){
return SQLITE_SO_TEXT;
}
}
return SQLITE_SO_NUM;
@ -819,7 +775,9 @@ void sqliteAddCollateType(Parse *pParse, int collType){
*/
void sqliteChangeCookie(sqlite *db, Vdbe *v){
if( db->next_cookie==db->aDb[0].schema_cookie ){
db->next_cookie = db->aDb[0].schema_cookie + sqliteRandomByte() + 1;
unsigned char r;
sqliteRandomness(1, &r);
db->next_cookie = db->aDb[0].schema_cookie + r + 1;
db->flags |= SQLITE_InternChanges;
sqliteVdbeAddOp(v, OP_Integer, db->next_cookie, 0);
sqliteVdbeAddOp(v, OP_SetCookie, 0, 0);
@ -910,8 +868,8 @@ static char *createTableStmt(Table *p){
** is added to the internal hash tables, assuming no errors have
** occurred.
**
** An entry for the table is made in the master table on disk,
** unless this is a temporary table or initFlag==1. When initFlag==1,
** An entry for the table is made in the master table on disk, unless
** this is a temporary table or db->init.busy==1. When db->init.busy==1
** it means we are reading the sqlite_master table because we just
** connected to the database or because the sqlite_master table has
** recently changes, so the entry for this table already exists in
@ -944,14 +902,14 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
sqliteDeleteTable(0, pSelTab);
}
/* If the initFlag is 1 it means we are reading the SQL off the
/* If the db->init.busy is 1 it means we are reading the SQL off the
** "sqlite_master" or "sqlite_temp_master" table on the disk.
** So do not write to the disk again. Extract the root page number
** for the table from the pParse->newTnum field. (The page number
** for the table from the db->init.newTnum field. (The page number
** should have been put there by the sqliteOpenCb routine.)
*/
if( pParse->initFlag ){
p->tnum = pParse->newTnum;
if( db->init.busy ){
p->tnum = db->init.newTnum;
}
/* If not initializing, then create a record for the new table
@ -961,7 +919,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
** If this is a TEMPORARY table, write the entry into the auxiliary
** file instead of into the main database file.
*/
if( !pParse->initFlag ){
if( !db->init.busy ){
int n;
Vdbe *v;
@ -969,24 +927,16 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
if( v==0 ) return;
if( p->pSelect==0 ){
/* A regular table */
sqliteVdbeAddOp(v, OP_CreateTable, 0, p->iDb);
sqliteVdbeChangeP3(v, -1, (char *)&p->tnum, P3_POINTER);
sqliteVdbeOp3(v, OP_CreateTable, 0, p->iDb, (char*)&p->tnum, P3_POINTER);
}else{
/* A view */
sqliteVdbeAddOp(v, OP_Integer, 0, 0);
}
p->tnum = 0;
sqliteVdbeAddOp(v, OP_Pull, 1, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
if( p->pSelect==0 ){
sqliteVdbeChangeP3(v, -1, "table", P3_STATIC);
}else{
sqliteVdbeChangeP3(v, -1, "view", P3_STATIC);
}
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0, p->pSelect==0?"table":"view", P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0, p->zName, 0);
sqliteVdbeOp3(v, OP_String, 0, 0, p->zName, 0);
sqliteVdbeAddOp(v, OP_Dup, 4, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
if( pSelect ){
@ -1072,7 +1022,7 @@ void sqliteCreateView(
*/
p->pSelect = sqliteSelectDup(pSelect);
sqliteSelectDelete(pSelect);
if( !pParse->initFlag ){
if( !pParse->db->init.busy ){
sqliteViewGetColumnNames(pParse, p);
}
@ -1084,7 +1034,7 @@ void sqliteCreateView(
sEnd.z += sEnd.n;
}
sEnd.n = 0;
n = (char *) sEnd.z - (char *) pBegin->z;
n = sEnd.z - pBegin->z;
z = pBegin->z;
while( n>0 && (z[n-1]==';' || isspace(z[n-1])) ){ n--; }
sEnd.z = &z[n-1];
@ -1098,7 +1048,7 @@ void sqliteCreateView(
/*
** The Table structure pTable is really a VIEW. Fill in the names of
** the columns of the view in the pTable structure. Return the number
** of errors. If an error is seen leave an error message in pPare->zErrMsg.
** of errors. If an error is seen leave an error message in pParse->zErrMsg.
*/
int sqliteViewGetColumnNames(Parse *pParse, Table *pTable){
ExprList *pEList;
@ -1124,9 +1074,7 @@ int sqliteViewGetColumnNames(Parse *pParse, Table *pTable){
** should always fail. But we will leave it in place just to be safe.
*/
if( pTable->nCol<0 ){
sqliteSetString(&pParse->zErrMsg, "view ", pTable->zName,
" is circularly defined", (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse, "view %s is circularly defined", pTable->zName);
return 1;
}
@ -1176,12 +1124,12 @@ int sqliteViewGetColumnNames(Parse *pParse, Table *pTable){
*/
static void sqliteViewResetColumnNames(Table *pTable){
int i;
if( pTable==0 || pTable->pSelect==0 ) return;
if( pTable->nCol==0 ) return;
for(i=0; i<pTable->nCol; i++){
sqliteFree(pTable->aCol[i].zName);
sqliteFree(pTable->aCol[i].zDflt);
sqliteFree(pTable->aCol[i].zType);
Column *pCol;
assert( pTable!=0 && pTable->pSelect!=0 );
for(i=0, pCol=pTable->aCol; i<pTable->nCol; i++, pCol++){
sqliteFree(pCol->zName);
sqliteFree(pCol->zDflt);
sqliteFree(pCol->zType);
}
sqliteFree(pTable->aCol);
pTable->aCol = 0;
@ -1215,9 +1163,7 @@ Table *sqliteTableFromToken(Parse *pParse, Token *pTok){
pTab = sqliteFindTable(pParse->db, zName, 0);
sqliteFree(zName);
if( pTab==0 ){
sqliteSetNString(&pParse->zErrMsg, "no such table: ", 0,
pTok->z, pTok->n, 0);
pParse->nErr++;
sqliteErrorMsg(pParse, "no such table: %T", pTok);
}
return pTab;
}
@ -1268,21 +1214,16 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
}
#endif
if( pTable->readOnly ){
sqliteSetString(&pParse->zErrMsg, "table ", pTable->zName,
" may not be dropped", (char*)0);
sqliteErrorMsg(pParse, "table %s may not be dropped", pTable->zName);
pParse->nErr++;
return;
}
if( isView && pTable->pSelect==0 ){
sqliteSetString(&pParse->zErrMsg, "use DROP TABLE to delete table ",
pTable->zName, (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse, "use DROP TABLE to delete table %s", pTable->zName);
return;
}
if( !isView && pTable->pSelect ){
sqliteSetString(&pParse->zErrMsg, "use DROP VIEW to delete view ",
pTable->zName, (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse, "use DROP VIEW to delete view %s", pTable->zName);
return;
}
@ -1291,7 +1232,7 @@ void sqliteDropTable(Parse *pParse, Token *pName, int isView){
*/
v = sqliteGetVdbe(pParse);
if( v ){
static VdbeOp dropTable[] = {
static VdbeOpList dropTable[] = {
{ OP_Rewind, 0, ADDR(8), 0},
{ OP_String, 0, 0, 0}, /* 1 */
{ OP_MemStore, 1, 1, 0},
@ -1425,19 +1366,16 @@ void sqliteCreateForeignKey(
int iCol = p->nCol-1;
if( iCol<0 ) goto fk_end;
if( pToCol && pToCol->nId!=1 ){
sqliteSetNString(&pParse->zErrMsg, "foreign key on ", -1,
p->aCol[iCol].zName, -1,
" should reference only one column of table ", -1,
pTo->z, pTo->n, 0);
pParse->nErr++;
sqliteErrorMsg(pParse, "foreign key on %s"
" should reference only one column of table %T",
p->aCol[iCol].zName, pTo);
goto fk_end;
}
nCol = 1;
}else if( pToCol && pToCol->nId!=pFromCol->nId ){
sqliteSetString(&pParse->zErrMsg,
sqliteErrorMsg(pParse,
"number of columns in foreign key does not match the number of "
"columns in the referenced table", (char*)0);
pParse->nErr++;
"columns in the referenced table");
goto fk_end;
}else{
nCol = pFromCol->nId;
@ -1473,9 +1411,9 @@ void sqliteCreateForeignKey(
}
}
if( j>=p->nCol ){
sqliteSetString(&pParse->zErrMsg, "unknown column \"",
pFromCol->a[i].zName, "\" in foreign key definition", (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse,
"unknown column \"%s\" in foreign key definition",
pFromCol->a[i].zName);
goto fk_end;
}
}
@ -1550,8 +1488,8 @@ void sqliteCreateIndex(
sqlite *db = pParse->db;
if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
if( pParse->initFlag
&& sqliteFixInit(&sFix, pParse, pParse->iDb, "index", pName)
if( db->init.busy
&& sqliteFixInit(&sFix, pParse, db->init.iDb, "index", pName)
&& sqliteFixSrcList(&sFix, pTable)
){
goto exit_create_index;
@ -1570,20 +1508,15 @@ void sqliteCreateIndex(
}
if( pTab==0 || pParse->nErr ) goto exit_create_index;
if( pTab->readOnly ){
sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
" may not be indexed", (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse, "table %s may not be indexed", pTab->zName);
goto exit_create_index;
}
if( pTab->iDb>=2 && pParse->initFlag==0 ){
sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
" may not have indices added", (char*)0);
pParse->nErr++;
if( pTab->iDb>=2 && db->init.busy==0 ){
sqliteErrorMsg(pParse, "table %s may not have indices added", pTab->zName);
goto exit_create_index;
}
if( pTab->pSelect ){
sqliteSetString(&pParse->zErrMsg, "views may not be indexed", (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse, "views may not be indexed");
goto exit_create_index;
}
isTemp = pTab->iDb==1;
@ -1601,21 +1534,17 @@ void sqliteCreateIndex(
** dealing with a primary key or UNIQUE constraint. We have to invent our
** own name.
*/
if( pName && !pParse->initFlag ){
if( pName && !db->init.busy ){
Index *pISameName; /* Another index with the same name */
Table *pTSameName; /* A table with same name as the index */
zName = sqliteStrNDup(pName->z, pName->n);
if( zName==0 ) goto exit_create_index;
if( (pISameName = sqliteFindIndex(db, zName, 0))!=0 ){
sqliteSetString(&pParse->zErrMsg, "index ", zName,
" already exists", (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse, "index %s already exists", zName);
goto exit_create_index;
}
if( (pTSameName = sqliteFindTable(db, zName, 0))!=0 ){
sqliteSetString(&pParse->zErrMsg, "there is already a table named ",
zName, (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse, "there is already a table named %s", zName);
goto exit_create_index;
}
}else if( pName==0 ){
@ -1637,7 +1566,7 @@ void sqliteCreateIndex(
{
const char *zDb = db->aDb[pTab->iDb].zName;
assert( pTab->iDb==pParse->iDb || isTemp );
assert( pTab->iDb==db->init.iDb || isTemp );
if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
goto exit_create_index;
}
@ -1673,7 +1602,7 @@ void sqliteCreateIndex(
pIndex->nColumn = pList->nId;
pIndex->onError = onError;
pIndex->autoIndex = pName==0;
pIndex->iDb = isTemp ? 1 : pParse->iDb;
pIndex->iDb = isTemp ? 1 : db->init.iDb;
/* Scan the names of the columns of the table to be indexed and
** load the column indices into the Index structure. Report an error
@ -1684,9 +1613,8 @@ void sqliteCreateIndex(
if( sqliteStrICmp(pList->a[i].zName, pTab->aCol[j].zName)==0 ) break;
}
if( j>=pTab->nCol ){
sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
" has no column named ", pList->a[i].zName, (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse, "table %s has no column named %s",
pTab->zName, pList->a[i].zName);
sqliteFree(pIndex);
goto exit_create_index;
}
@ -1726,20 +1654,20 @@ void sqliteCreateIndex(
pOther->pNext = pIndex;
}
/* If the initFlag is 1 it means we are reading the SQL off the
/* If the db->init.busy is 1 it means we are reading the SQL off the
** "sqlite_master" table on the disk. So do not write to the disk
** again. Extract the table number from the pParse->newTnum field.
** again. Extract the table number from the db->init.newTnum field.
*/
if( pParse->initFlag && pTable!=0 ){
pIndex->tnum = pParse->newTnum;
if( db->init.busy && pTable!=0 ){
pIndex->tnum = db->init.newTnum;
}
/* If the initFlag is 0 then create the index on disk. This
/* If the db->init.busy is 0 then create the index on disk. This
** involves writing the index into the master table and filling in the
** index with the current table contents.
**
** The initFlag is 0 when the user first enters a CREATE INDEX
** command. The initFlag is 1 when a database is opened and
** The db->init.busy is 0 when the user first enters a CREATE INDEX
** command. db->init.busy is 1 when a database is opened and
** CREATE INDEX statements are read out of the master table. In
** the latter case the index already exists on disk, which is why
** we don't want to recreate it.
@ -1749,7 +1677,7 @@ void sqliteCreateIndex(
** has just been created, it contains no data and the index initialization
** step can be skipped.
*/
else if( pParse->initFlag==0 ){
else if( db->init.busy==0 ){
int n;
Vdbe *v;
int lbl1, lbl2;
@ -1763,19 +1691,17 @@ void sqliteCreateIndex(
sqliteOpenMasterTable(v, isTemp);
}
sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, "index", P3_STATIC);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pIndex->zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, isTemp);
sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, P3_POINTER);
sqliteVdbeOp3(v, OP_String, 0, 0, "index", P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0, pIndex->zName, 0);
sqliteVdbeOp3(v, OP_String, 0, 0, pTab->zName, 0);
sqliteVdbeOp3(v, OP_CreateIndex, 0, isTemp,(char*)&pIndex->tnum,P3_POINTER);
pIndex->tnum = 0;
if( pTable ){
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
sqliteVdbeAddOp(v, OP_Integer, isTemp, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0);
sqliteVdbeCode(v,
OP_Dup, 0, 0,
OP_Integer, isTemp, 0,
OP_OpenWrite, 1, 0,
0);
}
addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
if( pStart && pEnd ){
@ -1786,8 +1712,7 @@ void sqliteCreateIndex(
sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
if( pTable ){
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, 2, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
sqliteVdbeOp3(v, OP_OpenRead, 2, pTab->tnum, pTab->zName, 0);
lbl2 = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_Rewind, 2, lbl2);
lbl1 = sqliteVdbeAddOp(v, OP_Recno, 2, 0);
@ -1801,8 +1726,8 @@ void sqliteCreateIndex(
}
sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0);
if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIndex);
sqliteVdbeAddOp(v, OP_IdxPut, 1, pIndex->onError!=OE_None);
sqliteVdbeChangeP3(v, -1, "indexed columns are not unique", P3_STATIC);
sqliteVdbeOp3(v, OP_IdxPut, 1, pIndex->onError!=OE_None,
"indexed columns are not unique", P3_STATIC);
sqliteVdbeAddOp(v, OP_Next, 2, lbl1);
sqliteVdbeResolveLabel(v, lbl2);
sqliteVdbeAddOp(v, OP_Close, 2, 0);
@ -1870,7 +1795,7 @@ void sqliteDropIndex(Parse *pParse, SrcList *pName){
/* Generate code to remove the index and from the master table */
v = sqliteGetVdbe(pParse);
if( v ){
static VdbeOp dropIndex[] = {
static VdbeOpList dropIndex[] = {
{ OP_Rewind, 0, ADDR(9), 0},
{ OP_String, 0, 0, 0}, /* 1 */
{ OP_MemStore, 1, 1, 0},
@ -2102,8 +2027,10 @@ void sqliteBeginTransaction(Parse *pParse, int onError){
return;
}
sqliteBeginWriteOperation(pParse, 0, 0);
db->flags |= SQLITE_InTrans;
db->onError = onError;
if( !pParse->explain ){
db->flags |= SQLITE_InTrans;
db->onError = onError;
}
}
/*
@ -2119,9 +2046,13 @@ void sqliteCommitTransaction(Parse *pParse){
sqliteErrorMsg(pParse, "cannot commit - no transaction is active");
return;
}
db->flags &= ~SQLITE_InTrans;
if( !pParse->explain ){
db->flags &= ~SQLITE_InTrans;
}
sqliteEndWriteOperation(pParse);
db->onError = OE_Default;
if( !pParse->explain ){
db->onError = OE_Default;
}
}
/*
@ -2142,8 +2073,10 @@ void sqliteRollbackTransaction(Parse *pParse){
if( v ){
sqliteVdbeAddOp(v, OP_Rollback, 0, 0);
}
db->flags &= ~SQLITE_InTrans;
db->onError = OE_Default;
if( !pParse->explain ){
db->flags &= ~SQLITE_InTrans;
db->onError = OE_Default;
}
}
/*

View file

@ -37,7 +37,6 @@ void sqliteCopy(
int i;
Vdbe *v;
int addr, end;
Index *pIdx;
char *zFile = 0;
const char *zDb;
sqlite *db = pParse->db;
@ -58,18 +57,9 @@ void sqliteCopy(
v = sqliteGetVdbe(pParse);
if( v ){
sqliteBeginWriteOperation(pParse, 1, pTab->iDb);
addr = sqliteVdbeAddOp(v, OP_FileOpen, 0, 0);
sqliteVdbeChangeP3(v, addr, pFilename->z, pFilename->n);
addr = sqliteVdbeOp3(v, OP_FileOpen, 0, 0, pFilename->z, pFilename->n);
sqliteVdbeDequoteP3(v, addr);
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, 0, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
assert( pIdx->iDb==1 || pIdx->iDb==pTab->iDb );
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, i, pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
}
sqliteOpenTableAndIndices(pParse, pTab, 0);
if( db->flags & SQLITE_CountRows ){
sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */
}
@ -107,7 +97,7 @@ void sqliteCopy(
sqliteVdbeAddOp(v, OP_Noop, 0, 0);
sqliteEndWriteOperation(pParse);
if( db->flags & SQLITE_CountRows ){
sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
sqliteVdbeAddOp(v, OP_ColumnName, 0, 1);
sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC);
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
}

View file

@ -47,7 +47,6 @@
** Willmann-Bell, Inc
** Richmond, Virginia (USA)
*/
#ifndef SQLITE_OMIT_DATETIME_FUNCS
#include "os.h"
#include "sqliteInt.h"
#include <ctype.h>
@ -55,6 +54,8 @@
#include <assert.h>
#include <time.h>
#ifndef SQLITE_OMIT_DATETIME_FUNCS
/*
** A structure for holding a single date and time.
*/
@ -73,17 +74,50 @@ struct DateTime {
/*
** Convert N digits from zDate into an integer. Return
** -1 if zDate does not begin with N digits.
** Convert zDate into one or more integers. Additional arguments
** come in groups of 5 as follows:
**
** N number of digits in the integer
** min minimum allowed value of the integer
** max maximum allowed value of the integer
** nextC first character after the integer
** pVal where to write the integers value.
**
** Conversions continue until one with nextC==0 is encountered.
** The function returns the number of successful conversions.
*/
static int getDigits(const char *zDate, int N){
int val = 0;
while( N-- ){
if( !isdigit(*zDate) ) return -1;
val = val*10 + *zDate - '0';
static int getDigits(const char *zDate, ...){
va_list ap;
int val;
int N;
int min;
int max;
int nextC;
int *pVal;
int cnt = 0;
va_start(ap, zDate);
do{
N = va_arg(ap, int);
min = va_arg(ap, int);
max = va_arg(ap, int);
nextC = va_arg(ap, int);
pVal = va_arg(ap, int*);
val = 0;
while( N-- ){
if( !isdigit(*zDate) ){
return cnt;
}
val = val*10 + *zDate - '0';
zDate++;
}
if( val<min || val>max || (nextC!=0 && nextC!=*zDate) ){
return cnt;
}
*pVal = val;
zDate++;
}
return val;
cnt++;
}while( nextC );
return cnt;
}
/*
@ -91,38 +125,9 @@ static int getDigits(const char *zDate, int N){
** the number of digits converted.
*/
static int getValue(const char *z, double *pR){
double r = 0.0;
double rDivide = 1.0;
int isNeg = 0;
int nChar = 0;
if( *z=='+' ){
z++;
nChar++;
}else if( *z=='-' ){
z++;
isNeg = 1;
nChar++;
}
if( !isdigit(*z) ) return 0;
while( isdigit(*z) ){
r = r*10.0 + *z - '0';
nChar++;
z++;
}
if( *z=='.' && isdigit(z[1]) ){
z++;
nChar++;
while( isdigit(*z) ){
r = r*10.0 + *z - '0';
rDivide *= 10.0;
nChar++;
z++;
}
r /= rDivide;
}
if( *z!=0 && !isspace(*z) ) return 0;
*pR = isNeg ? -r : r;
return nChar;
const char *zEnd;
*pR = sqliteAtoF(z, &zEnd);
return zEnd - z;
}
/*
@ -150,14 +155,10 @@ static int parseTimezone(const char *zDate, DateTime *p){
return *zDate!=0;
}
zDate++;
nHr = getDigits(zDate, 2);
if( nHr<0 || nHr>14 ) return 1;
zDate += 2;
if( zDate[0]!=':' ) return 1;
zDate++;
nMn = getDigits(zDate, 2);
if( nMn<0 || nMn>59 ) return 1;
zDate += 2;
if( getDigits(zDate, 2, 0, 14, ':', &nHr, 2, 0, 59, 0, &nMn)!=2 ){
return 1;
}
zDate += 5;
p->tz = sgn*(nMn + nHr*60);
while( isspace(*zDate) ){ zDate++; }
return *zDate!=0;
@ -173,16 +174,16 @@ static int parseTimezone(const char *zDate, DateTime *p){
static int parseHhMmSs(const char *zDate, DateTime *p){
int h, m, s;
double ms = 0.0;
h = getDigits(zDate, 2);
if( h<0 || zDate[2]!=':' ) return 1;
zDate += 3;
m = getDigits(zDate, 2);
if( m<0 || m>59 ) return 1;
zDate += 2;
if( getDigits(zDate, 2, 0, 24, ':', &h, 2, 0, 59, 0, &m)!=2 ){
return 1;
}
zDate += 5;
if( *zDate==':' ){
s = getDigits(&zDate[1], 2);
if( s<0 || s>59 ) return 1;
zDate += 3;
zDate++;
if( getDigits(zDate, 2, 0, 59, 0, &s)!=1 ){
return 1;
}
zDate += 2;
if( *zDate=='.' && isdigit(zDate[1]) ){
double rScale = 1.0;
zDate++;
@ -259,20 +260,21 @@ static void computeJD(DateTime *p){
** date.
*/
static int parseYyyyMmDd(const char *zDate, DateTime *p){
int Y, M, D;
int Y, M, D, neg;
Y = getDigits(zDate, 4);
if( Y<0 || zDate[4]!='-' ) return 1;
zDate += 5;
M = getDigits(zDate, 2);
if( M<=0 || M>12 || zDate[2]!='-' ) return 1;
zDate += 3;
D = getDigits(zDate, 2);
if( D<=0 || D>31 ) return 1;
zDate += 2;
if( zDate[0]=='-' ){
zDate++;
neg = 1;
}else{
neg = 0;
}
if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){
return 1;
}
zDate += 10;
while( isspace(*zDate) ){ zDate++; }
if( isdigit(*zDate) ){
if( parseHhMmSs(zDate, p) ) return 1;
if( parseHhMmSs(zDate, p)==0 ){
/* We got the time */
}else if( *zDate==0 ){
p->validHMS = 0;
}else{
@ -280,7 +282,7 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
}
p->validJD = 0;
p->validYMD = 1;
p->Y = Y;
p->Y = neg ? -Y : Y;
p->M = M;
p->D = D;
if( p->validTZ ){
@ -306,15 +308,12 @@ static int parseYyyyMmDd(const char *zDate, DateTime *p){
** as there is a year and date.
*/
static int parseDateOrTime(const char *zDate, DateTime *p){
int i;
memset(p, 0, sizeof(*p));
for(i=0; isdigit(zDate[i]); i++){}
if( i==4 && zDate[i]=='-' ){
return parseYyyyMmDd(zDate, p);
}else if( i==2 && zDate[i]==':' ){
return parseHhMmSs(zDate, p);
if( parseYyyyMmDd(zDate,p)==0 ){
return 0;
}else if( i==0 && sqliteStrICmp(zDate,"now")==0 ){
}else if( parseHhMmSs(zDate, p)==0 ){
return 0;
}else if( sqliteStrICmp(zDate,"now")==0){
double r;
if( sqliteOsCurrentTime(&r)==0 ){
p->rJD = r;
@ -323,7 +322,7 @@ static int parseDateOrTime(const char *zDate, DateTime *p){
}
return 1;
}else if( sqliteIsNumber(zDate) ){
p->rJD = sqliteAtoF(zDate);
p->rJD = sqliteAtoF(zDate, 0);
p->validJD = 1;
return 0;
}
@ -336,17 +335,23 @@ static int parseDateOrTime(const char *zDate, DateTime *p){
static void computeYMD(DateTime *p){
int Z, A, B, C, D, E, X1;
if( p->validYMD ) return;
Z = p->rJD + 0.5;
A = (Z - 1867216.25)/36524.25;
A = Z + 1 + A - (A/4);
B = A + 1524;
C = (B - 122.1)/365.25;
D = 365.25*C;
E = (B-D)/30.6001;
X1 = 30.6001*E;
p->D = B - D - X1;
p->M = E<14 ? E-1 : E-13;
p->Y = p->M>2 ? C - 4716 : C - 4715;
if( !p->validJD ){
p->Y = 2000;
p->M = 1;
p->D = 1;
}else{
Z = p->rJD + 0.5;
A = (Z - 1867216.25)/36524.25;
A = Z + 1 + A - (A/4);
B = A + 1524;
C = (B - 122.1)/365.25;
D = 365.25*C;
E = (B-D)/30.6001;
X1 = 30.6001*E;
p->D = B - D - X1;
p->M = E<14 ? E-1 : E-13;
p->Y = p->M>2 ? C - 4716 : C - 4715;
}
p->validYMD = 1;
}
@ -452,8 +457,9 @@ static int parseModifier(const char *zMod, DateTime *p){
int rc = 1;
int n;
double r;
char z[30];
for(n=0; n<sizeof(z)-1 && zMod[n]; n++){
char *z, zBuf[30];
z = zBuf;
for(n=0; n<sizeof(zBuf)-1 && zMod[n]; n++){
z[n] = tolower(zMod[n]);
}
z[n] = 0;
@ -526,22 +532,22 @@ static int parseModifier(const char *zMod, DateTime *p){
** or month or year.
*/
if( strncmp(z, "start of ", 9)!=0 ) break;
zMod = &z[9];
z += 9;
computeYMD(p);
p->validHMS = 1;
p->h = p->m = 0;
p->s = 0.0;
p->validTZ = 0;
p->validJD = 0;
if( strcmp(zMod,"month")==0 ){
if( strcmp(z,"month")==0 ){
p->D = 1;
rc = 0;
}else if( strcmp(zMod,"year")==0 ){
}else if( strcmp(z,"year")==0 ){
computeYMD(p);
p->M = 1;
p->D = 1;
rc = 0;
}else if( strcmp(zMod,"day")==0 ){
}else if( strcmp(z,"day")==0 ){
rc = 0;
}
break;
@ -560,11 +566,33 @@ static int parseModifier(const char *zMod, DateTime *p){
case '9': {
n = getValue(z, &r);
if( n<=0 ) break;
zMod = &z[n];
while( isspace(zMod[0]) ) zMod++;
n = strlen(zMod);
if( z[n]==':' ){
/* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
** specified number of hours, minutes, seconds, and fractional seconds
** to the time. The ".FFF" may be omitted. The ":SS.FFF" may be
** omitted.
*/
const char *z2 = z;
DateTime tx;
int day;
if( !isdigit(*z2) ) z2++;
memset(&tx, 0, sizeof(tx));
if( parseHhMmSs(z2, &tx) ) break;
computeJD(&tx);
tx.rJD -= 0.5;
day = (int)tx.rJD;
tx.rJD -= day;
if( z[0]=='-' ) tx.rJD = -tx.rJD;
computeJD(p);
clearYMD_HMS_TZ(p);
p->rJD += tx.rJD;
rc = 0;
break;
}
z += n;
while( isspace(z[0]) ) z++;
n = strlen(z);
if( n>10 || n<3 ) break;
strcpy(z, zMod);
if( z[n-1]=='s' ){ z[n-1] = 0; n--; }
computeJD(p);
rc = 0;

View file

@ -189,7 +189,7 @@ void sqliteDeleteFrom(
}
/* The usual case: There is a WHERE clause so we have to scan through
** the table an pick which records to delete.
** the table and pick which records to delete.
*/
else{
/* Begin the database scan
@ -253,12 +253,7 @@ void sqliteDeleteFrom(
** cursors are opened only once on the outside the loop.
*/
pParse->nTab = iCur + 1;
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, iCur, pTab->tnum);
for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, pParse->nTab++, pIdx->tnum);
}
sqliteOpenTableAndIndices(pParse, pTab, iCur);
/* This is the beginning of the delete loop when there are no
** row triggers */
@ -299,13 +294,14 @@ void sqliteDeleteFrom(
pParse->nTab = iCur;
}
}
sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
sqliteEndWriteOperation(pParse);
/*
** Return the number of rows that were deleted.
*/
if( db->flags & SQLITE_CountRows ){
sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
sqliteVdbeAddOp(v, OP_ColumnName, 0, 1);
sqliteVdbeChangeP3(v, -1, "rows deleted", P3_STATIC);
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
}
@ -347,7 +343,8 @@ void sqliteGenerateRowDelete(
int addr;
addr = sqliteVdbeAddOp(v, OP_NotExists, iCur, 0);
sqliteGenerateRowIndexDelete(db, v, pTab, iCur, 0);
sqliteVdbeAddOp(v, OP_Delete, iCur, count);
sqliteVdbeAddOp(v, OP_Delete, iCur,
(count?OPFLAG_NCHANGE:0) | OPFLAG_CSCHANGE);
sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
}

View file

@ -18,6 +18,7 @@
** $Id$
*/
#include <string.h>
#include <assert.h>
/*
** How This Encoder Works
@ -26,7 +27,7 @@
** 0x00. This is accomplished by using an escape character to encode
** 0x27 and 0x00 as a two-byte sequence. The escape character is always
** 0x01. An 0x00 is encoded as the two byte sequence 0x01 0x01. The
** 0x27 character is encoded as the two byte sequence 0x01 0x03. Finally,
** 0x27 character is encoded as the two byte sequence 0x01 0x28. Finally,
** the escape character itself is encoded as the two-character sequence
** 0x01 0x02.
**
@ -34,7 +35,7 @@
**
** 0x00 -> 0x01 0x01
** 0x01 -> 0x01 0x02
** 0x27 -> 0x01 0x03
** 0x27 -> 0x01 0x28
**
** If that were all the encoder did, it would work, but in certain cases
** it could double the size of the encoded string. For example, to
@ -80,7 +81,7 @@
** the offset in step 7 below.
**
** (6) Convert each 0x01 0x01 sequence into a single character 0x00.
** Convert 0x01 0x02 into 0x01. Convert 0x01 0x03 into 0x27.
** Convert 0x01 0x02 into 0x01. Convert 0x01 0x28 into 0x27.
**
** (7) Subtract the offset value that was the first character of
** the encoded buffer from all characters in the output buffer.
@ -114,13 +115,20 @@
**
** The return value is the number of characters in the encoded
** string, excluding the "\000" terminator.
**
** If out==NULL then no output is generated but the routine still returns
** the number of characters that would have been generated if out had
** not been NULL.
*/
int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out){
int i, j, e, m;
unsigned char x;
int cnt[256];
if( n<=0 ){
out[0] = 'x';
out[1] = 0;
if( out ){
out[0] = 'x';
out[1] = 0;
}
return 1;
}
memset(cnt, 0, sizeof(cnt));
@ -136,24 +144,21 @@ int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out){
if( m==0 ) break;
}
}
if( out==0 ){
return n+m+1;
}
out[0] = e;
j = 1;
for(i=0; i<n; i++){
int c = (in[i] - e)&0xff;
if( c==0 ){
x = in[i] - e;
if( x==0 || x==1 || x=='\''){
out[j++] = 1;
out[j++] = 1;
}else if( c==1 ){
out[j++] = 1;
out[j++] = 2;
}else if( c=='\'' ){
out[j++] = 1;
out[j++] = 3;
}else{
out[j++] = c;
x++;
}
out[j++] = x;
}
out[j] = 0;
assert( j==n+m+1 );
return j;
}
@ -168,38 +173,32 @@ int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out){
** to decode a string in place.
*/
int sqlite_decode_binary(const unsigned char *in, unsigned char *out){
int i, c, e;
int i, e;
unsigned char c;
e = *(in++);
i = 0;
while( (c = *(in++))!=0 ){
if( c==1 ){
c = *(in++);
if( c==1 ){
c = 0;
}else if( c==2 ){
c = 1;
}else if( c==3 ){
c = '\'';
}else{
return -1;
}
c = *(in++) - 1;
}
out[i++] = (c + e)&0xff;
out[i++] = c + e;
}
return i;
}
#ifdef ENCODER_TEST
#include <stdio.h>
/*
** The subroutines above are not tested by the usual test suite. To test
** these routines, compile just this one file with a -DENCODER_TEST=1 option
** and run the result.
*/
int main(int argc, char **argv){
int i, j, n, m, nOut;
int i, j, n, m, nOut, nByteIn, nByteOut;
unsigned char in[30000];
unsigned char out[33000];
nByteIn = nByteOut = 0;
for(i=0; i<sizeof(in); i++){
printf("Test %d: ", i+1);
n = rand() % (i+1);
@ -213,11 +212,17 @@ int main(int argc, char **argv){
}else{
for(j=0; j<n; j++) in[j] = rand() & 0xff;
}
nByteIn += n;
nOut = sqlite_encode_binary(in, n, out);
nByteOut += nOut;
if( nOut!=strlen(out) ){
printf(" ERROR return value is %d instead of %d\n", nOut, strlen(out));
exit(1);
}
if( nOut!=sqlite_encode_binary(in, n, 0) ){
printf(" ERROR actual output size disagrees with predicted size\n");
exit(1);
}
m = (256*n + 1262)/253;
printf("size %d->%d (max %d)", n, strlen(out)+1, m);
if( strlen(out)+1>m ){
@ -241,5 +246,9 @@ int main(int argc, char **argv){
}
printf(" OK\n");
}
fprintf(stderr,"Finished. Total encoding: %d->%d bytes\n",
nByteIn, nByteOut);
fprintf(stderr,"Avg size increase: %.3f%%\n",
(nByteOut-nByteIn)*100.0/(double)nByteIn);
}
#endif /* ENCODER_TEST */

View file

@ -26,8 +26,7 @@ Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
Expr *pNew;
pNew = sqliteMalloc( sizeof(Expr) );
if( pNew==0 ){
sqliteExprDelete(pLeft);
sqliteExprDelete(pRight);
/* When malloc fails, we leak memory from pLeft and pRight */
return 0;
}
pNew->op = op;
@ -38,9 +37,9 @@ Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
pNew->token = *pToken;
pNew->span = *pToken;
}else{
pNew->token.dyn = 0;
pNew->token.z = 0;
pNew->token.n = 0;
assert( pNew->token.dyn==0 );
assert( pNew->token.z==0 );
assert( pNew->token.n==0 );
if( pLeft && pRight ){
sqliteExprSpan(pNew, &pLeft->span, &pRight->span);
}else{
@ -55,14 +54,15 @@ Expr *sqliteExpr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
** text between the two given tokens.
*/
void sqliteExprSpan(Expr *pExpr, Token *pLeft, Token *pRight){
if( pExpr && pRight && pRight->z && pLeft && pLeft->z ){
assert( pRight!=0 );
assert( pLeft!=0 );
/* Note: pExpr might be NULL due to a prior malloc failure */
if( pExpr && pRight->z && pLeft->z ){
if( pLeft->dyn==0 && pRight->dyn==0 ){
pExpr->span.z = pLeft->z;
pExpr->span.n = pRight->n + Addr(pRight->z) - Addr(pLeft->z);
}else{
pExpr->span.z = 0;
pExpr->span.n = 0;
pExpr->span.dyn = 0;
}
}
}
@ -75,18 +75,16 @@ Expr *sqliteExprFunction(ExprList *pList, Token *pToken){
Expr *pNew;
pNew = sqliteMalloc( sizeof(Expr) );
if( pNew==0 ){
sqliteExprListDelete(pList);
/* sqliteExprListDelete(pList); // Leak pList when malloc fails */
return 0;
}
pNew->op = TK_FUNCTION;
pNew->pList = pList;
pNew->token.dyn = 0;
if( pToken ){
assert( pToken->dyn==0 );
pNew->token = *pToken;
}else{
pNew->token.z = 0;
pNew->token.n = 0;
}
pNew->span = pNew->token;
return pNew;
@ -97,12 +95,12 @@ Expr *sqliteExprFunction(ExprList *pList, Token *pToken){
*/
void sqliteExprDelete(Expr *p){
if( p==0 ) return;
if( p->span.dyn && p->span.z ) sqliteFree((char*)p->span.z);
if( p->token.dyn && p->token.z ) sqliteFree((char*)p->token.z);
if( p->pLeft ) sqliteExprDelete(p->pLeft);
if( p->pRight ) sqliteExprDelete(p->pRight);
if( p->pList ) sqliteExprListDelete(p->pList);
if( p->pSelect ) sqliteSelectDelete(p->pSelect);
if( p->span.dyn ) sqliteFree((char*)p->span.z);
if( p->token.dyn ) sqliteFree((char*)p->token.z);
sqliteExprDelete(p->pLeft);
sqliteExprDelete(p->pRight);
sqliteExprListDelete(p->pList);
sqliteSelectDelete(p->pSelect);
sqliteFree(p);
}
@ -129,13 +127,9 @@ Expr *sqliteExprDup(Expr *p){
pNew->token.z = sqliteStrDup(p->token.z);
pNew->token.dyn = 1;
}else{
pNew->token.z = 0;
pNew->token.n = 0;
pNew->token.dyn = 0;
assert( pNew->token.z==0 );
}
pNew->span.z = 0;
pNew->span.n = 0;
pNew->span.dyn = 0;
pNew->pLeft = sqliteExprDup(p->pLeft);
pNew->pRight = sqliteExprDup(p->pRight);
pNew->pList = sqliteExprListDup(p->pList);
@ -149,23 +143,22 @@ void sqliteTokenCopy(Token *pTo, Token *pFrom){
pTo->z = sqliteStrNDup(pFrom->z, pFrom->n);
pTo->dyn = 1;
}else{
pTo->n = 0;
pTo->z = 0;
pTo->dyn = 0;
}
}
ExprList *sqliteExprListDup(ExprList *p){
ExprList *pNew;
struct ExprList_item *pItem;
int i;
if( p==0 ) return 0;
pNew = sqliteMalloc( sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->nExpr = pNew->nAlloc = p->nExpr;
pNew->a = sqliteMalloc( p->nExpr*sizeof(p->a[0]) );
if( pNew->a==0 ) return 0;
for(i=0; i<p->nExpr; i++){
pNew->a = pItem = sqliteMalloc( p->nExpr*sizeof(p->a[0]) );
if( pItem==0 ) return 0; /* Leaks memory after a malloc failure */
for(i=0; i<p->nExpr; i++, pItem++){
Expr *pNewExpr, *pOldExpr;
pNew->a[i].pExpr = pNewExpr = sqliteExprDup(pOldExpr = p->a[i].pExpr);
pItem->pExpr = pNewExpr = sqliteExprDup(pOldExpr = p->a[i].pExpr);
if( pOldExpr->span.z!=0 && pNewExpr ){
/* Always make a copy of the span for top-level expressions in the
** expression list. The logic in SELECT processing that determines
@ -174,10 +167,10 @@ ExprList *sqliteExprListDup(ExprList *p){
}
assert( pNewExpr==0 || pNewExpr->span.z!=0
|| pOldExpr->span.z==0 || sqlite_malloc_failed );
pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
pNew->a[i].sortOrder = p->a[i].sortOrder;
pNew->a[i].isAgg = p->a[i].isAgg;
pNew->a[i].done = 0;
pItem->zName = sqliteStrDup(p->a[i].zName);
pItem->sortOrder = p->a[i].sortOrder;
pItem->isAgg = p->a[i].isAgg;
pItem->done = 0;
}
return pNew;
}
@ -187,19 +180,21 @@ SrcList *sqliteSrcListDup(SrcList *p){
int nByte;
if( p==0 ) return 0;
nByte = sizeof(*p) + (p->nSrc>0 ? sizeof(p->a[0]) * (p->nSrc-1) : 0);
pNew = sqliteMalloc( nByte );
pNew = sqliteMallocRaw( nByte );
if( pNew==0 ) return 0;
pNew->nSrc = pNew->nAlloc = p->nSrc;
for(i=0; i<p->nSrc; i++){
pNew->a[i].zDatabase = sqliteStrDup(p->a[i].zDatabase);
pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
pNew->a[i].zAlias = sqliteStrDup(p->a[i].zAlias);
pNew->a[i].jointype = p->a[i].jointype;
pNew->a[i].iCursor = p->a[i].iCursor;
pNew->a[i].pTab = 0;
pNew->a[i].pSelect = sqliteSelectDup(p->a[i].pSelect);
pNew->a[i].pOn = sqliteExprDup(p->a[i].pOn);
pNew->a[i].pUsing = sqliteIdListDup(p->a[i].pUsing);
struct SrcList_item *pNewItem = &pNew->a[i];
struct SrcList_item *pOldItem = &p->a[i];
pNewItem->zDatabase = sqliteStrDup(pOldItem->zDatabase);
pNewItem->zName = sqliteStrDup(pOldItem->zName);
pNewItem->zAlias = sqliteStrDup(pOldItem->zAlias);
pNewItem->jointype = pOldItem->jointype;
pNewItem->iCursor = pOldItem->iCursor;
pNewItem->pTab = 0;
pNewItem->pSelect = sqliteSelectDup(pOldItem->pSelect);
pNewItem->pOn = sqliteExprDup(pOldItem->pOn);
pNewItem->pUsing = sqliteIdListDup(pOldItem->pUsing);
}
return pNew;
}
@ -207,21 +202,23 @@ IdList *sqliteIdListDup(IdList *p){
IdList *pNew;
int i;
if( p==0 ) return 0;
pNew = sqliteMalloc( sizeof(*pNew) );
pNew = sqliteMallocRaw( sizeof(*pNew) );
if( pNew==0 ) return 0;
pNew->nId = pNew->nAlloc = p->nId;
pNew->a = sqliteMalloc( p->nId*sizeof(p->a[0]) );
pNew->a = sqliteMallocRaw( p->nId*sizeof(p->a[0]) );
if( pNew->a==0 ) return 0;
for(i=0; i<p->nId; i++){
pNew->a[i].zName = sqliteStrDup(p->a[i].zName);
pNew->a[i].idx = p->a[i].idx;
struct IdList_item *pNewItem = &pNew->a[i];
struct IdList_item *pOldItem = &p->a[i];
pNewItem->zName = sqliteStrDup(pOldItem->zName);
pNewItem->idx = pOldItem->idx;
}
return pNew;
}
Select *sqliteSelectDup(Select *p){
Select *pNew;
if( p==0 ) return 0;
pNew = sqliteMalloc( sizeof(*p) );
pNew = sqliteMallocRaw( sizeof(*p) );
if( pNew==0 ) return 0;
pNew->isDistinct = p->isDistinct;
pNew->pEList = sqliteExprListDup(p->pEList);
@ -246,32 +243,31 @@ Select *sqliteSelectDup(Select *p){
** initially NULL, then create a new expression list.
*/
ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
int i;
if( pList==0 ){
pList = sqliteMalloc( sizeof(ExprList) );
if( pList==0 ){
sqliteExprDelete(pExpr);
/* sqliteExprDelete(pExpr); // Leak memory if malloc fails */
return 0;
}
pList->nAlloc = 0;
assert( pList->nAlloc==0 );
}
if( pList->nAlloc<=pList->nExpr ){
struct ExprList_item *a;
pList->nAlloc = pList->nAlloc*2 + 4;
a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]));
if( a==0 ){
sqliteExprDelete(pExpr);
pList->a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]));
if( pList->a==0 ){
/* sqliteExprDelete(pExpr); // Leak memory if malloc fails */
pList->nExpr = pList->nAlloc = 0;
return pList;
}
pList->a = a;
}
if( pList->a && (pExpr || pName) ){
i = pList->nExpr++;
memset(&pList->a[i], 0, sizeof(pList->a[i]));
pList->a[i].pExpr = pExpr;
assert( pList->a!=0 );
if( pExpr || pName ){
struct ExprList_item *pItem = &pList->a[pList->nExpr++];
memset(pItem, 0, sizeof(*pItem));
pItem->pExpr = pExpr;
if( pName ){
sqliteSetNString(&pList->a[i].zName, pName->z, pName->n, 0);
sqliteDequote(pList->a[i].zName);
sqliteSetNString(&pItem->zName, pName->z, pName->n, 0);
sqliteDequote(pItem->zName);
}
}
return pList;
@ -283,6 +279,8 @@ ExprList *sqliteExprListAppend(ExprList *pList, Expr *pExpr, Token *pName){
void sqliteExprListDelete(ExprList *pList){
int i;
if( pList==0 ) return;
assert( pList->a!=0 || (pList->nExpr==0 && pList->nAlloc==0) );
assert( pList->nExpr<=pList->nAlloc );
for(i=0; i<pList->nExpr; i++){
sqliteExprDelete(pList->a[i].pExpr);
sqliteFree(pList->a[i].zName);
@ -379,6 +377,221 @@ int sqliteIsRowid(const char *z){
return 0;
}
/*
** Given the name of a column of the form X.Y.Z or Y.Z or just Z, look up
** that name in the set of source tables in pSrcList and make the pExpr
** expression node refer back to that source column. The following changes
** are made to pExpr:
**
** pExpr->iDb Set the index in db->aDb[] of the database holding
** the table.
** pExpr->iTable Set to the cursor number for the table obtained
** from pSrcList.
** pExpr->iColumn Set to the column number within the table.
** pExpr->dataType Set to the appropriate data type for the column.
** pExpr->op Set to TK_COLUMN.
** pExpr->pLeft Any expression this points to is deleted
** pExpr->pRight Any expression this points to is deleted.
**
** The pDbToken is the name of the database (the "X"). This value may be
** NULL meaning that name is of the form Y.Z or Z. Any available database
** can be used. The pTableToken is the name of the table (the "Y"). This
** value can be NULL if pDbToken is also NULL. If pTableToken is NULL it
** means that the form of the name is Z and that columns from any table
** can be used.
**
** If the name cannot be resolved unambiguously, leave an error message
** in pParse and return non-zero. Return zero on success.
*/
static int lookupName(
Parse *pParse, /* The parsing context */
Token *pDbToken, /* Name of the database containing table, or NULL */
Token *pTableToken, /* Name of table containing column, or NULL */
Token *pColumnToken, /* Name of the column. */
SrcList *pSrcList, /* List of tables used to resolve column names */
ExprList *pEList, /* List of expressions used to resolve "AS" */
Expr *pExpr /* Make this EXPR node point to the selected column */
){
char *zDb = 0; /* Name of the database. The "X" in X.Y.Z */
char *zTab = 0; /* Name of the table. The "Y" in X.Y.Z or Y.Z */
char *zCol = 0; /* Name of the column. The "Z" */
int i, j; /* Loop counters */
int cnt = 0; /* Number of matching column names */
int cntTab = 0; /* Number of matching table names */
sqlite *db = pParse->db; /* The database */
assert( pColumnToken && pColumnToken->z ); /* The Z in X.Y.Z cannot be NULL */
if( pDbToken && pDbToken->z ){
zDb = sqliteStrNDup(pDbToken->z, pDbToken->n);
sqliteDequote(zDb);
}else{
zDb = 0;
}
if( pTableToken && pTableToken->z ){
zTab = sqliteStrNDup(pTableToken->z, pTableToken->n);
sqliteDequote(zTab);
}else{
assert( zDb==0 );
zTab = 0;
}
zCol = sqliteStrNDup(pColumnToken->z, pColumnToken->n);
sqliteDequote(zCol);
if( sqlite_malloc_failed ){
return 1; /* Leak memory (zDb and zTab) if malloc fails */
}
assert( zTab==0 || pEList==0 );
pExpr->iTable = -1;
for(i=0; i<pSrcList->nSrc; i++){
struct SrcList_item *pItem = &pSrcList->a[i];
Table *pTab = pItem->pTab;
Column *pCol;
if( pTab==0 ) continue;
assert( pTab->nCol>0 );
if( zTab ){
if( pItem->zAlias ){
char *zTabName = pItem->zAlias;
if( sqliteStrICmp(zTabName, zTab)!=0 ) continue;
}else{
char *zTabName = pTab->zName;
if( zTabName==0 || sqliteStrICmp(zTabName, zTab)!=0 ) continue;
if( zDb!=0 && sqliteStrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){
continue;
}
}
}
if( 0==(cntTab++) ){
pExpr->iTable = pItem->iCursor;
pExpr->iDb = pTab->iDb;
}
for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
if( sqliteStrICmp(pCol->zName, zCol)==0 ){
cnt++;
pExpr->iTable = pItem->iCursor;
pExpr->iDb = pTab->iDb;
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
pExpr->dataType = pCol->sortOrder & SQLITE_SO_TYPEMASK;
break;
}
}
}
/* If we have not already resolved the name, then maybe
** it is a new.* or old.* trigger argument reference
*/
if( zDb==0 && zTab!=0 && cnt==0 && pParse->trigStack!=0 ){
TriggerStack *pTriggerStack = pParse->trigStack;
Table *pTab = 0;
if( pTriggerStack->newIdx != -1 && sqliteStrICmp("new", zTab) == 0 ){
pExpr->iTable = pTriggerStack->newIdx;
assert( pTriggerStack->pTab );
pTab = pTriggerStack->pTab;
}else if( pTriggerStack->oldIdx != -1 && sqliteStrICmp("old", zTab) == 0 ){
pExpr->iTable = pTriggerStack->oldIdx;
assert( pTriggerStack->pTab );
pTab = pTriggerStack->pTab;
}
if( pTab ){
int j;
Column *pCol = pTab->aCol;
pExpr->iDb = pTab->iDb;
cntTab++;
for(j=0; j < pTab->nCol; j++, pCol++) {
if( sqliteStrICmp(pCol->zName, zCol)==0 ){
cnt++;
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
pExpr->dataType = pCol->sortOrder & SQLITE_SO_TYPEMASK;
break;
}
}
}
}
/*
** Perhaps the name is a reference to the ROWID
*/
if( cnt==0 && cntTab==1 && sqliteIsRowid(zCol) ){
cnt = 1;
pExpr->iColumn = -1;
pExpr->dataType = SQLITE_SO_NUM;
}
/*
** If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z
** might refer to an result-set alias. This happens, for example, when
** we are resolving names in the WHERE clause of the following command:
**
** SELECT a+b AS x FROM table WHERE x<10;
**
** In cases like this, replace pExpr with a copy of the expression that
** forms the result set entry ("a+b" in the example) and return immediately.
** Note that the expression in the result set should have already been
** resolved by the time the WHERE clause is resolved.
*/
if( cnt==0 && pEList!=0 ){
for(j=0; j<pEList->nExpr; j++){
char *zAs = pEList->a[j].zName;
if( zAs!=0 && sqliteStrICmp(zAs, zCol)==0 ){
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
pExpr->op = TK_AS;
pExpr->iColumn = j;
pExpr->pLeft = sqliteExprDup(pEList->a[j].pExpr);
sqliteFree(zCol);
assert( zTab==0 && zDb==0 );
return 0;
}
}
}
/*
** If X and Y are NULL (in other words if only the column name Z is
** supplied) and the value of Z is enclosed in double-quotes, then
** Z is a string literal if it doesn't match any column names. In that
** case, we need to return right away and not make any changes to
** pExpr.
*/
if( cnt==0 && zTab==0 && pColumnToken->z[0]=='"' ){
sqliteFree(zCol);
return 0;
}
/*
** cnt==0 means there was not match. cnt>1 means there were two or
** more matches. Either way, we have an error.
*/
if( cnt!=1 ){
char *z = 0;
char *zErr;
zErr = cnt==0 ? "no such column: %s" : "ambiguous column name: %s";
if( zDb ){
sqliteSetString(&z, zDb, ".", zTab, ".", zCol, 0);
}else if( zTab ){
sqliteSetString(&z, zTab, ".", zCol, 0);
}else{
z = sqliteStrDup(zCol);
}
sqliteErrorMsg(pParse, zErr, z);
sqliteFree(z);
}
/* Clean up and return
*/
sqliteFree(zDb);
sqliteFree(zTab);
sqliteFree(zCol);
sqliteExprDelete(pExpr->pLeft);
pExpr->pLeft = 0;
sqliteExprDelete(pExpr->pRight);
pExpr->pRight = 0;
pExpr->op = TK_COLUMN;
sqliteAuthRead(pParse, pExpr, pSrcList);
return cnt!=1;
}
/*
** This routine walks an expression tree and resolves references to
** table columns. Nodes of the form ID.ID or ID resolve into an
@ -412,15 +625,15 @@ int sqliteIsRowid(const char *z){
*/
int sqliteExprResolveIds(
Parse *pParse, /* The parser context */
SrcList *pTabList, /* List of tables used to resolve column names */
SrcList *pSrcList, /* List of tables used to resolve column names */
ExprList *pEList, /* List of expressions used to resolve "AS" */
Expr *pExpr /* The expression to be analyzed. */
){
int i;
if( pExpr==0 || pTabList==0 ) return 0;
for(i=0; i<pTabList->nSrc; i++){
assert( pTabList->a[i].iCursor>=0 && pTabList->a[i].iCursor<pParse->nTab );
if( pExpr==0 || pSrcList==0 ) return 0;
for(i=0; i<pSrcList->nSrc; i++){
assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab );
}
switch( pExpr->op ){
/* Double-quoted strings (ex: "abc") are used as identifiers if
@ -431,79 +644,11 @@ int sqliteExprResolveIds(
if( pExpr->token.z[0]=='\'' ) break;
/* Fall thru into the TK_ID case if this is a double-quoted string */
}
/* A lone identifier. Try and match it as follows:
**
** 1. To the name of a column of one of the tables in pTabList
**
** 2. To the right side of an AS keyword in the column list of
** a SELECT statement. (For example, match against 'x' in
** "SELECT a+b AS 'x' FROM t1".)
**
** 3. One of the special names "ROWID", "OID", or "_ROWID_".
/* A lone identifier is the name of a columnd.
*/
case TK_ID: {
int cnt = 0; /* Number of matches */
char *z;
int iDb = -1;
assert( pExpr->token.z );
z = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
sqliteDequote(z);
if( z==0 ) return 1;
for(i=0; i<pTabList->nSrc; i++){
int j;
Table *pTab = pTabList->a[i].pTab;
if( pTab==0 ) continue;
iDb = pTab->iDb;
assert( pTab->nCol>0 );
for(j=0; j<pTab->nCol; j++){
if( sqliteStrICmp(pTab->aCol[j].zName, z)==0 ){
cnt++;
pExpr->iTable = pTabList->a[i].iCursor;
pExpr->iDb = pTab->iDb;
if( j==pTab->iPKey ){
/* Substitute the record number for the INTEGER PRIMARY KEY */
pExpr->iColumn = -1;
pExpr->dataType = SQLITE_SO_NUM;
}else{
pExpr->iColumn = j;
pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK;
}
pExpr->op = TK_COLUMN;
}
}
}
if( cnt==0 && pEList!=0 ){
int j;
for(j=0; j<pEList->nExpr; j++){
char *zAs = pEList->a[j].zName;
if( zAs!=0 && sqliteStrICmp(zAs, z)==0 ){
cnt++;
assert( pExpr->pLeft==0 && pExpr->pRight==0 );
pExpr->op = TK_AS;
pExpr->iColumn = j;
pExpr->pLeft = sqliteExprDup(pEList->a[j].pExpr);
}
}
}
if( cnt==0 && iDb>=0 && sqliteIsRowid(z) ){
pExpr->iColumn = -1;
pExpr->iTable = pTabList->a[0].iCursor;
pExpr->iDb = iDb;
cnt = 1 + (pTabList->nSrc>1);
pExpr->op = TK_COLUMN;
pExpr->dataType = SQLITE_SO_NUM;
}
sqliteFree(z);
if( cnt==0 && pExpr->token.z[0]!='"' ){
sqliteErrorMsg(pParse, "no such column: %T", &pExpr->token);
if( lookupName(pParse, 0, 0, &pExpr->token, pSrcList, pEList, pExpr) ){
return 1;
}else if( cnt>1 ){
sqliteErrorMsg(pParse, "ambiguous column name: %T", &pExpr->token);
return 1;
}
if( pExpr->op==TK_COLUMN ){
sqliteAuthRead(pParse, pExpr, pTabList);
}
break;
}
@ -512,134 +657,32 @@ int sqliteExprResolveIds(
** Or a database, table and column: ID.ID.ID
*/
case TK_DOT: {
int cnt = 0; /* Number of matches */
int cntTab = 0; /* Number of matching tables */
int i; /* Loop counter */
Expr *pLeft, *pRight; /* Left and right subbranches of the expr */
char *zLeft, *zRight; /* Text of an identifier */
char *zDb; /* Name of database holding table */
sqlite *db = pParse->db;
Token *pColumn;
Token *pTable;
Token *pDb;
Expr *pRight;
pRight = pExpr->pRight;
if( pRight->op==TK_ID ){
pLeft = pExpr->pLeft;
zDb = 0;
pDb = 0;
pTable = &pExpr->pLeft->token;
pColumn = &pRight->token;
}else{
Expr *pDb = pExpr->pLeft;
assert( pDb && pDb->op==TK_ID && pDb->token.z );
zDb = sqliteStrNDup(pDb->token.z, pDb->token.n);
pLeft = pRight->pLeft;
pRight = pRight->pRight;
assert( pRight->op==TK_DOT );
pDb = &pExpr->pLeft->token;
pTable = &pRight->pLeft->token;
pColumn = &pRight->pRight->token;
}
assert( pLeft && pLeft->op==TK_ID && pLeft->token.z );
assert( pRight && pRight->op==TK_ID && pRight->token.z );
zLeft = sqliteStrNDup(pLeft->token.z, pLeft->token.n);
zRight = sqliteStrNDup(pRight->token.z, pRight->token.n);
if( zLeft==0 || zRight==0 ){
sqliteFree(zLeft);
sqliteFree(zRight);
sqliteFree(zDb);
if( lookupName(pParse, pDb, pTable, pColumn, pSrcList, 0, pExpr) ){
return 1;
}
sqliteDequote(zDb);
sqliteDequote(zLeft);
sqliteDequote(zRight);
pExpr->iTable = -1;
for(i=0; i<pTabList->nSrc; i++){
int j;
char *zTab;
Table *pTab = pTabList->a[i].pTab;
if( pTab==0 ) continue;
assert( pTab->nCol>0 );
if( pTabList->a[i].zAlias ){
zTab = pTabList->a[i].zAlias;
if( sqliteStrICmp(zTab, zLeft)!=0 ) continue;
}else{
zTab = pTab->zName;
if( zTab==0 || sqliteStrICmp(zTab, zLeft)!=0 ) continue;
if( zDb!=0 && sqliteStrICmp(db->aDb[pTab->iDb].zName, zDb)!=0 ){
continue;
}
}
if( 0==(cntTab++) ){
pExpr->iTable = pTabList->a[i].iCursor;
pExpr->iDb = pTab->iDb;
}
for(j=0; j<pTab->nCol; j++){
if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
cnt++;
pExpr->iTable = pTabList->a[i].iCursor;
pExpr->iDb = pTab->iDb;
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK;
}
}
}
/* If we have not already resolved this *.* expression, then maybe
* it is a new.* or old.* trigger argument reference */
if( cnt == 0 && pParse->trigStack != 0 ){
TriggerStack *pTriggerStack = pParse->trigStack;
int t = 0;
if( pTriggerStack->newIdx != -1 && sqliteStrICmp("new", zLeft) == 0 ){
pExpr->iTable = pTriggerStack->newIdx;
assert( pTriggerStack->pTab );
pExpr->iDb = pTriggerStack->pTab->iDb;
cntTab++;
t = 1;
}
if( pTriggerStack->oldIdx != -1 && sqliteStrICmp("old", zLeft) == 0 ){
pExpr->iTable = pTriggerStack->oldIdx;
assert( pTriggerStack->pTab );
pExpr->iDb = pTriggerStack->pTab->iDb;
cntTab++;
t = 1;
}
if( t ){
int j;
Table *pTab = pTriggerStack->pTab;
for(j=0; j < pTab->nCol; j++) {
if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
cnt++;
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK;
}
}
}
}
if( cnt==0 && cntTab==1 && sqliteIsRowid(zRight) ){
cnt = 1;
pExpr->iColumn = -1;
pExpr->dataType = SQLITE_SO_NUM;
}
sqliteFree(zDb);
sqliteFree(zLeft);
sqliteFree(zRight);
if( cnt==0 ){
sqliteErrorMsg(pParse, "no such column: %T.%T",
&pLeft->token, &pRight->token);
return 1;
}else if( cnt>1 ){
sqliteErrorMsg(pParse, "ambiguous column name: %T.%T",
&pLeft->token, &pRight->token);
return 1;
}
sqliteExprDelete(pExpr->pLeft);
pExpr->pLeft = 0;
sqliteExprDelete(pExpr->pRight);
pExpr->pRight = 0;
pExpr->op = TK_COLUMN;
sqliteAuthRead(pParse, pExpr, pTabList);
break;
}
case TK_IN: {
Vdbe *v = sqliteGetVdbe(pParse);
if( v==0 ) return 1;
if( sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pLeft) ){
if( sqliteExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
return 1;
}
if( pExpr->pSelect ){
@ -677,9 +720,10 @@ int sqliteExprResolveIds(
case TK_FLOAT:
case TK_INTEGER:
case TK_STRING: {
int addr = sqliteVdbeAddOp(v, OP_SetInsert, iSet, 0);
int addr;
assert( pE2->token.z );
sqliteVdbeChangeP3(v, addr, pE2->token.z, pE2->token.n);
addr = sqliteVdbeOp3(v, OP_SetInsert, iSet, 0,
pE2->token.z, pE2->token.n);
sqliteVdbeDequoteP3(v, addr);
break;
}
@ -709,11 +753,11 @@ int sqliteExprResolveIds(
/* For all else, just recursively walk the tree */
default: {
if( pExpr->pLeft
&& sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pLeft) ){
&& sqliteExprResolveIds(pParse, pSrcList, pEList, pExpr->pLeft) ){
return 1;
}
if( pExpr->pRight
&& sqliteExprResolveIds(pParse, pTabList, pEList, pExpr->pRight) ){
&& sqliteExprResolveIds(pParse, pSrcList, pEList, pExpr->pRight) ){
return 1;
}
if( pExpr->pList ){
@ -721,7 +765,7 @@ int sqliteExprResolveIds(
ExprList *pList = pExpr->pList;
for(i=0; i<pList->nExpr; i++){
Expr *pArg = pList->a[i].pExpr;
if( sqliteExprResolveIds(pParse, pTabList, pEList, pArg) ){
if( sqliteExprResolveIds(pParse, pSrcList, pEList, pArg) ){
return 1;
}
}
@ -782,7 +826,6 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
case TK_FUNCTION: {
int n = pExpr->pList ? pExpr->pList->nExpr : 0; /* Number of arguments */
int no_such_func = 0; /* True if no such function exists */
int is_type_of = 0; /* True if is the special TypeOf() function */
int wrong_num_args = 0; /* True if wrong number of arguments */
int is_agg = 0; /* True if is an aggregate function */
int i;
@ -795,11 +838,7 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
if( pDef==0 ){
pDef = sqliteFindFunction(pParse->db, zId, nId, -1, 0);
if( pDef==0 ){
if( n==1 && nId==6 && sqliteStrNICmp(zId, "typeof", 6)==0 ){
is_type_of = 1;
}else {
no_such_func = 1;
}
no_such_func = 1;
}else{
wrong_num_args = 1;
}
@ -807,38 +846,27 @@ int sqliteExprCheck(Parse *pParse, Expr *pExpr, int allowAgg, int *pIsAgg){
is_agg = pDef->xFunc==0;
}
if( is_agg && !allowAgg ){
sqliteSetNString(&pParse->zErrMsg, "misuse of aggregate function ", -1,
zId, nId, "()", 2, 0);
pParse->nErr++;
sqliteErrorMsg(pParse, "misuse of aggregate function %.*s()", nId, zId);
nErr++;
is_agg = 0;
}else if( no_such_func ){
sqliteSetNString(&pParse->zErrMsg, "no such function: ", -1, zId,nId,0);
pParse->nErr++;
sqliteErrorMsg(pParse, "no such function: %.*s", nId, zId);
nErr++;
}else if( wrong_num_args ){
sqliteSetNString(&pParse->zErrMsg,
"wrong number of arguments to function ", -1, zId, nId, "()", 2, 0);
pParse->nErr++;
sqliteErrorMsg(pParse,"wrong number of arguments to function %.*s()",
nId, zId);
nErr++;
}
if( is_agg ) pExpr->op = TK_AGG_FUNCTION;
if( is_agg && pIsAgg ) *pIsAgg = 1;
if( is_agg ){
pExpr->op = TK_AGG_FUNCTION;
if( pIsAgg ) *pIsAgg = 1;
}
for(i=0; nErr==0 && i<n; i++){
nErr = sqliteExprCheck(pParse, pExpr->pList->a[i].pExpr,
allowAgg && !is_agg, pIsAgg);
}
if( pDef==0 ){
if( is_type_of ){
pExpr->op = TK_STRING;
if( sqliteExprType(pExpr->pList->a[0].pExpr)==SQLITE_SO_NUM ){
pExpr->token.z = "numeric";
pExpr->token.n = 7;
}else{
pExpr->token.z = "text";
pExpr->token.n = 4;
}
}
/* Already reported an error */
}else if( pDef->dataType>=0 ){
if( pDef->dataType<n ){
pExpr->dataType =
@ -973,8 +1001,6 @@ int sqliteExprType(Expr *p){
return SQLITE_SO_NUM;
}
/* Run */
/*
** Generate code into the current Vdbe to evaluate the given
** expression and leave the result on the top of stack.
@ -1019,26 +1045,17 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
}
break;
}
case TK_STRING:
case TK_FLOAT:
case TK_INTEGER: {
if( !sqliteFitsIn32Bits(pExpr->token.z) ){
sqliteVdbeAddOp(v, OP_String, 0, 0);
}else{
if( pExpr->op==TK_INTEGER && sqliteFitsIn32Bits(pExpr->token.z) ){
sqliteVdbeAddOp(v, OP_Integer, atoi(pExpr->token.z), 0);
}else{
sqliteVdbeAddOp(v, OP_String, 0, 0);
}
sqliteVdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n);
break;
}
case TK_FLOAT: {
sqliteVdbeAddOp(v, OP_String, 0, 0);
assert( pExpr->token.z );
sqliteVdbeChangeP3(v, -1, pExpr->token.z, pExpr->token.n);
break;
}
case TK_STRING: {
int addr = sqliteVdbeAddOp(v, OP_String, 0, 0);
assert( pExpr->token.z );
sqliteVdbeChangeP3(v, addr, pExpr->token.z, pExpr->token.n);
sqliteVdbeDequoteP3(v, addr);
sqliteVdbeDequoteP3(v, -1);
break;
}
case TK_NULL: {
@ -1087,23 +1104,6 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteVdbeAddOp(v, OP_Concat, 2, 0);
break;
}
case TK_UPLUS: {
Expr *pLeft = pExpr->pLeft;
if( pLeft && pLeft->op==TK_INTEGER ){
if( sqliteFitsIn32Bits(pLeft->token.z) ){
sqliteVdbeAddOp(v, OP_Integer, atoi(pLeft->token.z), 0);
}else{
sqliteVdbeAddOp(v, OP_String, 0, 0);
}
sqliteVdbeChangeP3(v, -1, pLeft->token.z, pLeft->token.n);
}else if( pLeft && pLeft->op==TK_FLOAT ){
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pLeft->token.z, pLeft->token.n);
}else{
sqliteExprCode(pParse, pExpr->pLeft);
}
break;
}
case TK_UMINUS: {
assert( pExpr->pLeft );
if( pExpr->pLeft->op==TK_FLOAT || pExpr->pLeft->op==TK_INTEGER ){
@ -1144,7 +1144,6 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
case TK_GLOB:
case TK_LIKE:
case TK_FUNCTION: {
int i;
ExprList *pList = pExpr->pList;
int nExpr = pList ? pList->nExpr : 0;
FuncDef *pDef;
@ -1153,11 +1152,8 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
getFunctionName(pExpr, &zId, &nId);
pDef = sqliteFindFunction(pParse->db, zId, nId, nExpr, 0);
assert( pDef!=0 );
for(i=0; i<nExpr; i++){
sqliteExprCode(pParse, pList->a[i].pExpr);
}
sqliteVdbeAddOp(v, OP_Function, nExpr, 0);
sqliteVdbeChangeP3(v, -1, (char*)pDef, P3_POINTER);
nExpr = sqliteExprCodeExprList(pParse, pList, pDef->includeTypes);
sqliteVdbeOp3(v, OP_Function, nExpr, 0, (char*)pDef, P3_POINTER);
break;
}
case TK_SELECT: {
@ -1170,7 +1166,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteExprCode(pParse, pExpr->pLeft);
addr = sqliteVdbeCurrentAddr(v);
sqliteVdbeAddOp(v, OP_NotNull, -1, addr+4);
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
sqliteVdbeAddOp(v, OP_Pop, 2, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, addr+6);
if( pExpr->pSelect ){
@ -1192,6 +1188,7 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
sqliteVdbeAddOp(v, OP_And, 0, 0);
break;
}
case TK_UPLUS:
case TK_AS: {
sqliteExprCode(pParse, pExpr->pLeft);
break;
@ -1246,21 +1243,49 @@ void sqliteExprCode(Parse *pParse, Expr *pExpr){
if( pExpr->iColumn == OE_Rollback ||
pExpr->iColumn == OE_Abort ||
pExpr->iColumn == OE_Fail ){
char * msg = sqliteStrNDup(pExpr->token.z, pExpr->token.n);
sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn);
sqliteDequote(msg);
sqliteVdbeChangeP3(v, -1, msg, 0);
sqliteFree(msg);
sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, pExpr->iColumn,
pExpr->token.z, pExpr->token.n);
sqliteVdbeDequoteP3(v, -1);
} else {
assert( pExpr->iColumn == OE_Ignore );
sqliteVdbeAddOp(v, OP_Goto, 0, pParse->trigStack->ignoreJump);
sqliteVdbeChangeP3(v, -1, "(IGNORE jump)", 0);
sqliteVdbeOp3(v, OP_Goto, 0, pParse->trigStack->ignoreJump,
"(IGNORE jump)", 0);
}
}
break;
}
}
/*
** Generate code that pushes the value of every element of the given
** expression list onto the stack. If the includeTypes flag is true,
** then also push a string that is the datatype of each element onto
** the stack after the value.
**
** Return the number of elements pushed onto the stack.
*/
int sqliteExprCodeExprList(
Parse *pParse, /* Parsing context */
ExprList *pList, /* The expression list to be coded */
int includeTypes /* TRUE to put datatypes on the stack too */
){
struct ExprList_item *pItem;
int i, n;
Vdbe *v;
if( pList==0 ) return 0;
v = sqliteGetVdbe(pParse);
n = pList->nExpr;
for(pItem=pList->a, i=0; i<n; i++, pItem++){
sqliteExprCode(pParse, pItem->pExpr);
if( includeTypes ){
sqliteVdbeOp3(v, OP_String, 0, 0,
sqliteExprType(pItem->pExpr)==SQLITE_SO_NUM ? "numeric" : "text",
P3_STATIC);
}
}
return includeTypes ? n*2 : n;
}
/*
** Generate code for a boolean expression such that a jump is made
** to the label "dest" if the expression is true but execution

View file

@ -28,35 +28,36 @@
/*
** Implementation of the non-aggregate min() and max() functions
*/
static void minFunc(sqlite_func *context, int argc, const char **argv){
static void minmaxFunc(sqlite_func *context, int argc, const char **argv){
const char *zBest;
int i;
int (*xCompare)(const char*, const char*);
int mask; /* 0 for min() or 0xffffffff for max() */
if( argc==0 ) return;
mask = (int)sqlite_user_data(context);
zBest = argv[0];
if( zBest==0 ) return;
for(i=1; i<argc; i++){
if( argv[1][0]=='n' ){
xCompare = sqliteCompare;
}else{
xCompare = strcmp;
}
for(i=2; i<argc; i+=2){
if( argv[i]==0 ) return;
if( sqliteCompare(argv[i], zBest)<0 ){
if( (xCompare(argv[i], zBest)^mask)<0 ){
zBest = argv[i];
}
}
sqlite_set_result_string(context, zBest, -1);
}
static void maxFunc(sqlite_func *context, int argc, const char **argv){
const char *zBest;
int i;
if( argc==0 ) return;
zBest = argv[0];
if( zBest==0 ) return;
for(i=1; i<argc; i++){
if( argv[i]==0 ) return;
if( sqliteCompare(argv[i], zBest)>0 ){
zBest = argv[i];
}
}
sqlite_set_result_string(context, zBest, -1);
/*
** Return the type of the argument.
*/
static void typeofFunc(sqlite_func *context, int argc, const char **argv){
assert( argc==2 );
sqlite_set_result_string(context, argv[1], -1);
}
/*
@ -147,7 +148,7 @@ static void roundFunc(sqlite_func *context, int argc, const char **argv){
n = argc==2 ? atoi(argv[1]) : 0;
if( n>30 ) n = 30;
if( n<0 ) n = 0;
r = sqliteAtoF(argv[0]);
r = sqliteAtoF(argv[0], 0);
sprintf(zBuf,"%.*f",n,r);
sqlite_set_result_string(context, zBuf, -1);
}
@ -178,8 +179,8 @@ static void lowerFunc(sqlite_func *context, int argc, const char **argv){
/*
** Implementation of the IFNULL(), NVL(), and COALESCE() functions.
** All three do the same thing. They return the first argument
** non-NULL argument.
** All three do the same thing. They return the first non-NULL
** argument.
*/
static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
int i;
@ -195,7 +196,9 @@ static void ifnullFunc(sqlite_func *context, int argc, const char **argv){
** Implementation of random(). Return a random integer.
*/
static void randomFunc(sqlite_func *context, int argc, const char **argv){
sqlite_set_result_int(context, sqliteRandomInteger());
int r;
sqliteRandomness(sizeof(r), &r);
sqlite_set_result_int(context, r);
}
/*
@ -207,6 +210,25 @@ static void last_insert_rowid(sqlite_func *context, int arg, const char **argv){
sqlite_set_result_int(context, sqlite_last_insert_rowid(db));
}
/*
** Implementation of the change_count() SQL function. The return
** value is the same as the sqlite_changes() API function.
*/
static void change_count(sqlite_func *context, int arg, const char **argv){
sqlite *db = sqlite_user_data(context);
sqlite_set_result_int(context, sqlite_changes(db));
}
/*
** Implementation of the last_statement_change_count() SQL function. The
** return value is the same as the sqlite_last_statement_changes() API function.
*/
static void last_statement_change_count(sqlite_func *context, int arg,
const char **argv){
sqlite *db = sqlite_user_data(context);
sqlite_set_result_int(context, sqlite_last_statement_changes(db));
}
/*
** Implementation of the like() SQL function. This function implements
** the build-in LIKE operator. The first argument to the function is the
@ -341,13 +363,13 @@ static void soundexFunc(sqlite_func *context, int argc, const char **argv){
** generating test data.
*/
static void randStr(sqlite_func *context, int argc, const char **argv){
static const char zSrc[] =
static const unsigned char zSrc[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
".-!,:*^+=_|?/<> ";
int iMin, iMax, n, r, i;
char zBuf[1000];
unsigned char zBuf[1000];
if( argc>=1 ){
iMin = atoi(argv[0]);
if( iMin<0 ) iMin = 0;
@ -358,19 +380,20 @@ static void randStr(sqlite_func *context, int argc, const char **argv){
if( argc>=2 ){
iMax = atoi(argv[1]);
if( iMax<iMin ) iMax = iMin;
if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf);
if( iMax>=sizeof(zBuf) ) iMax = sizeof(zBuf)-1;
}else{
iMax = 50;
}
n = iMin;
if( iMax>iMin ){
r = sqliteRandomInteger() & 0x7fffffff;
sqliteRandomness(sizeof(r), &r);
r &= 0x7fffffff;
n += r%(iMax + 1 - iMin);
}
r = 0;
assert( n<sizeof(zBuf) );
sqliteRandomness(n, zBuf);
for(i=0; i<n; i++){
r = (r + sqliteRandomByte())% (sizeof(zSrc)-1);
zBuf[i] = zSrc[r];
zBuf[i] = zSrc[zBuf[i]%(sizeof(zSrc)-1)];
}
zBuf[n] = 0;
sqlite_set_result_string(context, zBuf, n);
@ -395,7 +418,7 @@ static void sumStep(sqlite_func *context, int argc, const char **argv){
if( argc<1 ) return;
p = sqlite_aggregate_context(context, sizeof(*p));
if( p && argv[0] ){
p->sum += sqliteAtoF(argv[0]);
p->sum += sqliteAtoF(argv[0], 0);
p->cnt++;
}
}
@ -433,7 +456,7 @@ static void stdDevStep(sqlite_func *context, int argc, const char **argv){
if( argc<1 ) return;
p = sqlite_aggregate_context(context, sizeof(*p));
if( p && argv[0] ){
x = sqliteAtoF(argv[0]);
x = sqliteAtoF(argv[0], 0);
p->sum += x;
p->sum2 += x*x;
p->cnt++;
@ -488,39 +511,32 @@ struct MinMaxCtx {
/*
** Routines to implement min() and max() aggregate functions.
*/
static void minStep(sqlite_func *context, int argc, const char **argv){
static void minmaxStep(sqlite_func *context, int argc, const char **argv){
MinMaxCtx *p;
p = sqlite_aggregate_context(context, sizeof(*p));
if( p==0 || argc<1 || argv[0]==0 ) return;
if( p->z==0 || sqliteCompare(argv[0],p->z)<0 ){
int len;
if( p->z && p->z!=p->zBuf ){
sqliteFree(p->z);
}
len = strlen(argv[0]);
if( len < sizeof(p->zBuf) ){
p->z = p->zBuf;
}else{
p->z = sqliteMalloc( len+1 );
if( p->z==0 ) return;
}
strcpy(p->z, argv[0]);
int (*xCompare)(const char*, const char*);
int mask; /* 0 for min() or 0xffffffff for max() */
assert( argc==2 );
if( argv[1][0]=='n' ){
xCompare = sqliteCompare;
}else{
xCompare = strcmp;
}
}
static void maxStep(sqlite_func *context, int argc, const char **argv){
MinMaxCtx *p;
mask = (int)sqlite_user_data(context);
p = sqlite_aggregate_context(context, sizeof(*p));
if( p==0 || argc<1 || argv[0]==0 ) return;
if( p->z==0 || sqliteCompare(argv[0],p->z)>0 ){
if( p->z==0 || (xCompare(argv[0],p->z)^mask)<0 ){
int len;
if( p->z && p->z!=p->zBuf ){
if( !p->zBuf[0] ){
sqliteFree(p->z);
}
len = strlen(argv[0]);
if( len < sizeof(p->zBuf) ){
p->z = p->zBuf;
if( len < sizeof(p->zBuf)-1 ){
p->z = &p->zBuf[1];
p->zBuf[0] = 1;
}else{
p->z = sqliteMalloc( len+1 );
p->zBuf[0] = 0;
if( p->z==0 ) return;
}
strcpy(p->z, argv[0]);
@ -532,7 +548,7 @@ static void minMaxFinalize(sqlite_func *context){
if( p && p->z ){
sqlite_set_result_string(context, p->z, strlen(p->z));
}
if( p && p->z && p->z!=p->zBuf ){
if( p && !p->zBuf[0] ){
sqliteFree(p->z);
}
}
@ -545,71 +561,86 @@ static void minMaxFinalize(sqlite_func *context){
void sqliteRegisterBuiltinFunctions(sqlite *db){
static struct {
char *zName;
int nArg;
int dataType;
signed char nArg;
signed char dataType;
u8 argType; /* 0: none. 1: db 2: (-1) */
void (*xFunc)(sqlite_func*,int,const char**);
} aFuncs[] = {
{ "min", -1, SQLITE_ARGS, minFunc },
{ "min", 0, 0, 0 },
{ "max", -1, SQLITE_ARGS, maxFunc },
{ "max", 0, 0, 0 },
{ "length", 1, SQLITE_NUMERIC, lengthFunc },
{ "substr", 3, SQLITE_TEXT, substrFunc },
{ "abs", 1, SQLITE_NUMERIC, absFunc },
{ "round", 1, SQLITE_NUMERIC, roundFunc },
{ "round", 2, SQLITE_NUMERIC, roundFunc },
{ "upper", 1, SQLITE_TEXT, upperFunc },
{ "lower", 1, SQLITE_TEXT, lowerFunc },
{ "coalesce", -1, SQLITE_ARGS, ifnullFunc },
{ "coalesce", 0, 0, 0 },
{ "coalesce", 1, 0, 0 },
{ "ifnull", 2, SQLITE_ARGS, ifnullFunc },
{ "random", -1, SQLITE_NUMERIC, randomFunc },
{ "like", 2, SQLITE_NUMERIC, likeFunc },
{ "glob", 2, SQLITE_NUMERIC, globFunc },
{ "nullif", 2, SQLITE_ARGS, nullifFunc },
{ "sqlite_version",0,SQLITE_TEXT, versionFunc},
{ "quote", 1, SQLITE_ARGS, quoteFunc },
{ "min", -1, SQLITE_ARGS, 0, minmaxFunc },
{ "min", 0, 0, 0, 0 },
{ "max", -1, SQLITE_ARGS, 2, minmaxFunc },
{ "max", 0, 0, 2, 0 },
{ "typeof", 1, SQLITE_TEXT, 0, typeofFunc },
{ "length", 1, SQLITE_NUMERIC, 0, lengthFunc },
{ "substr", 3, SQLITE_TEXT, 0, substrFunc },
{ "abs", 1, SQLITE_NUMERIC, 0, absFunc },
{ "round", 1, SQLITE_NUMERIC, 0, roundFunc },
{ "round", 2, SQLITE_NUMERIC, 0, roundFunc },
{ "upper", 1, SQLITE_TEXT, 0, upperFunc },
{ "lower", 1, SQLITE_TEXT, 0, lowerFunc },
{ "coalesce", -1, SQLITE_ARGS, 0, ifnullFunc },
{ "coalesce", 0, 0, 0, 0 },
{ "coalesce", 1, 0, 0, 0 },
{ "ifnull", 2, SQLITE_ARGS, 0, ifnullFunc },
{ "random", -1, SQLITE_NUMERIC, 0, randomFunc },
{ "like", 2, SQLITE_NUMERIC, 0, likeFunc },
{ "glob", 2, SQLITE_NUMERIC, 0, globFunc },
{ "nullif", 2, SQLITE_ARGS, 0, nullifFunc },
{ "sqlite_version",0,SQLITE_TEXT, 0, versionFunc},
{ "quote", 1, SQLITE_ARGS, 0, quoteFunc },
{ "last_insert_rowid", 0, SQLITE_NUMERIC, 1, last_insert_rowid },
{ "change_count", 0, SQLITE_NUMERIC, 1, change_count },
{ "last_statement_change_count",
0, SQLITE_NUMERIC, 1, last_statement_change_count },
#ifdef SQLITE_SOUNDEX
{ "soundex", 1, SQLITE_TEXT, soundexFunc},
{ "soundex", 1, SQLITE_TEXT, 0, soundexFunc},
#endif
#ifdef SQLITE_TEST
{ "randstr", 2, SQLITE_TEXT, randStr },
{ "randstr", 2, SQLITE_TEXT, 0, randStr },
#endif
};
static struct {
char *zName;
int nArg;
int dataType;
signed char nArg;
signed char dataType;
u8 argType;
void (*xStep)(sqlite_func*,int,const char**);
void (*xFinalize)(sqlite_func*);
} aAggs[] = {
{ "min", 1, 0, minStep, minMaxFinalize },
{ "max", 1, 0, maxStep, minMaxFinalize },
{ "sum", 1, SQLITE_NUMERIC, sumStep, sumFinalize },
{ "avg", 1, SQLITE_NUMERIC, sumStep, avgFinalize },
{ "count", 0, SQLITE_NUMERIC, countStep, countFinalize },
{ "count", 1, SQLITE_NUMERIC, countStep, countFinalize },
{ "min", 1, 0, 0, minmaxStep, minMaxFinalize },
{ "max", 1, 0, 2, minmaxStep, minMaxFinalize },
{ "sum", 1, SQLITE_NUMERIC, 0, sumStep, sumFinalize },
{ "avg", 1, SQLITE_NUMERIC, 0, sumStep, avgFinalize },
{ "count", 0, SQLITE_NUMERIC, 0, countStep, countFinalize },
{ "count", 1, SQLITE_NUMERIC, 0, countStep, countFinalize },
#if 0
{ "stddev", 1, SQLITE_NUMERIC, stdDevStep, stdDevFinalize },
{ "stddev", 1, SQLITE_NUMERIC, 0, stdDevStep, stdDevFinalize },
#endif
};
static const char *azTypeFuncs[] = { "min", "max", "typeof" };
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
void *pArg = aFuncs[i].argType==2 ? (void*)(-1) : db;
sqlite_create_function(db, aFuncs[i].zName,
aFuncs[i].nArg, aFuncs[i].xFunc, 0);
aFuncs[i].nArg, aFuncs[i].xFunc, pArg);
if( aFuncs[i].xFunc ){
sqlite_function_type(db, aFuncs[i].zName, aFuncs[i].dataType);
}
}
sqlite_create_function(db, "last_insert_rowid", 0,
last_insert_rowid, db);
sqlite_function_type(db, "last_insert_rowid", SQLITE_NUMERIC);
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
void *pArg = aAggs[i].argType==2 ? (void*)(-1) : db;
sqlite_create_aggregate(db, aAggs[i].zName,
aAggs[i].nArg, aAggs[i].xStep, aAggs[i].xFinalize, 0);
aAggs[i].nArg, aAggs[i].xStep, aAggs[i].xFinalize, pArg);
sqlite_function_type(db, aAggs[i].zName, aAggs[i].dataType);
}
for(i=0; i<sizeof(azTypeFuncs)/sizeof(azTypeFuncs[0]); i++){
int n = strlen(azTypeFuncs[i]);
FuncDef *p = sqliteHashFind(&db->aFunc, azTypeFuncs[i], n);
while( p ){
p->includeTypes = 1;
p = p->pNext;
}
}
sqliteRegisterDateTimeFunctions(db);
}

View file

@ -330,14 +330,7 @@ void sqliteInsert(
/* Open tables and indices if there are no row triggers */
if( !row_triggers_exist ){
base = pParse->nTab;
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
}
idx = sqliteOpenTableAndIndices(pParse, pTab, base);
pParse->nTab += idx;
}
@ -391,8 +384,7 @@ void sqliteInsert(
}
}
if( pColumn && j>=pColumn->nId ){
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
}else if( useTempTable ){
sqliteVdbeAddOp(v, OP_Column, srcTab, j);
}else if( pSelect ){
@ -416,14 +408,7 @@ void sqliteInsert(
*/
if( row_triggers_exist && !isView ){
base = pParse->nTab;
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, idx+base, pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
}
idx = sqliteOpenTableAndIndices(pParse, pTab, base);
pParse->nTab += idx;
}
@ -472,8 +457,7 @@ void sqliteInsert(
}
}
if( pColumn && j>=pColumn->nId ){
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
}else if( useTempTable ){
sqliteVdbeAddOp(v, OP_Column, srcTab, j);
}else if( pSelect ){
@ -535,14 +519,14 @@ void sqliteInsert(
}
}
sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
sqliteEndWriteOperation(pParse);
/*
** Return the number of rows inserted.
*/
if( db->flags & SQLITE_CountRows ){
sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC);
sqliteVdbeOp3(v, OP_ColumnName, 0, 1, "rows inserted", P3_STATIC);
sqliteVdbeAddOp(v, OP_MemLoad, iCntMem, 0);
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
}
@ -698,8 +682,7 @@ void sqliteGenerateConstraintChecks(
break;
}
case OE_Replace: {
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zDflt, P3_STATIC);
sqliteVdbeAddOp(v, OP_Push, nCol-i, 0);
break;
}
@ -741,8 +724,8 @@ void sqliteGenerateConstraintChecks(
case OE_Rollback:
case OE_Abort:
case OE_Fail: {
sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
sqliteVdbeChangeP3(v, -1, "PRIMARY KEY must be unique", P3_STATIC);
sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError,
"PRIMARY KEY must be unique", P3_STATIC);
break;
}
case OE_Replace: {
@ -839,8 +822,7 @@ void sqliteGenerateConstraintChecks(
}
strcpy(&zErrMsg[n1],
pIdx->nColumn>1 ? " are not unique" : " is not unique");
sqliteVdbeAddOp(v, OP_Halt, SQLITE_CONSTRAINT, onError);
sqliteVdbeChangeP3(v, -1, sqliteStrDup(zErrMsg), P3_DYNAMIC);
sqliteVdbeOp3(v, OP_Halt, SQLITE_CONSTRAINT, onError, zErrMsg, 0);
break;
}
case OE_Ignore: {
@ -906,8 +888,32 @@ void sqliteCompleteInsertion(
sqliteVdbeAddOp(v, OP_Dup, 1, 0);
sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
}
sqliteVdbeAddOp(v, OP_PutIntKey, base, pParse->trigStack?0:1);
sqliteVdbeAddOp(v, OP_PutIntKey, base,
(pParse->trigStack?0:OPFLAG_NCHANGE) |
(isUpdate?0:OPFLAG_LASTROWID) | OPFLAG_CSCHANGE);
if( isUpdate && recnoChng ){
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
}
}
/*
** Generate code that will open write cursors for a table and for all
** indices of that table. The "base" parameter is the cursor number used
** for the table. Indices are opened on subsequent cursors.
**
** Return the total number of cursors opened. This is always at least
** 1 (for the main table) plus more for each cursor.
*/
int sqliteOpenTableAndIndices(Parse *pParse, Table *pTab, int base){
int i;
Index *pIdx;
Vdbe *v = sqliteGetVdbe(pParse);
assert( v!=0 );
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeOp3(v, OP_OpenWrite, base, pTab->tnum, pTab->zName, P3_STATIC);
for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeOp3(v, OP_OpenWrite, i+base, pIdx->tnum, pIdx->zName, P3_STATIC);
}
return i;
}

View file

@ -33,8 +33,9 @@ typedef struct {
** Fill the InitData structure with an error message that indicates
** that the database is corrupt.
*/
static void corruptSchema(InitData *pData){
sqliteSetString(pData->pzErrMsg, "malformed database schema", (char*)0);
static void corruptSchema(InitData *pData, const char *zExtra){
sqliteSetString(pData->pzErrMsg, "malformed database schema",
zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
}
/*
@ -54,36 +55,39 @@ static void corruptSchema(InitData *pData){
static
int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
InitData *pData = (InitData*)pInit;
Parse sParse;
int nErr = 0;
assert( argc==5 );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
if( argv[0]==0 ){
corruptSchema(pData);
corruptSchema(pData, 0);
return 1;
}
switch( argv[0][0] ){
case 'v':
case 'i':
case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */
sqlite *db = pData->db;
if( argv[2]==0 || argv[4]==0 ){
corruptSchema(pData);
corruptSchema(pData, 0);
return 1;
}
if( argv[3] && argv[3][0] ){
/* Call the parser to process a CREATE TABLE, INDEX or VIEW.
** But because sParse.initFlag is set to 1, no VDBE code is generated
** But because db->init.busy is set to 1, no VDBE code is generated
** or executed. All the parser does is build the internal data
** structures that describe the table, index, or view.
*/
memset(&sParse, 0, sizeof(sParse));
sParse.db = pData->db;
sParse.initFlag = 1;
sParse.iDb = atoi(argv[4]);
sParse.newTnum = atoi(argv[2]);
sParse.useCallback = 1;
sqliteRunParser(&sParse, argv[3], pData->pzErrMsg);
char *zErr;
assert( db->init.busy );
db->init.iDb = atoi(argv[4]);
assert( db->init.iDb>=0 && db->init.iDb<db->nDb );
db->init.newTnum = atoi(argv[2]);
if( sqlite_exec(db, argv[3], 0, 0, &zErr) ){
corruptSchema(pData, zErr);
sqlite_freemem(zErr);
}
db->init.iDb = 0;
}else{
/* If the SQL column is blank it means this is an index that
** was created to be the PRIMARY KEY or to fulfill a UNIQUE
@ -95,8 +99,8 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
Index *pIndex;
iDb = atoi(argv[4]);
assert( iDb>=0 && iDb<pData->db->nDb );
pIndex = sqliteFindIndex(pData->db, argv[1], pData->db->aDb[iDb].zName);
assert( iDb>=0 && iDb<db->nDb );
pIndex = sqliteFindIndex(db, argv[1], db->aDb[iDb].zName);
if( pIndex==0 || pIndex->tnum!=0 ){
/* This can occur if there exists an index on a TEMP table which
** has the same name as another index on a permanent index. Since
@ -127,6 +131,9 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
** format version 1 or 2 to version 3. The correct operation of
** this routine relys on the fact that no indices are used when
** copying a table out to a temporary file.
**
** The change from version 2 to version 3 occurred between SQLite
** version 2.5.6 and 2.6.0 on 2002-July-18.
*/
static
int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
@ -150,8 +157,8 @@ int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
"DROP TABLE sqlite_x;",
0, 0, &zErr, argv[0], argv[0], argv[0]);
if( zErr ){
sqliteSetString(pData->pzErrMsg, zErr, (char*)0);
sqlite_freemem(zErr);
if( *pData->pzErrMsg ) sqlite_freemem(*pData->pzErrMsg);
*pData->pzErrMsg = zErr;
}
/* If an error occurred in the SQL above, then the transaction will
@ -185,7 +192,6 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
char *azArg[6];
char zDbNum[30];
int meta[SQLITE_N_BTREE_META];
Parse sParse;
InitData initData;
/*
@ -242,6 +248,7 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
/* Construct the schema tables: sqlite_master and sqlite_temp_master
*/
sqliteSafetyOff(db);
azArg[0] = "table";
azArg[1] = MASTER_NAME;
azArg[2] = "2";
@ -266,6 +273,7 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
pTab->readOnly = 1;
}
}
sqliteSafetyOn(db);
/* Create a cursor to hold the database open
*/
@ -292,6 +300,9 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
if( size==0 ){ size = MAX_PAGES; }
db->cache_size = size;
db->safety_level = meta[4];
if( meta[6]>0 && meta[6]<=2 && db->temp_store==0 ){
db->temp_store = meta[6];
}
if( db->safety_level==0 ) db->safety_level = 2;
/*
@ -327,31 +338,28 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
/* Read the schema information out of the schema tables
*/
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
sParse.xCallback = sqliteInitCallback;
sParse.pArg = (void*)&initData;
sParse.initFlag = 1;
sParse.useCallback = 1;
assert( db->init.busy );
sqliteSafetyOff(db);
if( iDb==0 ){
sqliteRunParser(&sParse,
rc = sqlite_exec(db,
db->file_format>=2 ? init_script : older_init_script,
pzErrMsg);
sqliteInitCallback, &initData, 0);
}else{
char *zSql = 0;
sqliteSetString(&zSql,
"SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
db->aDb[iDb].zName, "\".sqlite_master", (char*)0);
sqliteRunParser(&sParse, zSql, pzErrMsg);
rc = sqlite_exec(db, zSql, sqliteInitCallback, &initData, 0);
sqliteFree(zSql);
}
sqliteSafetyOn(db);
sqliteBtreeCloseCursor(curMain);
if( sqlite_malloc_failed ){
sqliteSetString(pzErrMsg, "out of memory", (char*)0);
sParse.rc = SQLITE_NOMEM;
rc = SQLITE_NOMEM;
sqliteResetInternalSchema(db, 0);
}
if( sParse.rc==SQLITE_OK ){
if( rc==SQLITE_OK ){
DbSetProperty(db, iDb, DB_SchemaLoaded);
if( iDb==0 ){
DbSetProperty(db, 1, DB_SchemaLoaded);
@ -359,7 +367,7 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
}else{
sqliteResetInternalSchema(db, iDb);
}
return sParse.rc;
return rc;
}
/*
@ -378,17 +386,58 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
int sqliteInit(sqlite *db, char **pzErrMsg){
int i, rc;
if( db->init.busy ) return SQLITE_OK;
assert( (db->flags & SQLITE_Initialized)==0 );
rc = SQLITE_OK;
db->init.busy = 1;
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue;
assert( i!=1 ); /* Should have been initialized together with 0 */
rc = sqliteInitOne(db, i, pzErrMsg);
if( rc ){
sqliteResetInternalSchema(db, i);
}
}
db->init.busy = 0;
if( rc==SQLITE_OK ){
db->flags |= SQLITE_Initialized;
sqliteCommitInternalChanges(db);
}else{
}
/* If the database is in formats 1 or 2, then upgrade it to
** version 3. This will reconstruct all indices. If the
** upgrade fails for any reason (ex: out of disk space, database
** is read only, interrupt received, etc.) then fail the init.
*/
if( rc==SQLITE_OK && db->file_format<3 ){
char *zErr = 0;
InitData initData;
int meta[SQLITE_N_BTREE_META];
db->magic = SQLITE_MAGIC_OPEN;
initData.db = db;
initData.pzErrMsg = &zErr;
db->file_format = 3;
rc = sqlite_exec(db,
"BEGIN; SELECT name FROM sqlite_master WHERE type='table';",
upgrade_3_callback,
&initData,
&zErr);
if( rc==SQLITE_OK ){
sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
meta[2] = 4;
sqliteBtreeUpdateMeta(db->aDb[0].pBt, meta);
sqlite_exec(db, "COMMIT", 0, 0, 0);
}
if( rc!=SQLITE_OK ){
sqliteSetString(pzErrMsg,
"unable to upgrade database to the version 2.6 format",
zErr ? ": " : 0, zErr, (char*)0);
}
sqlite_freemem(zErr);
}
if( rc!=SQLITE_OK ){
db->flags &= ~SQLITE_Initialized;
}
return rc;
@ -432,6 +481,7 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
db->magic = SQLITE_MAGIC_BUSY;
db->nDb = 2;
db->aDb = db->aDbStatic;
/* db->flags |= SQLITE_ShortColNames; */
sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1);
for(i=0; i<db->nDb; i++){
sqliteHashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0);
@ -475,42 +525,6 @@ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){
*pzErrMsg = 0;
}
/* If the database is in formats 1 or 2, then upgrade it to
** version 3. This will reconstruct all indices. If the
** upgrade fails for any reason (ex: out of disk space, database
** is read only, interrupt received, etc.) then refuse to open.
*/
if( rc==SQLITE_OK && db->file_format<3 ){
char *zErr = 0;
InitData initData;
int meta[SQLITE_N_BTREE_META];
initData.db = db;
initData.pzErrMsg = &zErr;
db->file_format = 3;
rc = sqlite_exec(db,
"BEGIN; SELECT name FROM sqlite_master WHERE type='table';",
upgrade_3_callback,
&initData,
&zErr);
if( rc==SQLITE_OK ){
sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
meta[2] = 4;
sqliteBtreeUpdateMeta(db->aDb[0].pBt, meta);
sqlite_exec(db, "COMMIT", 0, 0, 0);
}
if( rc!=SQLITE_OK ){
sqliteSetString(pzErrMsg,
"unable to upgrade database to the version 2.6 format",
zErr ? ": " : 0, zErr, (char*)0);
sqlite_freemem(zErr);
sqliteStrRealloc(pzErrMsg);
sqlite_close(db);
return 0;
}
sqlite_freemem(zErr);
}
/* Return a pointer to the newly opened database structure */
return db;
@ -534,6 +548,16 @@ int sqlite_changes(sqlite *db){
return db->nChange;
}
/*
** Return the number of changes produced by the last INSERT, UPDATE, or
** DELETE statement to complete execution. The count does not include
** changes due to SQL statements executed in trigger programs that were
** triggered by that statement
*/
int sqlite_last_statement_changes(sqlite *db){
return db->lsChange;
}
/*
** Close an existing SQLite database
*/
@ -547,13 +571,10 @@ void sqlite_close(sqlite *db){
}
db->magic = SQLITE_MAGIC_CLOSED;
for(j=0; j<db->nDb; j++){
if( db->aDb[j].pBt ){
sqliteBtreeClose(db->aDb[j].pBt);
db->aDb[j].pBt = 0;
}
if( j>=2 ){
sqliteFree(db->aDb[j].zName);
db->aDb[j].zName = 0;
struct Db *pDb = &db->aDb[j];
if( pDb->pBt ){
sqliteBtreeClose(pDb->pBt);
pDb->pBt = 0;
}
}
sqliteResetInternalSchema(db, 0);
@ -581,84 +602,8 @@ void sqliteRollbackAll(sqlite *db){
db->aDb[i].inTrans = 0;
}
}
sqliteRollbackInternalChanges(db);
}
/*
** This routine does the work of either sqlite_exec() or sqlite_compile().
** It works like sqlite_exec() if pVm==NULL and it works like sqlite_compile()
** otherwise.
*/
static int sqliteMain(
sqlite *db, /* The database on which the SQL executes */
const char *zSql, /* The SQL to be executed */
sqlite_callback xCallback, /* Invoke this callback routine */
void *pArg, /* First argument to xCallback() */
const char **pzTail, /* OUT: Next statement after the first */
sqlite_vm **ppVm, /* OUT: The virtual machine */
char **pzErrMsg /* OUT: Write error messages here */
){
Parse sParse;
if( pzErrMsg ) *pzErrMsg = 0;
if( sqliteSafetyOn(db) ) goto exec_misuse;
if( (db->flags & SQLITE_Initialized)==0 ){
int rc, cnt = 1;
while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY
&& db->xBusyCallback && db->xBusyCallback(db->pBusyArg, "", cnt++)!=0 ){}
if( rc!=SQLITE_OK ){
sqliteStrRealloc(pzErrMsg);
sqliteSafetyOff(db);
return rc;
}
if( pzErrMsg ){
sqliteFree(*pzErrMsg);
*pzErrMsg = 0;
}
}
if( db->file_format<3 ){
sqliteSafetyOff(db);
sqliteSetString(pzErrMsg, "obsolete database file format", (char*)0);
return SQLITE_ERROR;
}
if( db->pVdbe==0 ){ db->nChange = 0; }
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
sParse.xCallback = xCallback;
sParse.pArg = pArg;
sParse.useCallback = ppVm==0;
if( db->xTrace ) db->xTrace(db->pTraceArg, zSql);
sqliteRunParser(&sParse, zSql, pzErrMsg);
if( sqlite_malloc_failed ){
sqliteSetString(pzErrMsg, "out of memory", (char*)0);
sParse.rc = SQLITE_NOMEM;
sqliteRollbackAll(db);
sqliteResetInternalSchema(db, 0);
db->flags &= ~SQLITE_InTrans;
}
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){
sqliteSetString(pzErrMsg, sqlite_error_string(sParse.rc), (char*)0);
}
sqliteStrRealloc(pzErrMsg);
if( sParse.rc==SQLITE_SCHEMA ){
sqliteResetInternalSchema(db, 0);
}
if( sParse.useCallback==0 ){
assert( ppVm );
*ppVm = (sqlite_vm*)sParse.pVdbe;
if( pzTail ) *pzTail = sParse.zTail;
}
if( sqliteSafetyOff(db) ) goto exec_misuse;
return sParse.rc;
exec_misuse:
if( pzErrMsg ){
*pzErrMsg = 0;
sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0);
sqliteStrRealloc(pzErrMsg);
}
return SQLITE_MISUSE;
sqliteResetInternalSchema(db, 0);
/* sqliteRollbackInternalChanges(db); */
}
/*
@ -678,9 +623,62 @@ int sqlite_exec(
void *pArg, /* First argument to xCallback() */
char **pzErrMsg /* Write error messages here */
){
return sqliteMain(db, zSql, xCallback, pArg, 0, 0, pzErrMsg);
int rc = SQLITE_OK;
const char *zLeftover;
sqlite_vm *pVm;
int nRetry = 0;
int nChange = 0;
int nCallback;
if( zSql==0 ) return SQLITE_OK;
while( rc==SQLITE_OK && zSql[0] ){
pVm = 0;
rc = sqlite_compile(db, zSql, &zLeftover, &pVm, pzErrMsg);
if( rc!=SQLITE_OK ){
assert( pVm==0 || sqlite_malloc_failed );
return rc;
}
if( pVm==0 ){
/* This happens if the zSql input contained only whitespace */
break;
}
db->nChange += nChange;
nCallback = 0;
while(1){
int nArg;
char **azArg, **azCol;
rc = sqlite_step(pVm, &nArg, (const char***)&azArg,(const char***)&azCol);
if( rc==SQLITE_ROW ){
if( xCallback!=0 && xCallback(pArg, nArg, azArg, azCol) ){
sqlite_finalize(pVm, 0);
return SQLITE_ABORT;
}
nCallback++;
}else{
if( rc==SQLITE_DONE && nCallback==0
&& (db->flags & SQLITE_NullCallback)!=0 && xCallback!=0 ){
xCallback(pArg, nArg, azArg, azCol);
}
rc = sqlite_finalize(pVm, pzErrMsg);
if( rc==SQLITE_SCHEMA && nRetry<2 ){
nRetry++;
rc = SQLITE_OK;
break;
}
if( db->pVdbe==0 ){
nChange = db->nChange;
}
nRetry = 0;
zSql = zLeftover;
while( isspace(zSql[0]) ) zSql++;
break;
}
}
}
return rc;
}
/*
** Compile a single statement of SQL into a virtual machine. Return one
** of the SQLITE_ success/failure codes. Also write an error message into
@ -693,7 +691,88 @@ int sqlite_compile(
sqlite_vm **ppVm, /* OUT: The virtual machine */
char **pzErrMsg /* OUT: Write error messages here */
){
return sqliteMain(db, zSql, 0, 0, pzTail, ppVm, pzErrMsg);
Parse sParse;
if( pzErrMsg ) *pzErrMsg = 0;
if( sqliteSafetyOn(db) ) goto exec_misuse;
if( !db->init.busy ){
if( (db->flags & SQLITE_Initialized)==0 ){
int rc, cnt = 1;
while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY
&& db->xBusyCallback
&& db->xBusyCallback(db->pBusyArg, "", cnt++)!=0 ){}
if( rc!=SQLITE_OK ){
sqliteStrRealloc(pzErrMsg);
sqliteSafetyOff(db);
return rc;
}
if( pzErrMsg ){
sqliteFree(*pzErrMsg);
*pzErrMsg = 0;
}
}
if( db->file_format<3 ){
sqliteSafetyOff(db);
sqliteSetString(pzErrMsg, "obsolete database file format", (char*)0);
return SQLITE_ERROR;
}
}
assert( (db->flags & SQLITE_Initialized)!=0 || db->init.busy );
if( db->pVdbe==0 ){ db->nChange = 0; }
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
sqliteRunParser(&sParse, zSql, pzErrMsg);
if( db->xTrace && !db->init.busy ){
/* Trace only the statment that was compiled.
** Make a copy of that part of the SQL string since zSQL is const
** and we must pass a zero terminated string to the trace function
** The copy is unnecessary if the tail pointer is pointing at the
** beginnig or end of the SQL string.
*/
if( sParse.zTail && sParse.zTail!=zSql && *sParse.zTail ){
char *tmpSql = sqliteStrNDup(zSql, sParse.zTail - zSql);
if( tmpSql ){
db->xTrace(db->pTraceArg, tmpSql);
free(tmpSql);
}else{
/* If a memory error occurred during the copy,
** trace entire SQL string and fall through to the
** sqlite_malloc_failed test to report the error.
*/
db->xTrace(db->pTraceArg, zSql);
}
}else{
db->xTrace(db->pTraceArg, zSql);
}
}
if( sqlite_malloc_failed ){
sqliteSetString(pzErrMsg, "out of memory", (char*)0);
sParse.rc = SQLITE_NOMEM;
sqliteRollbackAll(db);
sqliteResetInternalSchema(db, 0);
db->flags &= ~SQLITE_InTrans;
}
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){
sqliteSetString(pzErrMsg, sqlite_error_string(sParse.rc), (char*)0);
}
sqliteStrRealloc(pzErrMsg);
if( sParse.rc==SQLITE_SCHEMA ){
sqliteResetInternalSchema(db, 0);
}
assert( ppVm );
*ppVm = (sqlite_vm*)sParse.pVdbe;
if( pzTail ) *pzTail = sParse.zTail;
if( sqliteSafetyOff(db) ) goto exec_misuse;
return sParse.rc;
exec_misuse:
if( pzErrMsg ){
*pzErrMsg = 0;
sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0);
sqliteStrRealloc(pzErrMsg);
}
return SQLITE_MISUSE;
}
@ -729,7 +808,7 @@ int sqlite_reset(
char **pzErrMsg /* OUT: Write error messages here */
){
int rc = sqliteVdbeReset((Vdbe*)pVm, pzErrMsg);
sqliteVdbeMakeReady((Vdbe*)pVm, -1, 0, 0, 0);
sqliteVdbeMakeReady((Vdbe*)pVm, -1, 0);
sqliteStrRealloc(pzErrMsg);
return rc;
}
@ -767,6 +846,7 @@ const char *sqlite_error_string(int rc){
case SQLITE_AUTH: z = "authorization denied"; break;
case SQLITE_FORMAT: z = "auxiliary database format error"; break;
case SQLITE_RANGE: z = "bind index out of range"; break;
case SQLITE_NOTADB: z = "file is encrypted or is not a database";break;
default: z = "unknown error"; break;
}
return z;
@ -784,22 +864,23 @@ static int sqliteDefaultBusyCallback(
int count /* Number of times table has been busy */
){
#if SQLITE_MIN_SLEEP_MS==1
int delay = 10;
int prior_delay = 0;
static const char delays[] =
{ 1, 2, 5, 10, 15, 20, 25, 25, 25, 50, 50, 50, 100};
static const short int totals[] =
{ 0, 1, 3, 8, 18, 33, 53, 78, 103, 128, 178, 228, 287};
# define NDELAY (sizeof(delays)/sizeof(delays[0]))
int timeout = (int)(long)Timeout;
int i;
int delay, prior;
for(i=1; i<count; i++){
prior_delay += delay;
delay = delay*2;
if( delay>=1000 ){
delay = 1000;
prior_delay += 1000*(count - i - 1);
break;
}
if( count <= NDELAY ){
delay = delays[count-1];
prior = totals[count-1];
}else{
delay = delays[NDELAY-1];
prior = totals[NDELAY-1] + delay*(count-NDELAY-1);
}
if( prior_delay + delay > timeout ){
delay = timeout - prior_delay;
if( prior + delay > timeout ){
delay = timeout - prior;
if( delay<=0 ) return 0;
}
sqliteOsSleep(delay);
@ -856,9 +937,9 @@ void sqlite_progress_handler(
** This routine installs a default busy handler that waits for the
** specified number of milliseconds before returning 0.
*/
void sqlite_busy_timeout(sqlite *db, long ms){
void sqlite_busy_timeout(sqlite *db, int ms){
if( ms>0 ){
sqlite_busy_handler(db, sqliteDefaultBusyCallback, (void*)ms);
sqlite_busy_handler(db, sqliteDefaultBusyCallback, (void*)(long)ms);
}else{
sqlite_busy_handler(db, 0, 0);
}
@ -903,7 +984,7 @@ const char *sqlite_libencoding(void){ return sqlite_encoding; }
** sqlite_create_aggregate(), and vice versa.
**
** If nArg is -1 it means that this function will accept any number
** of arguments, including 0.
** of arguments, including 0. The maximum allowed value of nArg is 127.
*/
int sqlite_create_function(
sqlite *db, /* Add the function to this database connection */
@ -915,6 +996,7 @@ int sqlite_create_function(
FuncDef *p;
int nName;
if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1;
if( nArg<-1 || nArg>127 ) return 1;
nName = strlen(zName);
if( nName>255 ) return 1;
p = sqliteFindFunction(db, zName, nName, nArg, 1);
@ -936,6 +1018,7 @@ int sqlite_create_aggregate(
FuncDef *p;
int nName;
if( db==0 || zName==0 || sqliteSafetyCheck(db) ) return 1;
if( nArg<-1 || nArg>127 ) return 1;
nName = strlen(zName);
if( nName>255 ) return 1;
p = sqliteFindFunction(db, zName, nName, nArg, 1);
@ -976,6 +1059,24 @@ void *sqlite_trace(sqlite *db, void (*xTrace)(void*,const char*), void *pArg){
return pOld;
}
/*** EXPERIMENTAL ***
**
** Register a function to be invoked when a transaction comments.
** If either function returns non-zero, then the commit becomes a
** rollback.
*/
void *sqlite_commit_hook(
sqlite *db, /* Attach the hook to this database */
int (*xCallback)(void*), /* Function to invoke on each commit */
void *pArg /* Argument to the function */
){
void *pOld = db->pCommitArg;
db->xCommitCallback = xCallback;
db->pCommitArg = pArg;
return pOld;
}
/*
** This routine is called to create a connection to a database BTree
** driver. If zFilename is the name of a file, then that file is

View file

@ -13,7 +13,6 @@ char *sqliteOpcodeNames[] = { "???",
"Push",
"ColumnName",
"Callback",
"NullCallback",
"Concat",
"Add",
"Subtract",
@ -26,7 +25,7 @@ char *sqliteOpcodeNames[] = { "???",
"ShiftLeft",
"ShiftRight",
"AddImm",
"IsNumeric",
"ForceInt",
"MustBeInt",
"Eq",
"Ne",
@ -78,6 +77,7 @@ char *sqliteOpcodeNames[] = { "???",
"PutIntKey",
"PutStrKey",
"Delete",
"SetCounts",
"KeyAsData",
"RowKey",
"RowData",
@ -107,6 +107,8 @@ char *sqliteOpcodeNames[] = { "???",
"ListReset",
"ListPush",
"ListPop",
"ContextPush",
"ContextPop",
"SortPut",
"SortMakeRec",
"SortMakeKey",
@ -133,4 +135,6 @@ char *sqliteOpcodeNames[] = { "???",
"SetFirst",
"SetNext",
"Vacuum",
"StackDepth",
"StackReset",
};

View file

@ -12,71 +12,71 @@
#define OP_Push 11
#define OP_ColumnName 12
#define OP_Callback 13
#define OP_NullCallback 14
#define OP_Concat 15
#define OP_Add 16
#define OP_Subtract 17
#define OP_Multiply 18
#define OP_Divide 19
#define OP_Remainder 20
#define OP_Function 21
#define OP_BitAnd 22
#define OP_BitOr 23
#define OP_ShiftLeft 24
#define OP_ShiftRight 25
#define OP_AddImm 26
#define OP_IsNumeric 27
#define OP_MustBeInt 28
#define OP_Eq 29
#define OP_Ne 30
#define OP_Lt 31
#define OP_Le 32
#define OP_Gt 33
#define OP_Ge 34
#define OP_StrEq 35
#define OP_StrNe 36
#define OP_StrLt 37
#define OP_StrLe 38
#define OP_StrGt 39
#define OP_StrGe 40
#define OP_And 41
#define OP_Or 42
#define OP_Negative 43
#define OP_AbsValue 44
#define OP_Not 45
#define OP_BitNot 46
#define OP_Noop 47
#define OP_If 48
#define OP_IfNot 49
#define OP_IsNull 50
#define OP_NotNull 51
#define OP_MakeRecord 52
#define OP_MakeIdxKey 53
#define OP_MakeKey 54
#define OP_IncrKey 55
#define OP_Checkpoint 56
#define OP_Transaction 57
#define OP_Commit 58
#define OP_Rollback 59
#define OP_ReadCookie 60
#define OP_SetCookie 61
#define OP_VerifyCookie 62
#define OP_OpenRead 63
#define OP_OpenWrite 64
#define OP_OpenTemp 65
#define OP_OpenPseudo 66
#define OP_Close 67
#define OP_MoveLt 68
#define OP_MoveTo 69
#define OP_Distinct 70
#define OP_NotFound 71
#define OP_Found 72
#define OP_IsUnique 73
#define OP_NotExists 74
#define OP_NewRecno 75
#define OP_PutIntKey 76
#define OP_PutStrKey 77
#define OP_Delete 78
#define OP_Concat 14
#define OP_Add 15
#define OP_Subtract 16
#define OP_Multiply 17
#define OP_Divide 18
#define OP_Remainder 19
#define OP_Function 20
#define OP_BitAnd 21
#define OP_BitOr 22
#define OP_ShiftLeft 23
#define OP_ShiftRight 24
#define OP_AddImm 25
#define OP_ForceInt 26
#define OP_MustBeInt 27
#define OP_Eq 28
#define OP_Ne 29
#define OP_Lt 30
#define OP_Le 31
#define OP_Gt 32
#define OP_Ge 33
#define OP_StrEq 34
#define OP_StrNe 35
#define OP_StrLt 36
#define OP_StrLe 37
#define OP_StrGt 38
#define OP_StrGe 39
#define OP_And 40
#define OP_Or 41
#define OP_Negative 42
#define OP_AbsValue 43
#define OP_Not 44
#define OP_BitNot 45
#define OP_Noop 46
#define OP_If 47
#define OP_IfNot 48
#define OP_IsNull 49
#define OP_NotNull 50
#define OP_MakeRecord 51
#define OP_MakeIdxKey 52
#define OP_MakeKey 53
#define OP_IncrKey 54
#define OP_Checkpoint 55
#define OP_Transaction 56
#define OP_Commit 57
#define OP_Rollback 58
#define OP_ReadCookie 59
#define OP_SetCookie 60
#define OP_VerifyCookie 61
#define OP_OpenRead 62
#define OP_OpenWrite 63
#define OP_OpenTemp 64
#define OP_OpenPseudo 65
#define OP_Close 66
#define OP_MoveLt 67
#define OP_MoveTo 68
#define OP_Distinct 69
#define OP_NotFound 70
#define OP_Found 71
#define OP_IsUnique 72
#define OP_NotExists 73
#define OP_NewRecno 74
#define OP_PutIntKey 75
#define OP_PutStrKey 76
#define OP_Delete 77
#define OP_SetCounts 78
#define OP_KeyAsData 79
#define OP_RowKey 80
#define OP_RowData 81
@ -106,29 +106,33 @@
#define OP_ListReset 105
#define OP_ListPush 106
#define OP_ListPop 107
#define OP_SortPut 108
#define OP_SortMakeRec 109
#define OP_SortMakeKey 110
#define OP_Sort 111
#define OP_SortNext 112
#define OP_SortCallback 113
#define OP_SortReset 114
#define OP_FileOpen 115
#define OP_FileRead 116
#define OP_FileColumn 117
#define OP_MemStore 118
#define OP_MemLoad 119
#define OP_MemIncr 120
#define OP_AggReset 121
#define OP_AggInit 122
#define OP_AggFunc 123
#define OP_AggFocus 124
#define OP_AggSet 125
#define OP_AggGet 126
#define OP_AggNext 127
#define OP_SetInsert 128
#define OP_SetFound 129
#define OP_SetNotFound 130
#define OP_SetFirst 131
#define OP_SetNext 132
#define OP_Vacuum 133
#define OP_ContextPush 108
#define OP_ContextPop 109
#define OP_SortPut 110
#define OP_SortMakeRec 111
#define OP_SortMakeKey 112
#define OP_Sort 113
#define OP_SortNext 114
#define OP_SortCallback 115
#define OP_SortReset 116
#define OP_FileOpen 117
#define OP_FileRead 118
#define OP_FileColumn 119
#define OP_MemStore 120
#define OP_MemLoad 121
#define OP_MemIncr 122
#define OP_AggReset 123
#define OP_AggInit 124
#define OP_AggFunc 125
#define OP_AggFocus 126
#define OP_AggSet 127
#define OP_AggGet 128
#define OP_AggNext 129
#define OP_SetInsert 130
#define OP_SetFound 131
#define OP_SetNotFound 132
#define OP_SetFirst 133
#define OP_SetNext 134
#define OP_Vacuum 135
#define OP_StackDepth 136
#define OP_StackReset 137

View file

@ -34,9 +34,6 @@
# ifndef O_BINARY
# define O_BINARY 0
# endif
# ifndef EISDIR
# define EISDIR 21
# endif
#endif
@ -467,9 +464,11 @@ int sqliteOsOpenReadWrite(
id->dirfd = -1;
id->fd = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644);
if( id->fd<0 ){
if (errno == EISDIR) {
#ifdef EISDIR
if( errno==EISDIR ){
return SQLITE_CANTOPEN;
}
#endif
id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY);
if( id->fd<0 ){
return SQLITE_CANTOPEN;
@ -779,6 +778,13 @@ int sqliteOsOpenDirectory(
return SQLITE_OK;
}
/*
** If the following global variable points to a string which is the
** name of a directory, then that directory will be used to store
** temporary files.
*/
const char *sqlite_temp_directory = 0;
/*
** Create a temporary file name in zBuf. zBuf must be big enough to
** hold at least SQLITE_TEMPNAME_SIZE characters.
@ -786,19 +792,22 @@ int sqliteOsOpenDirectory(
int sqliteOsTempFileName(char *zBuf){
#if OS_UNIX
static const char *azDirs[] = {
0,
"/var/tmp",
"/usr/tmp",
"/tmp",
".",
};
static char zChars[] =
static unsigned char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
int i, j;
struct stat buf;
const char *zDir = ".";
azDirs[0] = sqlite_temp_directory;
for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
if( azDirs[i]==0 ) continue;
if( stat(azDirs[i], &buf) ) continue;
if( !S_ISDIR(buf.st_mode) ) continue;
if( access(azDirs[i], 07) ) continue;
@ -808,9 +817,9 @@ int sqliteOsTempFileName(char *zBuf){
do{
sprintf(zBuf, "%s/"TEMP_FILE_PREFIX, zDir);
j = strlen(zBuf);
for(i=0; i<15; i++){
int n = sqliteRandomByte() % (sizeof(zChars)-1);
zBuf[j++] = zChars[n];
sqliteRandomness(15, &zBuf[j]);
for(i=0; i<15; i++, j++){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
}while( access(zBuf,0)==0 );
@ -821,16 +830,22 @@ int sqliteOsTempFileName(char *zBuf){
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
int i, j;
char *zDir;
char zTempPath[SQLITE_TEMPNAME_SIZE];
GetTempPath(SQLITE_TEMPNAME_SIZE-30, zTempPath);
for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
zTempPath[i] = 0;
if( sqlite_temp_directory==0 ){
GetTempPath(SQLITE_TEMPNAME_SIZE-30, zTempPath);
for(i=strlen(zTempPath); i>0 && zTempPath[i-1]=='\\'; i--){}
zTempPath[i] = 0;
zDir = zTempPath;
}else{
zDir = sqlite_temp_directory;
}
for(;;){
sprintf(zBuf, "%s\\"TEMP_FILE_PREFIX, zTempPath);
sprintf(zBuf, "%s\\"TEMP_FILE_PREFIX, zDir);
j = strlen(zBuf);
for(i=0; i<15; i++){
int n = sqliteRandomByte() % (sizeof(zChars) - 1);
zBuf[j++] = zChars[n];
sqliteRandomness(15, &zBuf[j]);
for(i=0; i<15; i++, j++){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
if( !sqliteOsFileExists(zBuf) ) break;
@ -842,13 +857,16 @@ int sqliteOsTempFileName(char *zBuf){
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
int i, j;
char *zDir;
char zTempPath[SQLITE_TEMPNAME_SIZE];
char zdirName[32];
CInfoPBRec infoRec;
Str31 dirName;
memset(&infoRec, 0, sizeof(infoRec));
memset(zTempPath, 0, SQLITE_TEMPNAME_SIZE);
if( FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
if( sqlite_temp_directory!=0 ){
zDir = sqlite_temp_directory;
}else if( FindFolder(kOnSystemDisk, kTemporaryFolderType, kCreateFolder,
&(infoRec.dirInfo.ioVRefNum), &(infoRec.dirInfo.ioDrParID)) == noErr ){
infoRec.dirInfo.ioNamePtr = dirName;
do{
@ -865,15 +883,18 @@ int sqliteOsTempFileName(char *zBuf){
break;
}
} while( infoRec.dirInfo.ioDrDirID != fsRtDirID );
zDir = zTempPath;
}
if( *zTempPath == 0 )
if( zDir[0]==0 ){
getcwd(zTempPath, SQLITE_TEMPNAME_SIZE-24);
zDir = zTempPath;
}
for(;;){
sprintf(zBuf, "%s"TEMP_FILE_PREFIX, zTempPath);
sprintf(zBuf, "%s"TEMP_FILE_PREFIX, zDir);
j = strlen(zBuf);
for(i=0; i<15; i++){
int n = sqliteRandomByte() % sizeof(zChars);
zBuf[j++] = zChars[n];
sqliteRandomness(15, &zBuf[j]);
for(i=0; i<15; i++, j++){
zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ];
}
zBuf[j] = 0;
if( !sqliteOsFileExists(zBuf) ) break;
@ -1220,7 +1241,7 @@ int sqliteOsFileSize(OsFile *id, off_t *pSize){
** the LockFileEx() API.
*/
int isNT(void){
static osType = 0; /* 0=unknown 1=win95 2=winNT */
static int osType = 0; /* 0=unknown 1=win95 2=winNT */
if( osType==0 ){
OSVERSIONINFO sInfo;
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
@ -1331,9 +1352,11 @@ int sqliteOsReadLock(OsFile *id){
if( id->locked>0 ){
rc = SQLITE_OK;
}else{
int lk = (sqliteRandomInteger() & 0x7ffffff)%N_LOCKBYTE+1;
int lk;
int res;
int cnt = 100;
sqliteRandomness(sizeof(lk), &lk);
lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
while( cnt-->0 && (res = LockFile(id->h, FIRST_LOCKBYTE, 0, 1, 0))==0 ){
Sleep(1);
}
@ -1365,10 +1388,12 @@ int sqliteOsReadLock(OsFile *id){
if( id->locked>0 || id->refNumRF == -1 ){
rc = SQLITE_OK;
}else{
int lk = (sqliteRandomInteger() & 0x7ffffff)%N_LOCKBYTE+1;
int lk;
OSErr res;
int cnt = 5;
ParamBlockRec params;
sqliteRandomness(sizeof(lk), &lk);
lk = (lk & 0x7fffffff)%N_LOCKBYTE + 1;
memset(&params, 0, sizeof(params));
params.ioParam.ioRefNum = id->refNumRF;
params.ioParam.ioPosMode = fsFromStart;
@ -1783,7 +1808,7 @@ char *sqliteOsFullPathname(const char *zRelative){
}
/*
** The following variable, if set to a now-zero value, become the result
** The following variable, if set to a non-zero value, becomes the result
** returned from sqliteOsCurrentTime(). This is used for testing.
*/
#ifdef SQLITE_TEST

View file

@ -39,7 +39,9 @@
*/
#ifndef SQLITE_DISABLE_LFS
# define _LARGE_FILE 1
# define _FILE_OFFSET_BITS 64
# ifndef _FILE_OFFSET_BITS
# define _FILE_OFFSET_BITS 64
# endif
# define _LARGEFILE_SOURCE 1
#endif
@ -118,9 +120,6 @@
#endif
#if OS_WIN
# if defined(__CYGWIN__)
# define __CYGWIN_USE_BIG_TYPES__
# endif
#include <windows.h>
#include <winbase.h>
typedef struct OsFile OsFile;

View file

@ -84,6 +84,19 @@ static Pager *mainPager = 0;
** Each in-memory image of a page begins with the following header.
** This header is only visible to this pager module. The client
** code that calls pager sees only the data that follows the header.
**
** Client code should call sqlitepager_write() on a page prior to making
** any modifications to that page. The first time sqlitepager_write()
** is called, the original page contents are written into the rollback
** journal and PgHdr.inJournal and PgHdr.needSync are set. Later, once
** the journal page has made it onto the disk surface, PgHdr.needSync
** is cleared. The modified page cannot be written back into the original
** database file until the journal pages has been synced to disk and the
** PgHdr.needSync has been cleared.
**
** The PgHdr.dirty flag is set when sqlitepager_write() is called and
** is cleared again when the page content is written back to the original
** database file.
*/
typedef struct PgHdr PgHdr;
struct PgHdr {
@ -104,6 +117,16 @@ struct PgHdr {
/* Pager.nExtra bytes of local data follow the page data */
};
/*
** 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); }
#else
# define CODEC(P,D,N,X)
#endif
/*
** Convert a pointer to a PgHdr into a pointer to its data
** and back again.
@ -145,9 +168,11 @@ struct Pager {
int nRef; /* Number of in-memory pages with PgHdr.nRef>0 */
int mxPage; /* Maximum number of pages to hold in cache */
int nHit, nMiss, nOvfl; /* Cache hits, missing, and LRU overflows */
void (*xCodec)(void*,void*,Pgno,int); /* Routine for en/decoding data */
void *pCodecArg; /* First argument to xCodec() */
u8 journalOpen; /* True if journal file descriptors is valid */
u8 journalStarted; /* True if initial magic of journal is synced */
u8 useJournal; /* Do not use a rollback journal on this file */
u8 journalStarted; /* True if header of journal is synced */
u8 useJournal; /* Use a rollback journal on this file */
u8 ckptOpen; /* True if the checkpoint journal is open */
u8 ckptInUse; /* True we are in a checkpoint */
u8 ckptAutoopen; /* Open ckpt journal when main journal is opened*/
@ -188,8 +213,8 @@ struct Pager {
*/
typedef struct PageRecord PageRecord;
struct PageRecord {
Pgno pgno; /* The page number */
char aData[SQLITE_PAGE_SIZE]; /* Original data for page pgno */
Pgno pgno; /* The page number */
char aData[SQLITE_PAGE_SIZE]; /* Original data for page pgno */
};
/*
@ -279,7 +304,13 @@ int journal_format = 3;
#endif
/*
** Read a 32-bit integer from the given file descriptor
** 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
** error code is something goes wrong.
**
** If the journal format is 2 or 3, read a big-endian integer. If the
** journal format is 1, read an integer in the native byte-order of the
** host machine.
*/
static int read32bits(int format, OsFile *fd, u32 *pRes){
u32 res;
@ -295,8 +326,13 @@ static int read32bits(int format, OsFile *fd, u32 *pRes){
}
/*
** Write a 32-bit integer into the given file descriptor. Writing
** is always done using the new journal format.
** Write a 32-bit integer into the given file descriptor. Return SQLITE_OK
** on success or an error code is something goes wrong.
**
** If the journal format is 2 or 3, write the integer as 4 big-endian
** bytes. If the journal format is 1, write the integer in the native
** byte order. In normal operation, only formats 2 and 3 are used.
** Journal format 1 is only used for testing.
*/
static int write32bits(OsFile *fd, u32 val){
unsigned char ac[4];
@ -313,6 +349,9 @@ static int write32bits(OsFile *fd, u32 val){
/*
** Write a 32-bit integer into a page header right before the
** page data. This will overwrite the PgHdr.pDirty pointer.
**
** The integer is big-endian for formats 2 and 3 and native byte order
** for journal format 1.
*/
static void store32bits(u32 val, PgHdr *p, int offset){
unsigned char *ac;
@ -469,6 +508,10 @@ static int pager_unwritelock(Pager *pPager){
/*
** Compute and return a checksum for the page of data.
**
** This is not a real checksum. It is really just the sum of the
** random initial value and the page number. We considered do a checksum
** of the database, but that was found to be too slow.
*/
static u32 pager_cksum(Pager *pPager, Pgno pgno, const char *aData){
u32 cksum = pPager->cksumInit + pgno;
@ -529,6 +572,7 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int format){
memset(PGHDR_TO_EXTRA(pPg), 0, pPager->nExtra);
pPg->dirty = 0;
pPg->needSync = 0;
CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
}
return rc;
}
@ -537,21 +581,53 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int format){
** Playback the journal and thus restore the database file to
** the state it was in before we started making changes.
**
** The journal file format is as follows: There is an initial
** file-type string for sanity checking. Then there is a single
** Pgno number which is the number of pages in the database before
** changes were made. The database is truncated to this size.
** Next come zero or more page records where each page record
** consists of a Pgno and SQLITE_PAGE_SIZE bytes of data. See
** the PageRecord structure for details.
** The journal file format is as follows:
**
** * 8 byte prefix. One of the aJournalMagic123 vectors defined
** above. The format of the journal file is determined by which
** of the three prefix vectors is seen.
** * 4 byte big-endian integer which is the number of valid page records
** in the journal. If this value is 0xffffffff, then compute the
** number of page records from the journal size. This field appears
** in format 3 only.
** * 4 byte big-endian integer which is the initial value for the
** sanity checksum. This field appears in format 3 only.
** * 4 byte integer which is the number of pages to truncate the
** database to during a rollback.
** * Zero or more pages instances, each as follows:
** + 4 byte page number.
** + SQLITE_PAGE_SIZE bytes of data.
** + 4 byte checksum (format 3 only)
**
** When we speak of the journal header, we mean the first 4 bullets above.
** Each entry in the journal is an instance of the 5th bullet. Note that
** bullets 2 and 3 only appear in format-3 journals.
**
** Call the value from the second bullet "nRec". nRec is the number of
** valid page entries in the journal. In most cases, you can compute the
** value of nRec from the size of the journal file. But if a power
** failure occurred while the journal was being written, it could be the
** case that the size of the journal file had already been increased but
** the extra entries had not yet made it safely to disk. In such a case,
** the value of nRec computed from the file size would be too large. For
** that reason, we always use the nRec value in the header.
**
** If the nRec value is 0xffffffff it means that nRec should be computed
** from the file size. This value is used when the user selects the
** no-sync option for the journal. A power failure could lead to corruption
** in this case. But for things like temporary table (which will be
** deleted when the power is restored) we don't care.
**
** Journal formats 1 and 2 do not have an nRec value in the header so we
** have to compute nRec from the file size. This has risks (as described
** above) which is why all persistent tables have been changed to use
** format 3.
**
** If the file opened as the journal file is not a well-formed
** journal file (as determined by looking at the magic number
** at the beginning) then this routine returns SQLITE_PROTOCOL.
** If any other errors occur during playback, the database will
** likely be corrupted, so the PAGER_ERR_CORRUPT bit is set in
** pPager->errMask and SQLITE_CORRUPT is returned. If it all
** works, then this routine returns SQLITE_OK.
** journal file then the database will likely already be
** corrupted, so the PAGER_ERR_CORRUPT bit is set in pPager->errMask
** and SQLITE_CORRUPT is returned. If it all works, then this routine
** returns SQLITE_OK.
*/
static int pager_playback(Pager *pPager, int useJournalSize){
off_t szJ; /* Size of the journal file in bytes */
@ -571,6 +647,13 @@ static int pager_playback(Pager *pPager, int useJournalSize){
if( rc!=SQLITE_OK ){
goto end_playback;
}
/* If the journal file is too small to contain a complete header,
** it must mean that the process that created the journal was just
** beginning to write the journal file when it died. In that case,
** the database file should have still been completely unchanged.
** Nothing needs to be rolled back. We can safely ignore this journal.
*/
if( szJ < sizeof(aMagic)+sizeof(Pgno) ){
goto end_playback;
}
@ -594,6 +677,15 @@ static int pager_playback(Pager *pPager, int useJournalSize){
goto end_playback;
}
if( format>=JOURNAL_FORMAT_3 ){
if( szJ < sizeof(aMagic) + 3*sizeof(u32) ){
/* Ignore the journal if it is too small to contain a complete
** header. We already did this test once above, but at the prior
** test, we did not know the journal format and so we had to assume
** the smallest possible header. Now we know the header is bigger
** than the minimum so we test again.
*/
goto end_playback;
}
rc = read32bits(format, &pPager->jfd, (u32*)&nRec);
if( rc ) goto end_playback;
rc = read32bits(format, &pPager->jfd, &pPager->cksumInit);
@ -630,7 +722,7 @@ static int pager_playback(Pager *pPager, int useJournalSize){
/* 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 the back from the original database.
** pages by reading them back from the original database.
*/
if( rc==SQLITE_OK ){
PgHdr *pPg;
@ -640,6 +732,8 @@ static int pager_playback(Pager *pPager, int useJournalSize){
if( (int)pPg->pgno <= pPager->origDbSize ){
sqliteOsSeek(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)(pPg->pgno-1));
rc = sqliteOsRead(&pPager->fd, zBuf, SQLITE_PAGE_SIZE);
TRACE2("REFETCH %d\n", pPg->pgno);
CODEC(pPager, zBuf, pPg->pgno, 2);
if( rc ) break;
}else{
memset(zBuf, 0, SQLITE_PAGE_SIZE);
@ -747,6 +841,7 @@ end_ckpt_playback:
void sqlitepager_set_cachesize(Pager *pPager, int mxPage){
if( mxPage>=0 ){
pPager->noSync = pPager->tempFile;
if( pPager->noSync==0 ) pPager->needSync = 0;
}else{
pPager->noSync = 1;
mxPage = -mxPage;
@ -772,8 +867,9 @@ void sqlitepager_set_cachesize(Pager *pPager, int mxPage){
** when it is rolled back.
**
** FULL The journal is synced twice before writes begin on the
** database (with some additional information being written
** in between the two syncs. If we assume that writing a
** database (with some additional information - the nRec field
** of the journal header - being written in between the two
** syncs). If we assume that writing a
** single disk sector is atomic, then this mode provides
** assurance that the journal will not be corrupted to the
** point of causing damage to the database during rollback.
@ -784,6 +880,7 @@ void sqlitepager_set_cachesize(Pager *pPager, int mxPage){
void sqlitepager_set_safety_level(Pager *pPager, int level){
pPager->noSync = level==1 || pPager->tempFile;
pPager->fullSync = level==3 && !pPager->tempFile;
if( pPager->noSync==0 ) pPager->needSync = 0;
}
/*
@ -933,7 +1030,7 @@ int sqlitepager_pagecount(Pager *pPager){
/*
** Forward declaration
*/
static int syncAllPages(Pager*);
static int syncJournal(Pager*);
/*
** Truncate the file to the number of pages specified.
@ -950,7 +1047,7 @@ int sqlitepager_truncate(Pager *pPager, Pgno nPage){
if( nPage>=(unsigned)pPager->dbSize ){
return SQLITE_OK;
}
syncAllPages(pPager);
syncJournal(pPager);
rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)nPage);
if( rc==SQLITE_OK ){
pPager->dbSize = nPage;
@ -1056,23 +1153,26 @@ int sqlitepager_ref(void *pData){
}
/*
** Sync the journal and then write all free dirty pages to the database
** file.
** Sync the journal. In other words, make sure all the pages that have
** been written to the journal have actually reached the surface of the
** disk. It is not safe to modify the original database file until after
** the journal has been synced. If the original database is modified before
** the journal is synced and a power failure occurs, the unsynced journal
** data would be lost and we would be unable to completely rollback the
** database changes. Database corruption would occur.
**
** This routine also updates the nRec field in the header of the journal.
** (See comments on the pager_playback() routine for additional information.)
** If the sync mode is FULL, two syncs will occur. First the whole journal
** is synced, then the nRec field is updated, then a second sync occurs.
**
** Writing all free dirty pages to the database after the sync is a
** non-obvious optimization. fsync() is an expensive operation so we
** want to minimize the number ot times it is called. After an fsync() call,
** we are free to write dirty pages back to the database. It is best
** to go ahead and write as many dirty pages as possible to minimize
** the risk of having to do another fsync() later on. Writing dirty
** free pages in this way was observed to make database operations go
** up to 10 times faster.
** For temporary databases, we do not care if we are able to rollback
** after a power failure, so sync occurs.
**
** If we are writing to temporary database, there is no need to preserve
** the integrity of the journal file, so we can save time and skip the
** fsync().
** This routine clears the needSync field of every page current held in
** memory.
*/
static int syncAllPages(Pager *pPager){
static int syncJournal(Pager *pPager){
PgHdr *pPg;
int rc = SQLITE_OK;
@ -1082,9 +1182,13 @@ static int syncAllPages(Pager *pPager){
if( pPager->needSync ){
if( !pPager->tempFile ){
assert( pPager->journalOpen );
assert( !pPager->noSync );
/* assert( !pPager->noSync ); // noSync might be set if synchronous
** was turned off after the transaction was started. Ticket #615 */
#ifndef NDEBUG
{
/* Make sure the pPager->nRec counter we are keeping agrees
** with the nRec computed from the size of the journal file.
*/
off_t hdrSz, pgSz, jSz;
hdrSz = JOURNAL_HDR_SZ(journal_format);
pgSz = JOURNAL_PG_SZ(journal_format);
@ -1094,6 +1198,7 @@ static int syncAllPages(Pager *pPager){
}
#endif
if( journal_format>=3 ){
/* Write the nRec value into the journal file header */
off_t szJ;
if( pPager->fullSync ){
TRACE1("SYNC\n");
@ -1152,7 +1257,10 @@ static int pager_write_pagelist(PgHdr *pList){
while( pList ){
assert( pList->dirty );
sqliteOsSeek(&pPager->fd, (pList->pgno-1)*(off_t)SQLITE_PAGE_SIZE);
CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 6);
TRACE2("STORE %d\n", pList->pgno);
rc = sqliteOsWrite(&pPager->fd, PGHDR_TO_DATA(pList), SQLITE_PAGE_SIZE);
CODEC(pPager, PGHDR_TO_DATA(pList), pList->pgno, 0);
if( rc ) return rc;
pList->dirty = 0;
pList = pList->pDirty;
@ -1304,7 +1412,7 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
** it can't be helped.
*/
if( pPg==0 ){
int rc = syncAllPages(pPager);
int rc = syncJournal(pPager);
if( rc!=0 ){
sqlitepager_rollback(pPager);
return SQLITE_IOERR;
@ -1413,6 +1521,8 @@ int sqlitepager_get(Pager *pPager, Pgno pgno, void **ppPage){
int rc;
sqliteOsSeek(&pPager->fd, (pgno-1)*(off_t)SQLITE_PAGE_SIZE);
rc = sqliteOsRead(&pPager->fd, PGHDR_TO_DATA(pPg), SQLITE_PAGE_SIZE);
TRACE2("FETCH %d\n", pPg->pgno);
CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
if( rc!=SQLITE_OK ){
off_t fileSize;
if( sqliteOsFileSize(&pPager->fd,&fileSize)!=SQLITE_OK
@ -1557,7 +1667,7 @@ static int pager_open_journal(Pager *pPager){
rc = write32bits(&pPager->jfd, pPager->noSync ? 0xffffffff : 0);
}
if( rc==SQLITE_OK ){
pPager->cksumInit = (u32)sqliteRandomInteger();
sqliteRandomness(sizeof(pPager->cksumInit), &pPager->cksumInit);
rc = write32bits(&pPager->jfd, pPager->cksumInit);
}
}else if( journal_format==JOURNAL_FORMAT_2 ){
@ -1700,7 +1810,10 @@ int sqlitepager_write(void *pData){
szPg = SQLITE_PAGE_SIZE+4;
}
store32bits(pPg->pgno, pPg, -4);
CODEC(pPager, pData, pPg->pgno, 7);
rc = sqliteOsWrite(&pPager->jfd, &((char*)pData)[-4], szPg);
TRACE3("JOURNAL %d %d\n", pPg->pgno, pPg->needSync);
CODEC(pPager, pData, pPg->pgno, 0);
if( journal_format>=JOURNAL_FORMAT_3 ){
*(u32*)PGHDR_TO_EXTRA(pPg) = saved;
}
@ -1718,7 +1831,6 @@ int sqlitepager_write(void *pData){
pPager->aInCkpt[pPg->pgno/8] |= 1<<(pPg->pgno&7);
page_add_to_ckpt_list(pPg);
}
TRACE3("JOURNAL %d %d\n", pPg->pgno, pPg->needSync);
}else{
pPg->needSync = !pPager->journalStarted && !pPager->noSync;
TRACE3("APPEND %d %d\n", pPg->pgno, pPg->needSync);
@ -1736,7 +1848,10 @@ int sqlitepager_write(void *pData){
if( pPager->ckptInUse && !pPg->inCkpt && (int)pPg->pgno<=pPager->ckptSize ){
assert( pPg->inJournal || (int)pPg->pgno>pPager->origDbSize );
store32bits(pPg->pgno, pPg, -4);
CODEC(pPager, pData, pPg->pgno, 7);
rc = sqliteOsWrite(&pPager->cpfd, &((char*)pData)[-4], SQLITE_PAGE_SIZE+4);
TRACE2("CKPT-JOURNAL %d\n", pPg->pgno);
CODEC(pPager, pData, pPg->pgno, 0);
if( rc!=SQLITE_OK ){
sqlitepager_rollback(pPager);
pPager->errMask |= PAGER_ERR_FULL;
@ -1896,7 +2011,8 @@ int sqlitepager_commit(Pager *pPager){
return rc;
}
assert( pPager->journalOpen );
if( pPager->needSync && sqliteOsSync(&pPager->jfd)!=SQLITE_OK ){
rc = syncJournal(pPager);
if( rc!=SQLITE_OK ){
goto commit_abort;
}
pPg = pager_get_all_dirty_pages(pPager);
@ -2077,6 +2193,18 @@ const char *sqlitepager_filename(Pager *pPager){
return pPager->zFilename;
}
/*
** Set the codec for this pager
*/
void sqlitepager_set_codec(
Pager *pPager,
void (*xCodec)(void*,void*,Pgno,int),
void *pCodecArg
){
pPager->xCodec = xCodec;
pPager->pCodecArg = pCodecArg;
}
#ifdef SQLITE_TEST
/*
** Print a listing of all referenced pages and their ref count.

View file

@ -19,12 +19,35 @@
/*
** The size of one page
**
** You can change this value to another (reasonable) power of two
** such as 512, 2048, 4096, or 8192 and things will still work. But
** experiments show that a page size of 1024 gives the best speed.
** (The speed differences are minimal.)
** You can change this value to another (reasonable) value you want.
** It need not be a power of two, though the interface to the disk
** will likely be faster if it is.
**
** Experiments show that a page size of 1024 gives the best speed
** for common usages. The speed differences for different sizes
** such as 512, 2048, 4096, an so forth, is minimal. Note, however,
** that changing the page size results in a completely imcompatible
** file format.
*/
#ifndef SQLITE_PAGE_SIZE
#define SQLITE_PAGE_SIZE 1024
#endif
/*
** Number of extra bytes of data allocated at the end of each page and
** stored on disk but not used by the higher level btree layer. Changing
** this value results in a completely incompatible file format.
*/
#ifndef SQLITE_PAGE_RESERVE
#define SQLITE_PAGE_RESERVE 0
#endif
/*
** The total number of usable bytes stored on disk for each page.
** The usable bytes come at the beginning of the page and the reserve
** bytes come at the end.
*/
#define SQLITE_USABLE_SIZE (SQLITE_PAGE_SIZE-SQLITE_PAGE_RESERVE)
/*
** Maximum number of pages in one database. (This is a limitation of
@ -75,6 +98,7 @@ int *sqlitepager_stats(Pager*);
void sqlitepager_set_safety_level(Pager*,int);
const char *sqlitepager_filename(Pager*);
int sqlitepager_rename(Pager*, const char *zNewName);
void sqlitepager_set_codec(Pager*,void(*)(void*,void*,Pgno,int),void*);
#ifdef SQLITE_TEST
void sqlitepager_refdump(Pager*);

File diff suppressed because it is too large Load diff

View file

@ -1,130 +1,130 @@
#define TK_ABORT 1
#define TK_AFTER 2
#define TK_AGG_FUNCTION 3
#define TK_ALL 4
#define TK_AND 5
#define TK_AS 6
#define TK_ASC 7
#define TK_ATTACH 8
#define TK_BEFORE 9
#define TK_BEGIN 10
#define TK_BETWEEN 11
#define TK_BITAND 12
#define TK_BITNOT 13
#define TK_BITOR 14
#define TK_BY 15
#define TK_CASCADE 16
#define TK_CASE 17
#define TK_CHECK 18
#define TK_CLUSTER 19
#define TK_COLLATE 20
#define TK_COLUMN 21
#define TK_END_OF_FILE 1
#define TK_ILLEGAL 2
#define TK_SPACE 3
#define TK_UNCLOSED_STRING 4
#define TK_COMMENT 5
#define TK_FUNCTION 6
#define TK_COLUMN 7
#define TK_AGG_FUNCTION 8
#define TK_SEMI 9
#define TK_EXPLAIN 10
#define TK_BEGIN 11
#define TK_TRANSACTION 12
#define TK_COMMIT 13
#define TK_END 14
#define TK_ROLLBACK 15
#define TK_CREATE 16
#define TK_TABLE 17
#define TK_TEMP 18
#define TK_LP 19
#define TK_RP 20
#define TK_AS 21
#define TK_COMMA 22
#define TK_COMMENT 23
#define TK_COMMIT 24
#define TK_CONCAT 25
#define TK_CONFLICT 26
#define TK_CONSTRAINT 27
#define TK_COPY 28
#define TK_CREATE 29
#define TK_DATABASE 30
#define TK_DEFAULT 31
#define TK_DEFERRABLE 32
#define TK_DEFERRED 33
#define TK_DELETE 34
#define TK_ID 23
#define TK_ABORT 24
#define TK_AFTER 25
#define TK_ASC 26
#define TK_ATTACH 27
#define TK_BEFORE 28
#define TK_CASCADE 29
#define TK_CLUSTER 30
#define TK_CONFLICT 31
#define TK_COPY 32
#define TK_DATABASE 33
#define TK_DEFERRED 34
#define TK_DELIMITERS 35
#define TK_DESC 36
#define TK_DETACH 37
#define TK_DISTINCT 38
#define TK_DOT 39
#define TK_DROP 40
#define TK_EACH 41
#define TK_ELSE 42
#define TK_END 43
#define TK_END_OF_FILE 44
#define TK_EQ 45
#define TK_EXCEPT 46
#define TK_EXPLAIN 47
#define TK_FAIL 48
#define TK_FLOAT 49
#define TK_FOR 50
#define TK_FOREIGN 51
#define TK_FROM 52
#define TK_FUNCTION 53
#define TK_GE 54
#define TK_GLOB 55
#define TK_GROUP 56
#define TK_GT 57
#define TK_HAVING 58
#define TK_ID 59
#define TK_IGNORE 60
#define TK_ILLEGAL 61
#define TK_IMMEDIATE 62
#define TK_IN 63
#define TK_INDEX 64
#define TK_INITIALLY 65
#define TK_INSERT 66
#define TK_INSTEAD 67
#define TK_INTEGER 68
#define TK_INTERSECT 69
#define TK_INTO 70
#define TK_IS 71
#define TK_ISNULL 72
#define TK_JOIN 73
#define TK_JOIN_KW 74
#define TK_KEY 75
#define TK_LE 76
#define TK_LIKE 77
#define TK_LIMIT 78
#define TK_LP 79
#define TK_LSHIFT 80
#define TK_LT 81
#define TK_MATCH 82
#define TK_MINUS 83
#define TK_NE 84
#define TK_NOT 85
#define TK_NOTNULL 86
#define TK_NULL 87
#define TK_OF 88
#define TK_OFFSET 89
#define TK_ON 90
#define TK_OR 91
#define TK_ORDER 92
#define TK_PLUS 93
#define TK_PRAGMA 94
#define TK_PRIMARY 95
#define TK_RAISE 96
#define TK_EACH 38
#define TK_FAIL 39
#define TK_FOR 40
#define TK_GLOB 41
#define TK_IGNORE 42
#define TK_IMMEDIATE 43
#define TK_INITIALLY 44
#define TK_INSTEAD 45
#define TK_LIKE 46
#define TK_MATCH 47
#define TK_KEY 48
#define TK_OF 49
#define TK_OFFSET 50
#define TK_PRAGMA 51
#define TK_RAISE 52
#define TK_REPLACE 53
#define TK_RESTRICT 54
#define TK_ROW 55
#define TK_STATEMENT 56
#define TK_TRIGGER 57
#define TK_VACUUM 58
#define TK_VIEW 59
#define TK_OR 60
#define TK_AND 61
#define TK_NOT 62
#define TK_EQ 63
#define TK_NE 64
#define TK_ISNULL 65
#define TK_NOTNULL 66
#define TK_IS 67
#define TK_BETWEEN 68
#define TK_IN 69
#define TK_GT 70
#define TK_GE 71
#define TK_LT 72
#define TK_LE 73
#define TK_BITAND 74
#define TK_BITOR 75
#define TK_LSHIFT 76
#define TK_RSHIFT 77
#define TK_PLUS 78
#define TK_MINUS 79
#define TK_STAR 80
#define TK_SLASH 81
#define TK_REM 82
#define TK_CONCAT 83
#define TK_UMINUS 84
#define TK_UPLUS 85
#define TK_BITNOT 86
#define TK_STRING 87
#define TK_JOIN_KW 88
#define TK_INTEGER 89
#define TK_CONSTRAINT 90
#define TK_DEFAULT 91
#define TK_FLOAT 92
#define TK_NULL 93
#define TK_PRIMARY 94
#define TK_UNIQUE 95
#define TK_CHECK 96
#define TK_REFERENCES 97
#define TK_REM 98
#define TK_REPLACE 99
#define TK_RESTRICT 100
#define TK_ROLLBACK 101
#define TK_ROW 102
#define TK_RP 103
#define TK_RSHIFT 104
#define TK_SELECT 105
#define TK_SEMI 106
#define TK_SET 107
#define TK_SLASH 108
#define TK_SPACE 109
#define TK_STAR 110
#define TK_STATEMENT 111
#define TK_STRING 112
#define TK_TABLE 113
#define TK_TEMP 114
#define TK_THEN 115
#define TK_TRANSACTION 116
#define TK_TRIGGER 117
#define TK_UMINUS 118
#define TK_UNCLOSED_STRING 119
#define TK_UNION 120
#define TK_UNIQUE 121
#define TK_UPDATE 122
#define TK_UPLUS 123
#define TK_USING 124
#define TK_VACUUM 125
#define TK_VALUES 126
#define TK_VARIABLE 127
#define TK_VIEW 128
#define TK_WHEN 129
#define TK_WHERE 130
#define TK_COLLATE 98
#define TK_ON 99
#define TK_DELETE 100
#define TK_UPDATE 101
#define TK_INSERT 102
#define TK_SET 103
#define TK_DEFERRABLE 104
#define TK_FOREIGN 105
#define TK_DROP 106
#define TK_UNION 107
#define TK_ALL 108
#define TK_INTERSECT 109
#define TK_EXCEPT 110
#define TK_SELECT 111
#define TK_DISTINCT 112
#define TK_DOT 113
#define TK_FROM 114
#define TK_JOIN 115
#define TK_USING 116
#define TK_ORDER 117
#define TK_BY 118
#define TK_GROUP 119
#define TK_HAVING 120
#define TK_LIMIT 121
#define TK_WHERE 122
#define TK_INTO 123
#define TK_VALUES 124
#define TK_VARIABLE 125
#define TK_CASE 126
#define TK_WHEN 127
#define TK_THEN 128
#define TK_ELSE 129
#define TK_INDEX 130

View file

@ -23,13 +23,11 @@
%syntax_error {
if( pParse->zErrMsg==0 ){
if( TOKEN.z[0] ){
sqliteSetNString(&pParse->zErrMsg,
"near \"", -1, TOKEN.z, TOKEN.n, "\": syntax error", -1, 0);
sqliteErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
}else{
sqliteSetString(&pParse->zErrMsg, "incomplete SQL statement", (char*)0);
sqliteErrorMsg(pParse, "incomplete SQL statement");
}
}
pParse->nErr++;
}
%name sqliteParser
%include {
@ -65,13 +63,10 @@ struct TrigEvent { int a; IdList * b; };
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
COLUMN AGG_FUNCTION.
// Input is zero or more commands.
// Input is a single SQL command
input ::= cmdlist.
// A list of commands is zero or more commands
//
cmdlist ::= ecmd.
cmdlist ::= cmdlist ecmd.
cmdlist ::= ecmd.
ecmd ::= explain cmdx SEMI.
ecmd ::= SEMI.
cmdx ::= cmd. { sqliteExec(pParse); }
@ -132,6 +127,22 @@ id(A) ::= ID(X). {A = X;}
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
TEMP TRIGGER VACUUM VIEW.
// Define operator precedence early so that this is the first occurance
// of the operator tokens in the grammer. Keeping the operators together
// causes them to be assigned integer values that are close together,
// which keeps parser tables smaller.
//
%left OR.
%left AND.
%right NOT.
%left EQ NE ISNULL NOTNULL IS LIKE GLOB BETWEEN IN.
%left GT GE LT LE.
%left BITAND BITOR LSHIFT RSHIFT.
%left PLUS MINUS.
%left STAR SLASH REM.
%left CONCAT.
%right UMINUS UPLUS BITNOT.
// And "ids" is an identifer-or-string.
//
%type ids {Token}
@ -366,7 +377,8 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) on_opt(N) using_opt(U). {
else { sqliteIdListDelete(U); }
}
}
seltablist(A) ::= stl_prefix(X) LP select(S) RP as(Z) on_opt(N) using_opt(U). {
seltablist(A) ::= stl_prefix(X) LP seltablist_paren(S) RP
as(Z) on_opt(N) using_opt(U). {
A = sqliteSrcListAppend(X,0,0);
A->a[A->nSrc-1].pSelect = S;
if( Z.n ) sqliteSrcListAddAlias(A,&Z);
@ -380,6 +392,17 @@ seltablist(A) ::= stl_prefix(X) LP select(S) RP as(Z) on_opt(N) using_opt(U). {
}
}
// A seltablist_paren nonterminal represents anything in a FROM that
// is contained inside parentheses. This can be either a subquery or
// a grouping of table and subqueries.
//
%type seltablist_paren {Select*}
%destructor seltablist_paren {sqliteSelectDelete($$);}
seltablist_paren(A) ::= select(S). {A = S;}
seltablist_paren(A) ::= seltablist(F). {
A = sqliteSelectNew(0,F,0,0,0,0,0,-1,0);
}
%type dbnm {Token}
dbnm(A) ::= . {A.z=0; A.n=0;}
dbnm(A) ::= DOT nm(X). {A = X;}
@ -505,16 +528,6 @@ inscollist(A) ::= nm(Y). {A = sqliteIdListAppend(0,&Y);}
/////////////////////////// Expression Processing /////////////////////////////
//
%left OR.
%left AND.
%right NOT.
%left EQ NE ISNULL NOTNULL IS LIKE GLOB BETWEEN IN.
%left GT GE LT LE.
%left BITAND BITOR LSHIFT RSHIFT.
%left PLUS MINUS.
%left STAR SLASH REM.
%left CONCAT.
%right UMINUS UPLUS BITNOT.
%type expr {Expr*}
%destructor expr {sqliteExprDelete($$);}
@ -664,6 +677,20 @@ expr(A) ::= expr(X) NOT IN LP select(Y) RP(E). {
A = sqliteExpr(TK_NOT, A, 0, 0);
sqliteExprSpan(A,&X->span,&E);
}
expr(A) ::= expr(X) IN nm(Y) dbnm(D). {
SrcList *pSrc = sqliteSrcListAppend(0, &Y, &D);
A = sqliteExpr(TK_IN, X, 0, 0);
if( A ) A->pSelect = sqliteSelectNew(0,pSrc,0,0,0,0,0,-1,0);
sqliteExprSpan(A,&X->span,D.z?&D:&Y);
}
expr(A) ::= expr(X) NOT IN nm(Y) dbnm(D). {
SrcList *pSrc = sqliteSrcListAppend(0, &Y, &D);
A = sqliteExpr(TK_IN, X, 0, 0);
if( A ) A->pSelect = sqliteSelectNew(0,pSrc,0,0,0,0,0,-1,0);
A = sqliteExpr(TK_NOT, A, 0, 0);
sqliteExprSpan(A,&X->span,D.z?&D:&Y);
}
/* CASE expressions */
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
@ -812,11 +839,11 @@ trigger_cmd(A) ::= UPDATE orconf(R) nm(X) SET setlist(Y) where_opt(Z).
{ A = sqliteTriggerUpdateStep(&X, Y, Z, R); }
// INSERT
trigger_cmd(A) ::= INSERT orconf(R) INTO nm(X) inscollist_opt(F)
trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F)
VALUES LP itemlist(Y) RP.
{A = sqliteTriggerInsertStep(&X, F, Y, 0, R);}
trigger_cmd(A) ::= INSERT orconf(R) INTO nm(X) inscollist_opt(F) select(S).
trigger_cmd(A) ::= insert_cmd(R) INTO nm(X) inscollist_opt(F) select(S).
{A = sqliteTriggerInsertStep(&X, F, 0, S, R);}
// DELETE
@ -854,9 +881,12 @@ cmd ::= DROP TRIGGER nm(X) dbnm(D). {
}
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
cmd ::= ATTACH database_kw_opt ids(F) AS nm(D). {
sqliteAttach(pParse, &F, &D);
cmd ::= ATTACH database_kw_opt ids(F) AS nm(D) key_opt(K). {
sqliteAttach(pParse, &F, &D, &K);
}
%type key_opt {Token}
key_opt(A) ::= USING ids(X). { A = X; }
key_opt(A) ::= . { A.z = 0; A.n = 0; }
database_kw_opt ::= DATABASE.
database_kw_opt ::= .

View file

@ -19,7 +19,7 @@
/*
** Interpret the given string as a boolean value.
*/
static int getBoolean(char *z){
static int getBoolean(const char *z){
static char *azTrue[] = { "yes", "on", "true" };
int i;
if( z[0]==0 ) return 0;
@ -34,7 +34,8 @@ static int getBoolean(char *z){
/*
** Interpret the given string as a safety level. Return 0 for OFF,
** 1 for ON or NORMAL and 2 for FULL.
** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
** unrecognized string argument.
**
** Note that the values returned are one less that the values that
** should be passed into sqliteBtreeSetSafetyLevel(). The is done
@ -70,8 +71,8 @@ static int getSafetyLevel(char *z){
** backed temporary databases, 2 for the Red-Black tree in memory database
** and 0 to use the compile-time default.
*/
static int getTempStore(char *z){
if( z[0]>='0' || z[0]<='2' ){
static int getTempStore(const char *z){
if( z[0]>='0' && z[0]<='2' ){
return z[0] - '0';
}else if( sqliteStrICmp(z, "file")==0 ){
return 1;
@ -82,6 +83,68 @@ static int getTempStore(char *z){
}
}
/*
** If the TEMP database is open, close it and mark the database schema
** as needing reloading. This must be done when using the TEMP_STORE
** or DEFAULT_TEMP_STORE pragmas.
*/
static int changeTempStorage(Parse *pParse, const char *zStorageType){
int ts = getTempStore(zStorageType);
sqlite *db = pParse->db;
if( db->temp_store==ts ) return SQLITE_OK;
if( db->aDb[1].pBt!=0 ){
if( db->flags & SQLITE_InTrans ){
sqliteErrorMsg(pParse, "temporary storage cannot be changed "
"from within a transaction");
return SQLITE_ERROR;
}
sqliteBtreeClose(db->aDb[1].pBt);
db->aDb[1].pBt = 0;
sqliteResetInternalSchema(db, 0);
}
db->temp_store = ts;
return SQLITE_OK;
}
/*
** Check to see if zRight and zLeft refer to a pragma that queries
** or changes one of the flags in db->flags. Return 1 if so and 0 if not.
** Also, implement the pragma.
*/
static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
static const struct {
const char *zName; /* Name of the pragma */
int mask; /* Mask for the db->flags value */
} aPragma[] = {
{ "vdbe_trace", SQLITE_VdbeTrace },
{ "full_column_names", SQLITE_FullColNames },
{ "short_column_names", SQLITE_ShortColNames },
{ "show_datatypes", SQLITE_ReportTypes },
{ "count_changes", SQLITE_CountRows },
{ "empty_result_callbacks", SQLITE_NullCallback },
};
int i;
for(i=0; i<sizeof(aPragma)/sizeof(aPragma[0]); i++){
if( sqliteStrICmp(zLeft, aPragma[i].zName)==0 ){
sqlite *db = pParse->db;
Vdbe *v;
if( strcmp(zLeft,zRight)==0 && (v = sqliteGetVdbe(pParse))!=0 ){
sqliteVdbeOp3(v, OP_ColumnName, 0, 1, aPragma[i].zName, P3_STATIC);
sqliteVdbeOp3(v, OP_ColumnName, 1, 0, "boolean", P3_STATIC);
sqliteVdbeCode(v, OP_Integer, (db->flags & aPragma[i].mask)!=0, 0,
OP_Callback, 1, 0,
0);
}else if( getBoolean(zRight) ){
db->flags |= aPragma[i].mask;
}else{
db->flags &= ~aPragma[i].mask;
}
return 1;
}
}
return 0;
}
/*
** Process a pragma statement.
**
@ -132,20 +195,21 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
** and a positive value means synchronous is on.
*/
if( sqliteStrICmp(zLeft,"default_cache_size")==0 ){
static VdbeOp getCacheSize[] = {
static VdbeOpList getCacheSize[] = {
{ OP_ReadCookie, 0, 2, 0},
{ OP_AbsValue, 0, 0, 0},
{ OP_Dup, 0, 0, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Ne, 0, 6, 0},
{ OP_Integer, MAX_PAGES,0, 0},
{ OP_ColumnName, 0, 0, "cache_size"},
{ OP_Integer, 0, 0, 0}, /* 5 */
{ OP_ColumnName, 0, 1, "cache_size"},
{ OP_Callback, 1, 0, 0},
};
int addr;
if( pRight->z==pLeft->z ){
sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
addr = sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
sqliteVdbeChangeP1(v, addr+5, MAX_PAGES);
}else{
int addr;
int size = atoi(zRight);
if( size<0 ) size = -size;
sqliteBeginWriteOperation(pParse, 0, 0);
@ -176,8 +240,8 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
** N should be a positive integer.
*/
if( sqliteStrICmp(zLeft,"cache_size")==0 ){
static VdbeOp getCacheSize[] = {
{ OP_ColumnName, 0, 0, "cache_size"},
static VdbeOpList getCacheSize[] = {
{ OP_ColumnName, 0, 1, "cache_size"},
{ OP_Callback, 1, 0, 0},
};
if( pRight->z==pLeft->z ){
@ -214,8 +278,8 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
** zero, but with a write performance penalty. The default mode is NORMAL.
*/
if( sqliteStrICmp(zLeft,"default_synchronous")==0 ){
static VdbeOp getSync[] = {
{ OP_ColumnName, 0, 0, "synchronous"},
static VdbeOpList getSync[] = {
{ OP_ColumnName, 0, 1, "synchronous"},
{ OP_ReadCookie, 0, 3, 0},
{ OP_Dup, 0, 0, 0},
{ OP_If, 0, 0, 0}, /* 3 */
@ -267,8 +331,8 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
** opened.
*/
if( sqliteStrICmp(zLeft,"synchronous")==0 ){
static VdbeOp getSync[] = {
{ OP_ColumnName, 0, 0, "synchronous"},
static VdbeOpList getSync[] = {
{ OP_ColumnName, 0, 1, "synchronous"},
{ OP_Callback, 1, 0, 0},
};
if( pRight->z==pLeft->z ){
@ -285,6 +349,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
}
}else
#ifndef NDEBUG
if( sqliteStrICmp(zLeft, "trigger_overhead_test")==0 ){
if( getBoolean(zRight) ){
always_code_trigger_setup = 1;
@ -292,72 +357,35 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
always_code_trigger_setup = 0;
}
}else
#endif
if( sqliteStrICmp(zLeft, "vdbe_trace")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_VdbeTrace;
}else{
db->flags &= ~SQLITE_VdbeTrace;
}
}else
if( sqliteStrICmp(zLeft, "full_column_names")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_FullColNames;
}else{
db->flags &= ~SQLITE_FullColNames;
}
}else
if( sqliteStrICmp(zLeft, "show_datatypes")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_ReportTypes;
}else{
db->flags &= ~SQLITE_ReportTypes;
}
}else
if( sqliteStrICmp(zLeft, "count_changes")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_CountRows;
}else{
db->flags &= ~SQLITE_CountRows;
}
}else
if( sqliteStrICmp(zLeft, "empty_result_callbacks")==0 ){
if( getBoolean(zRight) ){
db->flags |= SQLITE_NullCallback;
}else{
db->flags &= ~SQLITE_NullCallback;
}
if( flagPragma(pParse, zLeft, zRight) ){
/* The flagPragma() call also generates any necessary code */
}else
if( sqliteStrICmp(zLeft, "table_info")==0 ){
Table *pTab;
pTab = sqliteFindTable(db, zRight, 0);
if( pTab ){
static VdbeOp tableInfoPreface[] = {
static VdbeOpList tableInfoPreface[] = {
{ OP_ColumnName, 0, 0, "cid"},
{ OP_ColumnName, 1, 0, "name"},
{ OP_ColumnName, 2, 0, "type"},
{ OP_ColumnName, 3, 0, "notnull"},
{ OP_ColumnName, 4, 0, "dflt_value"},
{ OP_ColumnName, 5, 0, "pk"},
{ OP_ColumnName, 5, 1, "pk"},
};
int i;
sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
sqliteViewGetColumnNames(pParse, pTab);
for(i=0; i<pTab->nCol; i++){
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1,
pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zName, 0);
sqliteVdbeOp3(v, OP_String, 0, 0,
pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->aCol[i].zDflt, P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0,
pTab->aCol[i].zDflt, P3_STATIC);
sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
sqliteVdbeAddOp(v, OP_Callback, 6, 0);
}
@ -369,10 +397,10 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
Table *pTab;
pIdx = sqliteFindIndex(db, zRight, 0);
if( pIdx ){
static VdbeOp tableInfoPreface[] = {
static VdbeOpList tableInfoPreface[] = {
{ OP_ColumnName, 0, 0, "seqno"},
{ OP_ColumnName, 1, 0, "cid"},
{ OP_ColumnName, 2, 0, "name"},
{ OP_ColumnName, 2, 1, "name"},
};
int i;
pTab = pIdx->pTable;
@ -381,9 +409,8 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
int cnum = pIdx->aiColumn[i];
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_Integer, cnum, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
assert( pTab->nCol>cnum );
sqliteVdbeChangeP3(v, -1, pTab->aCol[cnum].zName, P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[cnum].zName, 0);
sqliteVdbeAddOp(v, OP_Callback, 3, 0);
}
}
@ -399,17 +426,16 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
}
if( pTab && pIdx ){
int i = 0;
static VdbeOp indexListPreface[] = {
static VdbeOpList indexListPreface[] = {
{ OP_ColumnName, 0, 0, "seq"},
{ OP_ColumnName, 1, 0, "name"},
{ OP_ColumnName, 2, 0, "unique"},
{ OP_ColumnName, 2, 1, "unique"},
};
sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
while(pIdx){
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0, pIdx->zName, 0);
sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
sqliteVdbeAddOp(v, OP_Callback, 3, 0);
++i;
@ -428,12 +454,12 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
}
if( pTab && pFK ){
int i = 0;
static VdbeOp indexListPreface[] = {
static VdbeOpList indexListPreface[] = {
{ OP_ColumnName, 0, 0, "id"},
{ OP_ColumnName, 1, 0, "seq"},
{ OP_ColumnName, 2, 0, "table"},
{ OP_ColumnName, 3, 0, "from"},
{ OP_ColumnName, 4, 0, "to"},
{ OP_ColumnName, 4, 1, "to"},
};
sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
@ -442,13 +468,10 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
for(j=0; j<pFK->nCol; j++){
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_Integer, j, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pFK->zTo, P3_STATIC);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->aCol[pFK->aCol[j].iFrom].zName,
P3_STATIC);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pFK->aCol[j].zCol, P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0, pFK->zTo, 0);
sqliteVdbeOp3(v, OP_String, 0, 0,
pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
sqliteVdbeOp3(v, OP_String, 0, 0, pFK->aCol[j].zCol, 0);
sqliteVdbeAddOp(v, OP_Callback, 5, 0);
}
++i;
@ -459,10 +482,10 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
if( sqliteStrICmp(zLeft, "database_list")==0 ){
int i;
static VdbeOp indexListPreface[] = {
static VdbeOpList indexListPreface[] = {
{ OP_ColumnName, 0, 0, "seq"},
{ OP_ColumnName, 1, 0, "name"},
{ OP_ColumnName, 2, 0, "file"},
{ OP_ColumnName, 2, 1, "file"},
};
sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
@ -470,11 +493,9 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
if( db->aDb[i].pBt==0 ) continue;
assert( db->aDb[i].zName!=0 );
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, db->aDb[i].zName, P3_STATIC);
sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, sqliteBtreeGetFilename(db->aDb[i].pBt),
P3_STATIC);
sqliteVdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, 0);
sqliteVdbeOp3(v, OP_String, 0, 0,
sqliteBtreeGetFilename(db->aDb[i].pBt), 0);
sqliteVdbeAddOp(v, OP_Callback, 3, 0);
}
}else
@ -492,20 +513,15 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
** override this setting
*/
if( sqliteStrICmp(zLeft, "temp_store")==0 ){
static VdbeOp getTmpDbLoc[] = {
{ OP_ColumnName, 0, 0, "temp_store"},
static VdbeOpList getTmpDbLoc[] = {
{ OP_ColumnName, 0, 1, "temp_store"},
{ OP_Callback, 1, 0, 0},
};
if( pRight->z==pLeft->z ){
sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0);
sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
}else{
if (&db->aDb[1].pBt != 0) {
sqliteErrorMsg(pParse, "The temporary database already exists - "
"its location cannot now be changed");
} else {
db->temp_store = getTempStore(zRight);
}
changeTempStorage(pParse, zRight);
}
}else
@ -513,30 +529,25 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
** PRAGMA default_temp_store
** PRAGMA default_temp_store = "default"|"memory"|"file"
**
** Return or set the value of the persistent temp_store flag (as
** well as the value currently in force).
** Return or set the value of the persistent temp_store flag. Any
** change does not take effect until the next time the database is
** opened.
**
** Note that it is possible for the library compile-time options to
** override this setting
*/
if( sqliteStrICmp(zLeft, "default_temp_store")==0 ){
static VdbeOp getTmpDbLoc[] = {
{ OP_ColumnName, 0, 0, "temp_store"},
static VdbeOpList getTmpDbLoc[] = {
{ OP_ColumnName, 0, 1, "temp_store"},
{ OP_ReadCookie, 0, 5, 0},
{ OP_Callback, 1, 0, 0}};
if( pRight->z==pLeft->z ){
sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
}else{
if (&db->aDb[1].pBt != 0) {
sqliteErrorMsg(pParse, "The temporary database already exists - "
"its location cannot now be changed");
} else {
sqliteBeginWriteOperation(pParse, 0, 0);
db->temp_store = getTempStore(zRight);
sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0);
sqliteVdbeAddOp(v, OP_SetCookie, 0, 5);
sqliteEndWriteOperation(pParse);
}
sqliteBeginWriteOperation(pParse, 0, 0);
sqliteVdbeAddOp(v, OP_Integer, getTempStore(zRight), 0);
sqliteVdbeAddOp(v, OP_SetCookie, 0, 5);
sqliteEndWriteOperation(pParse);
}
}else
@ -557,15 +568,15 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
/* Code that initializes the integrity check program. Set the
** error count 0
*/
static VdbeOp initCode[] = {
static VdbeOpList initCode[] = {
{ OP_Integer, 0, 0, 0},
{ OP_MemStore, 0, 1, 0},
{ OP_ColumnName, 0, 0, "integrity_check"},
{ OP_ColumnName, 0, 1, "integrity_check"},
};
/* Code to do an BTree integrity check on a single database file.
*/
static VdbeOp checkDb[] = {
static VdbeOpList checkDb[] = {
{ OP_SetInsert, 0, 0, "2"},
{ OP_Integer, 0, 0, 0}, /* 1 */
{ OP_OpenRead, 0, 2, 0},
@ -590,7 +601,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
** messages have been generated, output OK. Otherwise output the
** error message
*/
static VdbeOp endCode[] = {
static VdbeOpList endCode[] = {
{ OP_MemLoad, 0, 0, 0},
{ OP_Integer, 0, 0, 0},
{ OP_Ne, 0, 0, 0}, /* 2 */
@ -625,13 +636,11 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
if( pTab->pIndex==0 ) continue;
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_OpenRead, 1, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
sqliteVdbeOp3(v, OP_OpenRead, 1, pTab->tnum, pTab->zName, 0);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
if( pIdx->tnum==0 ) continue;
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, j+2, pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
sqliteVdbeOp3(v, OP_OpenRead, j+2, pIdx->tnum, pIdx->zName, 0);
}
sqliteVdbeAddOp(v, OP_Integer, 0, 0);
sqliteVdbeAddOp(v, OP_MemStore, 1, 1);
@ -639,7 +648,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
sqliteVdbeAddOp(v, OP_MemIncr, 1, 0);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int k, jmp2;
static VdbeOp idxErr[] = {
static VdbeOpList idxErr[] = {
{ OP_MemIncr, 0, 0, 0},
{ OP_String, 0, 0, "rowid "},
{ OP_Recno, 1, 0, 0},
@ -667,7 +676,7 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
sqliteVdbeAddOp(v, OP_Next, 1, loopTop+1);
sqliteVdbeChangeP2(v, loopTop, sqliteVdbeCurrentAddr(v));
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
static VdbeOp cntIdx[] = {
static VdbeOpList cntIdx[] = {
{ OP_Integer, 0, 0, 0},
{ OP_MemStore, 2, 1, 0},
{ OP_Rewind, 0, 0, 0}, /* 2 */

View file

@ -1,7 +1,11 @@
/*
** The "printf" code that follows dates from the 1980's. It is in
** the public domain. The original comments are included here for
** completeness. They are slightly out-of-date.
** completeness. They are very out-of-date but might be useful as
** an historical reference. Most of the "enhancements" have been backed
** out so that the functionality is now the same as standard printf().
**
**************************************************************************
**
** The following modules is an enhanced replacement for the "printf" subroutines
** found in the standard C library. The following enhancements are
@ -48,76 +52,80 @@
*/
#include "sqliteInt.h"
/*
** Undefine COMPATIBILITY to make some slight changes in the way things
** work. I think the changes are an improvement, but they are not
** backwards compatible.
*/
/* #define COMPATIBILITY / * Compatible with SUN OS 4.1 */
/*
** Conversion types fall into various categories as defined by the
** following enumeration.
*/
enum et_type { /* The type of the format field */
etRADIX, /* Integer types. %d, %x, %o, and so forth */
etFLOAT, /* Floating point. %f */
etEXP, /* Exponentional notation. %e and %E */
etGENERIC, /* Floating or exponential, depending on exponent. %g */
etSIZE, /* Return number of characters processed so far. %n */
etSTRING, /* Strings. %s */
etDYNSTRING, /* Dynamically allocated strings. %z */
etPERCENT, /* Percent symbol. %% */
etCHARX, /* Characters. %c */
etERROR, /* Used to indicate no such conversion type */
#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */
#define etFLOAT 2 /* Floating point. %f */
#define etEXP 3 /* Exponentional notation. %e and %E */
#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */
#define etSIZE 5 /* Return number of characters processed so far. %n */
#define etSTRING 6 /* Strings. %s */
#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() */
etCHARLIT, /* Literal characters. %' */
etSQLESCAPE, /* Strings with '\'' doubled. %q */
etSQLESCAPE2, /* Strings with '\'' doubled and enclosed in '',
#define etCHARLIT 11 /* Literal characters. %' */
#define etSQLESCAPE 12 /* Strings with '\'' doubled. %q */
#define etSQLESCAPE2 13 /* Strings with '\'' doubled and enclosed in '',
NULL pointers replaced by SQL NULL. %Q */
etORDINAL /* 1st, 2nd, 3rd and so forth */
};
#define etTOKEN 14 /* a pointer to a Token structure */
#define etSRCLIST 15 /* a pointer to a SrcList */
/*
** An "etByte" is an 8-bit unsigned value.
*/
typedef unsigned char etByte;
/*
** Each builtin conversion character (ex: the 'd' in "%d") is described
** by an instance of the following structure
*/
typedef struct et_info { /* Information about each format field */
int fmttype; /* The format field code letter */
int base; /* The base for radix conversion */
char *charset; /* The character set for conversion */
int flag_signed; /* Is the quantity signed? */
char *prefix; /* Prefix on non-zero values in alt format */
enum et_type type; /* Conversion paradigm */
char fmttype; /* The format field code letter */
etByte base; /* The base for radix conversion */
etByte flags; /* One or more of FLAG_ constants below */
etByte type; /* Conversion paradigm */
char *charset; /* The character set for conversion */
char *prefix; /* Prefix on non-zero values in alt format */
} et_info;
/*
** Allowed values for et_info.flags
*/
#define FLAG_SIGNED 1 /* True if the value to convert is signed */
#define FLAG_INTERN 2 /* True if for internal use only */
/*
** The following table is searched linearly, so it is good to put the
** most frequently used conversion types first.
*/
static et_info fmtinfo[] = {
{ 'd', 10, "0123456789", 1, 0, etRADIX, },
{ 's', 0, 0, 0, 0, etSTRING, },
{ 'z', 0, 0, 0, 0, etDYNSTRING, },
{ 'q', 0, 0, 0, 0, etSQLESCAPE, },
{ 'Q', 0, 0, 0, 0, etSQLESCAPE2, },
{ 'c', 0, 0, 0, 0, etCHARX, },
{ 'o', 8, "01234567", 0, "0", etRADIX, },
{ 'u', 10, "0123456789", 0, 0, etRADIX, },
{ 'x', 16, "0123456789abcdef", 0, "x0", etRADIX, },
{ 'X', 16, "0123456789ABCDEF", 0, "X0", etRADIX, },
{ 'r', 10, "0123456789", 0, 0, etORDINAL, },
{ 'f', 0, 0, 1, 0, etFLOAT, },
{ 'e', 0, "e", 1, 0, etEXP, },
{ 'E', 0, "E", 1, 0, etEXP, },
{ 'g', 0, "e", 1, 0, etGENERIC, },
{ 'G', 0, "E", 1, 0, etGENERIC, },
{ 'i', 10, "0123456789", 1, 0, etRADIX, },
{ 'n', 0, 0, 0, 0, etSIZE, },
{ '%', 0, 0, 0, 0, etPERCENT, },
{ 'b', 2, "01", 0, "b0", etRADIX, }, /* Binary */
{ 'p', 10, "0123456789", 0, 0, etRADIX, }, /* Pointers */
{ '\'', 0, 0, 0, 0, etCHARLIT, }, /* Literal char */
{ 'd', 10, 1, etRADIX, "0123456789", 0 },
{ 's', 0, 0, etSTRING, 0, 0 },
{ 'z', 0, 2, etDYNSTRING, 0, 0 },
{ 'q', 0, 0, etSQLESCAPE, 0, 0 },
{ 'Q', 0, 0, etSQLESCAPE2, 0, 0 },
{ 'c', 0, 0, etCHARX, 0, 0 },
{ 'o', 8, 0, etRADIX, "01234567", "0" },
{ 'u', 10, 0, etRADIX, "0123456789", 0 },
{ 'x', 16, 0, etRADIX, "0123456789abcdef", "x0" },
{ 'X', 16, 0, etRADIX, "0123456789ABCDEF", "X0" },
{ 'f', 0, 1, etFLOAT, 0, 0 },
{ 'e', 0, 1, etEXP, "e", 0 },
{ 'E', 0, 1, etEXP, "E", 0 },
{ 'g', 0, 1, etGENERIC, "e", 0 },
{ 'G', 0, 1, etGENERIC, "E", 0 },
{ 'i', 10, 1, etRADIX, "0123456789", 0 },
{ 'n', 0, 0, etSIZE, 0, 0 },
{ '%', 0, 0, etPERCENT, 0, 0 },
{ 'p', 10, 0, etRADIX, "0123456789", 0 },
{ 'T', 0, 2, etTOKEN, 0, 0 },
{ 'S', 0, 2, etSRCLIST, 0, 0 },
};
#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))
@ -181,52 +189,49 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
** will run.
*/
static int vxprintf(
void (*func)(void*,char*,int),
void *arg,
const char *format,
va_list ap
void (*func)(void*,const char*,int), /* Consumer of text */
void *arg, /* First argument to the consumer */
int useExtended, /* Allow extended %-conversions */
const char *fmt, /* Format string */
va_list ap /* arguments */
){
register const char *fmt; /* The format string. */
register int c; /* Next character in the format string */
register char *bufpt; /* Pointer to the conversion buffer */
register int precision; /* Precision of the current field */
register int length; /* Length of the field */
register int idx; /* A general purpose loop counter */
int count; /* Total number of characters output */
int width; /* Width of the current field */
int flag_leftjustify; /* True if "-" flag is present */
int flag_plussign; /* True if "+" flag is present */
int flag_blanksign; /* True if " " flag is present */
int flag_alternateform; /* True if "#" flag is present */
int flag_zeropad; /* True if field width constant starts with zero */
int flag_long; /* True if "l" flag is present */
int flag_center; /* True if "=" flag is present */
unsigned long longvalue; /* Value for integer types */
int c; /* Next character in the format string */
char *bufpt; /* Pointer to the conversion buffer */
int precision; /* Precision of the current field */
int length; /* Length of the field */
int idx; /* A general purpose loop counter */
int count; /* Total number of characters output */
int width; /* Width of the current field */
etByte flag_leftjustify; /* True if "-" flag is present */
etByte flag_plussign; /* True if "+" flag is present */
etByte flag_blanksign; /* True if " " flag is present */
etByte flag_alternateform; /* True if "#" flag is present */
etByte flag_zeropad; /* True if field width constant starts with zero */
etByte flag_long; /* True if "l" flag is present */
unsigned long longvalue; /* Value for integer types */
LONGDOUBLE_TYPE realvalue; /* Value for real types */
et_info *infop; /* Pointer to the appropriate info structure */
char buf[etBUFSIZE]; /* Conversion buffer */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
int errorflag = 0; /* True if an error is encountered */
enum et_type xtype; /* Conversion paradigm */
char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
static char spaces[] = " "
" ";
et_info *infop; /* Pointer to the appropriate info structure */
char buf[etBUFSIZE]; /* Conversion buffer */
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
etByte errorflag = 0; /* True if an error is encountered */
etByte xtype; /* Conversion paradigm */
char *zExtra; /* Extra memory used for etTCLESCAPE conversions */
static char spaces[] = " ";
#define etSPACESIZE (sizeof(spaces)-1)
#ifndef etNOFLOATINGPOINT
int exp; /* exponent of real numbers */
double rounder; /* Used for rounding floating point values */
int flag_dp; /* True if decimal point should be shown */
int flag_rtz; /* True if trailing zeros should be removed */
int flag_exp; /* True to force display of the exponent */
int nsd; /* Number of significant digits returned */
int exp; /* exponent of real numbers */
double rounder; /* Used for rounding floating point values */
etByte flag_dp; /* True if decimal point should be shown */
etByte flag_rtz; /* True if trailing zeros should be removed */
etByte flag_exp; /* True to force display of the exponent */
int nsd; /* Number of significant digits returned */
#endif
fmt = format; /* Put in a register for speed */
count = length = 0;
bufpt = 0;
for(; (c=(*fmt))!=0; ++fmt){
if( c!='%' ){
register int amt;
int amt;
bufpt = (char *)fmt;
amt = 1;
while( (c=(*++fmt))!='%' && c!=0 ) amt++;
@ -242,7 +247,7 @@ static int vxprintf(
}
/* Find out what flags are present */
flag_leftjustify = flag_plussign = flag_blanksign =
flag_alternateform = flag_zeropad = flag_center = 0;
flag_alternateform = flag_zeropad = 0;
do{
switch( c ){
case '-': flag_leftjustify = 1; c = 0; break;
@ -250,11 +255,9 @@ static int vxprintf(
case ' ': flag_blanksign = 1; c = 0; break;
case '#': flag_alternateform = 1; c = 0; break;
case '0': flag_zeropad = 1; c = 0; break;
case '=': flag_center = 1; c = 0; break;
default: break;
}
}while( c==0 && (c=(*++fmt))!=0 );
if( flag_center ) flag_leftjustify = 0;
/* Get the field width */
width = 0;
if( c=='*' ){
@ -279,10 +282,7 @@ static int vxprintf(
c = *++fmt;
if( c=='*' ){
precision = va_arg(ap,int);
#ifndef etCOMPATIBILITY
/* This is sensible, but SUN OS 4.1 doesn't do it. */
if( precision<0 ) precision = -precision;
#endif
c = *++fmt;
}else{
while( c>='0' && c<='9' ){
@ -304,18 +304,16 @@ 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];
if( useExtended || (infop->flags & FLAG_INTERN)==0 ){
xtype = infop->type;
}
break;
}
}
/* No info entry found. It must be an error. */
if( infop==0 ){
xtype = etERROR;
}else{
xtype = infop->type;
}
zExtra = 0;
/*
@ -337,11 +335,10 @@ static int vxprintf(
** infop Pointer to the appropriate info struct.
*/
switch( xtype ){
case etORDINAL:
case etRADIX:
if( flag_long ) longvalue = va_arg(ap,long);
else longvalue = va_arg(ap,int);
#ifdef etCOMPATIBILITY
#if 1
/* For the format %#x, the value zero is printed "0" not "0x0".
** I think this is stupid. */
if( longvalue==0 ) flag_alternateform = 0;
@ -350,7 +347,7 @@ static int vxprintf(
** but leave the prefix for hex. */
if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;
#endif
if( infop->flag_signed ){
if( infop->flags & FLAG_SIGNED ){
if( *(long*)&longvalue<0 ){
longvalue = -*(long*)&longvalue;
prefix = '-';
@ -361,26 +358,7 @@ static int vxprintf(
if( flag_zeropad && precision<width-(prefix!=0) ){
precision = width-(prefix!=0);
}
bufpt = &buf[etBUFSIZE];
if( xtype==etORDINAL ){
long a,b;
a = longvalue%10;
b = longvalue%100;
bufpt -= 2;
if( a==0 || a>3 || (b>10 && b<14) ){
bufpt[0] = 't';
bufpt[1] = 'h';
}else if( a==1 ){
bufpt[0] = 's';
bufpt[1] = 't';
}else if( a==2 ){
bufpt[0] = 'n';
bufpt[1] = 'd';
}else if( a==3 ){
bufpt[0] = 'r';
bufpt[1] = 'd';
}
}
bufpt = &buf[etBUFSIZE-1];
{
register char *cset; /* Use registers for speed */
register int base;
@ -391,7 +369,7 @@ static int vxprintf(
longvalue = longvalue/base;
}while( longvalue>0 );
}
length = &buf[etBUFSIZE]-bufpt;
length = &buf[etBUFSIZE-1]-bufpt;
for(idx=precision-length; idx>0; idx--){
*(--bufpt) = '0'; /* Zero pad */
}
@ -403,7 +381,7 @@ static int vxprintf(
for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;
}
}
length = &buf[etBUFSIZE]-bufpt;
length = &buf[etBUFSIZE-1]-bufpt;
break;
case etFLOAT:
case etEXP:
@ -422,7 +400,7 @@ static int vxprintf(
}
if( infop->type==etGENERIC && precision>0 ) precision--;
rounder = 0.0;
#ifdef COMPATIBILITY
#if 0
/* Rounding works like BSD when the constant 0.4999 is used. Wierd! */
for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);
#else
@ -433,12 +411,11 @@ static int vxprintf(
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
exp = 0;
if( realvalue>0.0 ){
int k = 0;
while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; }
while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; }
while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; }
while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; }
if( k>=100 ){
while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
if( exp>350 || exp<-350 ){
bufpt = "NaN";
length = 3;
break;
@ -590,6 +567,25 @@ static int vxprintf(
if( precision>=0 && precision<length ) length = precision;
}
break;
case etTOKEN: {
Token *pToken = va_arg(ap, Token*);
(*func)(arg, pToken->z, pToken->n);
length = width = 0;
break;
}
case etSRCLIST: {
SrcList *pSrc = va_arg(ap, SrcList*);
int k = va_arg(ap, int);
struct SrcList_item *pItem = &pSrc->a[k];
assert( k>=0 && k<pSrc->nSrc );
if( pItem->zDatabase && pItem->zDatabase[0] ){
(*func)(arg, pItem->zDatabase, strlen(pItem->zDatabase));
(*func)(arg, ".", 1);
}
(*func)(arg, pItem->zName, strlen(pItem->zName));
length = width = 0;
break;
}
case etERROR:
buf[0] = '%';
buf[1] = c;
@ -609,11 +605,6 @@ static int vxprintf(
register int nspace;
nspace = width-length;
if( nspace>0 ){
if( flag_center ){
nspace = nspace/2;
width -= nspace;
flag_leftjustify = 1;
}
count += nspace;
while( nspace>=etSPACESIZE ){
(*func)(arg,spaces,etSPACESIZE);
@ -639,11 +630,7 @@ static int vxprintf(
}
}
if( zExtra ){
if( xtype==etDYNSTRING ){
free(zExtra);
}else{
sqliteFree(zExtra);
}
sqliteFree(zExtra);
}
}/* End for loop over the format string */
return errorflag ? -1 : count;
@ -657,7 +644,9 @@ struct sgMprintf {
char *zBase; /* A base allocation */
char *zText; /* The string collected so far */
int nChar; /* Length of the string so far */
int nTotal; /* Output size if unconstrained */
int nAlloc; /* Amount of space allocated in zText */
void *(*xRealloc)(void*,int); /* Function used to realloc memory */
};
/*
@ -666,24 +655,25 @@ struct sgMprintf {
** This routine add nNewChar characters of text in zNewText to
** the sgMprintf structure pointed to by "arg".
*/
static void mout(void *arg, char *zNewText, int nNewChar){
static void mout(void *arg, const char *zNewText, int nNewChar){
struct sgMprintf *pM = (struct sgMprintf*)arg;
pM->nTotal += nNewChar;
if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
pM->nAlloc = pM->nChar + nNewChar*2 + 1;
if( pM->zText==pM->zBase ){
pM->zText = sqliteMalloc(pM->nAlloc);
if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar);
if( pM->xRealloc==0 ){
nNewChar = pM->nAlloc - pM->nChar - 1;
}else{
char *z = sqliteRealloc(pM->zText, pM->nAlloc);
if( z==0 ){
sqliteFree(pM->zText);
pM->nChar = 0;
pM->nAlloc = 0;
pM->nAlloc = pM->nChar + nNewChar*2 + 1;
if( pM->zText==pM->zBase ){
pM->zText = pM->xRealloc(0, pM->nAlloc);
if( pM->zText && pM->nChar ){
memcpy(pM->zText, pM->zBase, pM->nChar);
}
}else{
pM->zText = pM->xRealloc(pM->zText, pM->nAlloc);
}
pM->zText = z;
}
}
if( pM->zText ){
if( pM->zText && nNewChar>0 ){
memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
pM->nChar += nNewChar;
pM->zText[pM->nChar] = 0;
@ -691,114 +681,104 @@ static void mout(void *arg, char *zNewText, int nNewChar){
}
/*
** sqlite_mprintf() works like printf(), but allocations memory to hold the
** resulting string and returns a pointer to the allocated memory. Use
** sqliteFree() to release the memory allocated.
** This routine is a wrapper around xprintf() that invokes mout() as
** the consumer.
*/
char *sqliteMPrintf(const char *zFormat, ...){
va_list ap;
struct sgMprintf sMprintf;
char zBuf[200];
sMprintf.nChar = 0;
sMprintf.nAlloc = sizeof(zBuf);
sMprintf.zText = zBuf;
sMprintf.zBase = zBuf;
va_start(ap,zFormat);
vxprintf(mout,&sMprintf,zFormat,ap);
va_end(ap);
sMprintf.zText[sMprintf.nChar] = 0;
return sqliteRealloc(sMprintf.zText, sMprintf.nChar+1);
static char *base_vprintf(
void *(*xRealloc)(void*,int), /* Routine to realloc memory. May be NULL */
int useInternal, /* Use internal %-conversions if true */
char *zInitBuf, /* Initially write here, before mallocing */
int nInitBuf, /* Size of zInitBuf[] */
const char *zFormat, /* format string */
va_list ap /* arguments */
){
struct sgMprintf sM;
sM.zBase = sM.zText = zInitBuf;
sM.nChar = sM.nTotal = 0;
sM.nAlloc = nInitBuf;
sM.xRealloc = xRealloc;
vxprintf(mout, &sM, useInternal, zFormat, ap);
if( xRealloc ){
if( sM.zText==sM.zBase ){
sM.zText = xRealloc(0, sM.nChar+1);
memcpy(sM.zText, sM.zBase, sM.nChar+1);
}else if( sM.nAlloc>sM.nChar+10 ){
sM.zText = xRealloc(sM.zText, sM.nChar+1);
}
}
return sM.zText;
}
/*
** sqlite_mprintf() works like printf(), but allocations memory to hold the
** resulting string and returns a pointer to the allocated memory. Use
** sqliteFree() to release the memory allocated.
** Realloc that is a real function, not a macro.
*/
static void *printf_realloc(void *old, int size){
return sqliteRealloc(old,size);
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
char *sqliteVMPrintf(const char *zFormat, va_list ap){
char zBase[1000];
return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
}
/*
** Print into memory obtained from sqliteMalloc(). Use the internal
** %-conversion extensions.
*/
char *sqliteMPrintf(const char *zFormat, ...){
va_list ap;
char *z;
char zBase[1000];
va_start(ap, zFormat);
z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
va_end(ap);
return z;
}
/*
** Print into memory obtained from malloc(). Do not use the internal
** %-conversion extensions. This routine is for use by external users.
*/
char *sqlite_mprintf(const char *zFormat, ...){
va_list ap;
struct sgMprintf sMprintf;
char *zNew;
char *z;
char zBuf[200];
sMprintf.nChar = 0;
sMprintf.nAlloc = sizeof(zBuf);
sMprintf.zText = zBuf;
sMprintf.zBase = zBuf;
va_start(ap,zFormat);
vxprintf(mout,&sMprintf,zFormat,ap);
z = base_vprintf((void*(*)(void*,int))realloc, 0,
zBuf, sizeof(zBuf), zFormat, ap);
va_end(ap);
sMprintf.zText[sMprintf.nChar] = 0;
zNew = malloc( sMprintf.nChar+1 );
if( zNew ) strcpy(zNew,sMprintf.zText);
if( sMprintf.zText!=sMprintf.zBase ){
sqliteFree(sMprintf.zText);
}
return zNew;
return z;
}
/* This is the varargs version of sqlite_mprintf.
*/
char *sqlite_vmprintf(const char *zFormat, va_list ap){
struct sgMprintf sMprintf;
char *zNew;
char zBuf[200];
sMprintf.nChar = 0;
sMprintf.zText = zBuf;
sMprintf.nAlloc = sizeof(zBuf);
sMprintf.zBase = zBuf;
vxprintf(mout,&sMprintf,zFormat,ap);
sMprintf.zText[sMprintf.nChar] = 0;
zNew = malloc( sMprintf.nChar+1 );
if( zNew ) strcpy(zNew,sMprintf.zText);
if( sMprintf.zText!=sMprintf.zBase ){
sqliteFree(sMprintf.zText);
}
return zNew;
}
/*
** This function implements the callback from vxprintf.
**
** This routine add nNewChar characters of text in zNewText to
** the sgMprintf structure pointed to by "arg". Unlike mout() above,
** this routine does not allocate new space when the buffer fills.
** It just truncates.
*/
static void sout(void *arg, char *zNewText, int nNewChar){
struct sgMprintf *pM = (struct sgMprintf*)arg;
if( pM->nChar + nNewChar + 1 > pM->nAlloc ){
nNewChar = pM->nAlloc - pM->nChar - 1;
if( nNewChar<=0 ) return;
}
memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);
pM->nChar += nNewChar;
pM->zText[pM->nChar] = 0;
return base_vprintf((void*(*)(void*,int))realloc, 0,
zBuf, sizeof(zBuf), zFormat, ap);
}
/*
** sqlite_sprintf() works like sprintf() except that it ignores the
** sqlite_snprintf() works like snprintf() except that it ignores the
** current locale settings. This is important for SQLite because we
** are not able to use a "," as the decimal point in place of "." as
** specified by some locales.
*/
int sqlite_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *sqlite_snprintf(int n, char *zBuf, const char *zFormat, ...){
char *z;
va_list ap;
struct sgMprintf sMprintf;
sMprintf.nChar = 0;
sMprintf.nAlloc = n;
sMprintf.zText = zBuf;
sMprintf.zBase = zBuf;
va_start(ap,zFormat);
vxprintf(sout,&sMprintf,zFormat,ap);
z = base_vprintf(0, 0, zBuf, n, zFormat, ap);
va_end(ap);
return sMprintf.nChar;
return z;
}
/*
** The following four routines implement the varargs versions of the
** sqlite_exec() and sqlite_get_table() interfaces. See the sqlite.h

View file

@ -35,15 +35,15 @@
** on RC4, which we know works very well.
*/
static int randomByte(){
int t;
unsigned char t;
/* All threads share a single random number generator.
** This structure is the current state of the generator.
*/
static struct {
int isInit; /* True if initialized */
int i, j; /* State variables */
int s[256]; /* State variables */
unsigned char isInit; /* True if initialized */
unsigned char i, j; /* State variables */
unsigned char s[256]; /* State variables */
} prng;
/* Initialize the state of the random number generator once,
@ -65,8 +65,7 @@ static int randomByte(){
prng.s[i] = i;
}
for(i=0; i<256; i++){
int t;
prng.j = (prng.j + prng.s[i] + k[i]) & 0xff;
prng.j += prng.s[i] + k[i];
t = prng.s[prng.j];
prng.s[prng.j] = prng.s[i];
prng.s[i] = t;
@ -76,38 +75,23 @@ static int randomByte(){
/* Generate and return single random byte
*/
prng.i = (prng.i + 1) & 0xff;
prng.j = (prng.j + prng.s[prng.i]) & 0xff;
prng.i++;
t = prng.s[prng.i];
prng.j += t;
prng.s[prng.i] = prng.s[prng.j];
prng.s[prng.j] = t;
t = prng.s[prng.i] + prng.s[prng.j];
return prng.s[t & 0xff];
t += prng.s[prng.i];
return prng.s[t];
}
/*
** Return an random 8-bit integer.
** Return N random bytes.
*/
int sqliteRandomByte(){
int r;
void sqliteRandomness(int N, void *pBuf){
unsigned char *zBuf = pBuf;
sqliteOsEnterMutex();
r = randomByte();
sqliteOsLeaveMutex();
return r;
}
/*
** Return a random 32-bit integer. The integer is generated by making
** 4 calls to sqliteRandomByte().
*/
int sqliteRandomInteger(){
int r;
int i;
sqliteOsEnterMutex();
r = randomByte();
for(i=1; i<4; i++){
r = (r<<8) + randomByte();
while( N-- ){
*(zBuf++) = randomByte();
}
sqliteOsLeaveMutex();
return r;
}

View file

@ -42,6 +42,9 @@ Select *sqliteSelectNew(
sqliteExprDelete(pHaving);
sqliteExprListDelete(pOrderBy);
}else{
if( pEList==0 ){
pEList = sqliteExprListAppend(0, sqliteExpr(TK_ALL,0,0,0), 0);
}
pNew->pEList = pEList;
pNew->pSrc = pSrc;
pNew->pWhere = pWhere;
@ -335,9 +338,7 @@ static void pushOntoSorter(Parse *pParse, Vdbe *v, ExprList *pOrderBy){
sqliteExprCode(pParse, pOrderBy->a[i].pExpr);
}
zSortOrder[pOrderBy->nExpr] = 0;
sqliteVdbeAddOp(v, OP_SortMakeKey, pOrderBy->nExpr, 0);
sqliteVdbeChangeP3(v, -1, zSortOrder, strlen(zSortOrder));
sqliteFree(zSortOrder);
sqliteVdbeOp3(v, OP_SortMakeKey, pOrderBy->nExpr, 0, zSortOrder, P3_DYNAMIC);
sqliteVdbeAddOp(v, OP_SortPut, 0, 0);
}
@ -360,8 +361,7 @@ void sqliteAddKeyType(Vdbe *v, ExprList *pEList){
zType[i] = sqliteExprType(pEList->a[i].pExpr)==SQLITE_SO_NUM ? 'n' : 't';
}
zType[i] = 0;
sqliteVdbeChangeP3(v, -1, zType, nColumn);
sqliteFree(zType);
sqliteVdbeChangeP3(v, -1, zType, P3_DYNAMIC);
}
/*
@ -564,18 +564,19 @@ static void generateSortTail(
int eDest, /* Write the sorted results here */
int iParm /* Optional parameter associated with eDest */
){
int end = sqliteVdbeMakeLabel(v);
int end1 = sqliteVdbeMakeLabel(v);
int end2 = sqliteVdbeMakeLabel(v);
int addr;
if( eDest==SRT_Sorter ) return;
sqliteVdbeAddOp(v, OP_Sort, 0, 0);
addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end);
addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end1);
if( p->iOffset>=0 ){
sqliteVdbeAddOp(v, OP_MemIncr, p->iOffset, addr+4);
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
}
if( p->iLimit>=0 ){
sqliteVdbeAddOp(v, OP_MemIncr, p->iLimit, end);
sqliteVdbeAddOp(v, OP_MemIncr, p->iLimit, end2);
}
switch( eDest ){
case SRT_Callback: {
@ -601,7 +602,7 @@ static void generateSortTail(
case SRT_Mem: {
assert( nColumn==1 );
sqliteVdbeAddOp(v, OP_MemStore, iParm, 1);
sqliteVdbeAddOp(v, OP_Goto, 0, end);
sqliteVdbeAddOp(v, OP_Goto, 0, end1);
break;
}
case SRT_Subroutine: {
@ -619,7 +620,9 @@ static void generateSortTail(
}
}
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
sqliteVdbeResolveLabel(v, end);
sqliteVdbeResolveLabel(v, end2);
sqliteVdbeAddOp(v, OP_Pop, 1, 0);
sqliteVdbeResolveLabel(v, end1);
sqliteVdbeAddOp(v, OP_SortReset, 0, 0);
}
@ -645,9 +648,6 @@ static void generateColumnTypes(
){
Vdbe *v = pParse->pVdbe;
int i, j;
if( pParse->useCallback && (pParse->db->flags & SQLITE_ReportTypes)==0 ){
return;
}
for(i=0; i<pEList->nExpr; i++){
Expr *p = pEList->a[i].pExpr;
char *zType = 0;
@ -672,15 +672,14 @@ static void generateColumnTypes(
zType = "NUMERIC";
}
}
sqliteVdbeAddOp(v, OP_ColumnName, i + pEList->nExpr, 0);
sqliteVdbeChangeP3(v, -1, zType, P3_STATIC);
sqliteVdbeOp3(v, OP_ColumnName, i + pEList->nExpr, 0, zType, 0);
}
}
/*
** Generate code that will tell the VDBE the names of columns
** in the result set. This information is used to provide the
** azCol[] vaolues in the callback.
** azCol[] values in the callback.
*/
static void generateColumnNames(
Parse *pParse, /* Parser context */
@ -689,21 +688,24 @@ static void generateColumnNames(
){
Vdbe *v = pParse->pVdbe;
int i, j;
sqlite *db = pParse->db;
int fullNames, shortNames;
assert( v!=0 );
if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return;
pParse->colNamesSet = 1;
fullNames = (db->flags & SQLITE_FullColNames)!=0;
shortNames = (db->flags & SQLITE_ShortColNames)!=0;
for(i=0; i<pEList->nExpr; i++){
Expr *p;
char *zType = 0;
int showFullNames;
int p2 = i==pEList->nExpr-1;
p = pEList->a[i].pExpr;
if( p==0 ) continue;
if( pEList->a[i].zName ){
char *zName = pEList->a[i].zName;
sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
sqliteVdbeChangeP3(v, -1, zName, strlen(zName));
sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, 0);
continue;
}
showFullNames = (pParse->db->flags & SQLITE_FullColNames)!=0;
if( p->op==TK_COLUMN && pTabList ){
Table *pTab;
char *zCol;
@ -715,39 +717,31 @@ static void generateColumnNames(
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
zCol = "_ROWID_";
zType = "INTEGER";
}else{
zCol = pTab->aCol[iCol].zName;
zType = pTab->aCol[iCol].zType;
}
if( p->span.z && p->span.z[0] && !showFullNames ){
int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0);
sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n);
if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){
int addr = sqliteVdbeOp3(v,OP_ColumnName, i, p2, p->span.z, p->span.n);
sqliteVdbeCompressSpace(v, addr);
}else if( pTabList->nSrc>1 || showFullNames ){
}else if( fullNames || (!shortNames && pTabList->nSrc>1) ){
char *zName = 0;
char *zTab;
zTab = pTabList->a[j].zAlias;
if( showFullNames || zTab==0 ) zTab = pTab->zName;
if( fullNames || zTab==0 ) zTab = pTab->zName;
sqliteSetString(&zName, zTab, ".", zCol, 0);
sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
sqliteVdbeChangeP3(v, -1, zName, strlen(zName));
sqliteFree(zName);
sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, P3_DYNAMIC);
}else{
sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
sqliteVdbeChangeP3(v, -1, zCol, 0);
sqliteVdbeOp3(v, OP_ColumnName, i, p2, zCol, 0);
}
}else if( p->span.z && p->span.z[0] ){
int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0);
sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n);
int addr = sqliteVdbeOp3(v,OP_ColumnName, i, p2, p->span.z, p->span.n);
sqliteVdbeCompressSpace(v, addr);
}else{
char zName[30];
assert( p->op!=TK_COLUMN || pTabList==0 );
sprintf(zName, "column%d", i+1);
sqliteVdbeAddOp(v, OP_ColumnName, i, 0);
sqliteVdbeChangeP3(v, -1, zName, strlen(zName));
sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, 0);
}
}
}
@ -777,8 +771,9 @@ static int fillInColumnList(Parse*, Select*);
*/
Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
Table *pTab;
int i;
int i, j;
ExprList *pEList;
Column *aCol;
if( fillInColumnList(pParse, pSelect) ){
return 0;
@ -791,17 +786,27 @@ Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){
pEList = pSelect->pEList;
pTab->nCol = pEList->nExpr;
assert( pTab->nCol>0 );
pTab->aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol );
pTab->aCol = aCol = sqliteMalloc( sizeof(pTab->aCol[0])*pTab->nCol );
for(i=0; i<pTab->nCol; i++){
Expr *p;
Expr *p, *pR;
if( pEList->a[i].zName ){
pTab->aCol[i].zName = sqliteStrDup(pEList->a[i].zName);
}else if( (p=pEList->a[i].pExpr)->span.z && p->span.z[0] ){
aCol[i].zName = sqliteStrDup(pEList->a[i].zName);
}else if( (p=pEList->a[i].pExpr)->op==TK_DOT
&& (pR=p->pRight)!=0 && pR->token.z && pR->token.z[0] ){
int cnt;
sqliteSetNString(&aCol[i].zName, pR->token.z, pR->token.n, 0);
for(j=cnt=0; j<i; j++){
if( sqliteStrICmp(aCol[j].zName, aCol[i].zName)==0 ){
int n;
char zBuf[30];
sprintf(zBuf,"_%d",++cnt);
n = strlen(zBuf);
sqliteSetNString(&aCol[i].zName, pR->token.z, pR->token.n, zBuf, n,0);
j = -1;
}
}
}else if( p->span.z && p->span.z[0] ){
sqliteSetNString(&pTab->aCol[i].zName, p->span.z, p->span.n, 0);
}else if( p->op==TK_DOT && p->pRight && p->pRight->token.z &&
p->pRight->token.z[0] ){
sqliteSetNString(&pTab->aCol[i].zName,
p->pRight->token.z, p->pRight->token.n, 0);
}else{
char zBuf[30];
sprintf(zBuf, "column%d", i+1);
@ -1262,7 +1267,7 @@ static void computeLimitRegisters(Parse *pParse, Select *p){
** |
** `-----> SELECT b FROM t2
** |
** `------> SELECT c FROM t1
** `------> SELECT a FROM t1
**
** The arrows in the diagram above represent the Select.pPrior pointer.
** So if this routine is called with p equal to the t3 query, then
@ -1485,14 +1490,6 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
" do not have the same number of result columns", selectOpName(p->op));
return 1;
}
/* Issue a null callback if that is what the user wants.
*/
if( eDest==SRT_Callback &&
(pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0)
){
sqliteVdbeAddOp(v, OP_NullCallback, p->pEList->nExpr, 0);
}
return 0;
}
@ -1512,25 +1509,29 @@ static int multiSelect(Parse *pParse, Select *p, int eDest, int iParm){
static void substExprList(ExprList*,int,ExprList*); /* Forward Decl */
static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){
if( pExpr==0 ) return;
if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable && pExpr->iColumn>=0 ){
Expr *pNew;
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
pNew = pEList->a[pExpr->iColumn].pExpr;
assert( pNew!=0 );
pExpr->op = pNew->op;
pExpr->dataType = pNew->dataType;
assert( pExpr->pLeft==0 );
pExpr->pLeft = sqliteExprDup(pNew->pLeft);
assert( pExpr->pRight==0 );
pExpr->pRight = sqliteExprDup(pNew->pRight);
assert( pExpr->pList==0 );
pExpr->pList = sqliteExprListDup(pNew->pList);
pExpr->iTable = pNew->iTable;
pExpr->iColumn = pNew->iColumn;
pExpr->iAgg = pNew->iAgg;
sqliteTokenCopy(&pExpr->token, &pNew->token);
sqliteTokenCopy(&pExpr->span, &pNew->span);
if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){
if( pExpr->iColumn<0 ){
pExpr->op = TK_NULL;
}else{
Expr *pNew;
assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );
assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );
pNew = pEList->a[pExpr->iColumn].pExpr;
assert( pNew!=0 );
pExpr->op = pNew->op;
pExpr->dataType = pNew->dataType;
assert( pExpr->pLeft==0 );
pExpr->pLeft = sqliteExprDup(pNew->pLeft);
assert( pExpr->pRight==0 );
pExpr->pRight = sqliteExprDup(pNew->pRight);
assert( pExpr->pList==0 );
pExpr->pList = sqliteExprListDup(pNew->pList);
pExpr->iTable = pNew->iTable;
pExpr->iColumn = pNew->iColumn;
pExpr->iAgg = pNew->iAgg;
sqliteTokenCopy(&pExpr->token, &pNew->token);
sqliteTokenCopy(&pExpr->span, &pNew->span);
}
}else{
substExpr(pExpr->pLeft, iTable, pEList);
substExpr(pExpr->pRight, iTable, pEList);
@ -1835,18 +1836,23 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
Vdbe *v;
int seekOp;
int cont;
ExprList eList;
ExprList *pEList, *pList, eList;
struct ExprList_item eListItem;
SrcList *pSrc;
/* Check to see if this query is a simple min() or max() query. Return
** zero if it is not.
*/
if( p->pGroupBy || p->pHaving || p->pWhere ) return 0;
if( p->pSrc->nSrc!=1 ) return 0;
if( p->pEList->nExpr!=1 ) return 0;
pExpr = p->pEList->a[0].pExpr;
pSrc = p->pSrc;
if( pSrc->nSrc!=1 ) return 0;
pEList = p->pEList;
if( pEList->nExpr!=1 ) return 0;
pExpr = pEList->a[0].pExpr;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0;
if( pExpr->pList==0 || pExpr->pList->nExpr!=1 ) return 0;
pList = pExpr->pList;
if( pList==0 || pList->nExpr!=1 ) return 0;
if( pExpr->token.n!=3 ) return 0;
if( sqliteStrNICmp(pExpr->token.z,"min",3)==0 ){
seekOp = OP_Rewind;
@ -1855,10 +1861,10 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
}else{
return 0;
}
pExpr = pExpr->pList->a[0].pExpr;
pExpr = pList->a[0].pExpr;
if( pExpr->op!=TK_COLUMN ) return 0;
iCol = pExpr->iColumn;
pTab = p->pSrc->a[0].pTab;
pTab = pSrc->a[0].pTab;
/* If we get to here, it means the query is of the correct form.
** Check to make sure we have an index and make pIdx point to the
@ -1886,24 +1892,30 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
generateColumnTypes(pParse, p->pSrc, p->pEList);
}
/* If the output is destined for a temporary table, open that table.
*/
if( eDest==SRT_TempTable ){
sqliteVdbeAddOp(v, OP_OpenTemp, iParm, 0);
}
/* Generating code to find the min or the max. Basically all we have
** to do is find the first or the last entry in the chosen index. If
** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
** or last entry in the main table.
*/
sqliteCodeVerifySchema(pParse, pTab->iDb);
base = p->pSrc->a[0].iCursor;
base = pSrc->a[0].iCursor;
computeLimitRegisters(pParse, p);
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
if( pSrc->a[0].pSelect==0 ){
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeOp3(v, OP_OpenRead, base, pTab->tnum, pTab->zName, 0);
}
cont = sqliteVdbeMakeLabel(v);
if( pIdx==0 ){
sqliteVdbeAddOp(v, seekOp, base, 0);
}else{
sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, base+1, pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pIdx->zName, P3_STATIC);
sqliteVdbeOp3(v, OP_OpenRead, base+1, pIdx->tnum, pIdx->zName, P3_STATIC);
sqliteVdbeAddOp(v, seekOp, base+1, 0);
sqliteVdbeAddOp(v, OP_IdxRecno, base+1, 0);
sqliteVdbeAddOp(v, OP_Close, base+1, 0);
@ -1916,6 +1928,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
selectInnerLoop(pParse, p, &eList, 0, 0, 0, -1, eDest, iParm, cont, cont);
sqliteVdbeResolveLabel(v, cont);
sqliteVdbeAddOp(v, OP_Close, base, 0);
return 1;
}
@ -1935,7 +1948,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
**
** SRT_Union Store results as a key in a temporary table iParm
**
** SRT_Except Remove results form the temporary table iParm.
** SRT_Except Remove results from the temporary table iParm.
**
** SRT_Table Store results in temporary table iParm
**
@ -2156,14 +2169,6 @@ int sqliteSelect(
generateColumnNames(pParse, pTabList, pEList);
}
/* Check for the special case of a min() or max() function by itself
** in the result set.
*/
if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){
rc = 0;
goto select_end;
}
/* Generate code for all sub-queries in the FROM clause
*/
for(i=0; i<pTabList->nSrc; i++){
@ -2193,6 +2198,14 @@ int sqliteSelect(
isDistinct = p->isDistinct;
}
/* Check for the special case of a min() or max() function by itself
** in the result set.
*/
if( simpleMinMaxQuery(pParse, p, eDest, iParm) ){
rc = 0;
goto select_end;
}
/* Check to see if this is a subquery that can be "flattened" into its parent.
** If flattening is a possiblity, do so and return immediately.
*/
@ -2262,8 +2275,7 @@ int sqliteSelect(
for(i=0; i<pParse->nAgg; i++){
FuncDef *pFunc;
if( (pFunc = pParse->aAgg[i].pFunc)!=0 && pFunc->xFinalize!=0 ){
sqliteVdbeAddOp(v, OP_AggInit, 0, i);
sqliteVdbeChangeP3(v, -1, (char*)pFunc, P3_POINTER);
sqliteVdbeOp3(v, OP_AggInit, 0, i, (char*)pFunc, P3_POINTER);
}
}
if( pGroupBy==0 ){
@ -2308,6 +2320,7 @@ int sqliteSelect(
** processing.
*/
else{
AggExpr *pAgg;
if( pGroupBy ){
int lbl1;
for(i=0; i<pGroupBy->nExpr; i++){
@ -2317,29 +2330,27 @@ int sqliteSelect(
if( pParse->db->file_format>=4 ) sqliteAddKeyType(v, pGroupBy);
lbl1 = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_AggFocus, 0, lbl1);
for(i=0; i<pParse->nAgg; i++){
if( pParse->aAgg[i].isAgg ) continue;
sqliteExprCode(pParse, pParse->aAgg[i].pExpr);
for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
if( pAgg->isAgg ) continue;
sqliteExprCode(pParse, pAgg->pExpr);
sqliteVdbeAddOp(v, OP_AggSet, 0, i);
}
sqliteVdbeResolveLabel(v, lbl1);
}
for(i=0; i<pParse->nAgg; i++){
for(i=0, pAgg=pParse->aAgg; i<pParse->nAgg; i++, pAgg++){
Expr *pE;
int j;
if( !pParse->aAgg[i].isAgg ) continue;
pE = pParse->aAgg[i].pExpr;
int nExpr;
FuncDef *pDef;
if( !pAgg->isAgg ) continue;
assert( pAgg->pFunc!=0 );
assert( pAgg->pFunc->xStep!=0 );
pDef = pAgg->pFunc;
pE = pAgg->pExpr;
assert( pE!=0 );
assert( pE->op==TK_AGG_FUNCTION );
if( pE->pList ){
for(j=0; j<pE->pList->nExpr; j++){
sqliteExprCode(pParse, pE->pList->a[j].pExpr);
}
}
nExpr = sqliteExprCodeExprList(pParse, pE->pList, pDef->includeTypes);
sqliteVdbeAddOp(v, OP_Integer, i, 0);
sqliteVdbeAddOp(v, OP_AggFunc, 0, pE->pList ? pE->pList->nExpr : 0);
assert( pParse->aAgg[i].pFunc!=0 );
assert( pParse->aAgg[i].pFunc->xStep!=0 );
sqliteVdbeChangeP3(v, -1, (char*)pParse->aAgg[i].pFunc, P3_POINTER);
sqliteVdbeOp3(v, OP_AggFunc, 0, nExpr, (char*)pDef, P3_POINTER);
}
}
@ -2375,13 +2386,16 @@ int sqliteSelect(
generateSortTail(p, v, pEList->nExpr, eDest, iParm);
}
/* Issue a null callback if that is what the user wants.
/* If this was a subquery, we have now converted the subquery into a
** temporary table. So delete the subquery structure from the parent
** to prevent this subquery from being evaluated again and to force the
** the use of the temporary table.
*/
if( eDest==SRT_Callback &&
(pParse->useCallback==0 || (pParse->db->flags & SQLITE_NullCallback)!=0)
){
sqliteVdbeAddOp(v, OP_NullCallback, pEList->nExpr, 0);
if( pParent ){
assert( pParent->pSrc->nSrc>parentTab );
assert( pParent->pSrc->a[parentTab].pSelect==p );
sqliteSelectDelete(p);
pParent->pSrc->a[parentTab].pSelect = 0;
}
/* The SELECT was successfully coded. Set the return code to 0

View file

@ -167,6 +167,7 @@ int sqlite_exec(
#define SQLITE_AUTH 23 /* Authorization denied */
#define SQLITE_FORMAT 24 /* Auxiliary database format error */
#define SQLITE_RANGE 25 /* 2nd parameter to sqlite_bind out of range */
#define SQLITE_NOTADB 26 /* File opened that is not a database file */
#define SQLITE_ROW 100 /* sqlite_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite_step() has finished executing */
@ -203,6 +204,32 @@ int sqlite_last_insert_rowid(sqlite*);
*/
int sqlite_changes(sqlite*);
/*
** This function returns the number of database rows that were changed
** by the last INSERT, UPDATE, or DELETE statment executed by sqlite_exec(),
** or by the last VM to run to completion. The change count is not updated
** by SQL statements other than INSERT, UPDATE or DELETE.
**
** Changes are counted, even if they are later undone by a ROLLBACK or
** ABORT. Changes associated with trigger programs that execute as a
** result of the INSERT, UPDATE, or DELETE statement are not counted.
**
** If a callback invokes sqlite_exec() recursively, then the changes
** in the inner, recursive call are counted together with the changes
** in the outer call.
**
** SQLite implements the command "DELETE FROM table" without a WHERE clause
** by dropping and recreating the table. (This is much faster than going
** through and deleting individual elements form the table.) Because of
** this optimization, the change count for "DELETE FROM table" will be
** zero regardless of the number of elements that were originally in the
** table. To get an accurate count of the number of rows deleted, use
** "DELETE FROM table WHERE 1" instead.
**
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
*/
int sqlite_last_statement_changes(sqlite*);
/* If the parameter to this routine is one of the return value constants
** defined above, then this routine returns a constant text string which
** descripts (in English) the meaning of the return value.
@ -262,7 +289,7 @@ void sqlite_busy_handler(sqlite*, int(*)(void*,const char*,int), void*);
** Calling this routine with an argument less than or equal to zero
** turns off all busy handlers.
*/
void sqlite_busy_timeout(sqlite*, long ms);
void sqlite_busy_timeout(sqlite*, int ms);
/*
** This next routine is really just a wrapper around sqlite_exec().
@ -439,13 +466,12 @@ int sqlite_create_aggregate(
** Use the following routine to define the datatype returned by a
** user-defined function. The second argument can be one of the
** constants SQLITE_NUMERIC, SQLITE_TEXT, or SQLITE_ARGS or it
** can be an integer greater than or equal to zero. The datatype
** will be numeric or text (the only two types supported) if the
** argument is SQLITE_NUMERIC or SQLITE_TEXT. If the argument is
** SQLITE_ARGS, then the datatype is numeric if any argument to the
** function is numeric and is text otherwise. If the second argument
** is an integer, then the datatype of the result is the same as the
** parameter to the function that corresponds to that integer.
** can be an integer greater than or equal to zero. When the datatype
** parameter is non-negative, the type of the result will be the
** same as the datatype-th argument. If datatype==SQLITE_NUMERIC
** then the result is always numeric. If datatype==SQLITE_TEXT then
** the result is always text. If datatype==SQLITE_ARGS then the result
** is numeric if any argument is numeric and is text otherwise.
*/
int sqlite_function_type(
sqlite *db, /* The database there the function is registered */
@ -753,9 +779,88 @@ int sqlite_bind(sqlite_vm*, int idx, const char *value, int len, int copy);
** query is immediately terminated and any database changes rolled back. If the
** query was part of a larger transaction, then the transaction is not rolled
** back and remains active. The sqlite_exec() call returns SQLITE_ABORT.
**
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
*/
void sqlite_progress_handler(sqlite*, int, int(*)(void*), void*);
/*
** Register a callback function to be invoked whenever a new transaction
** is committed. The pArg argument is passed through to the callback.
** callback. If the callback function returns non-zero, then the commit
** is converted into a rollback.
**
** If another function was previously registered, its pArg value is returned.
** Otherwise NULL is returned.
**
** Registering a NULL function disables the callback.
**
******* THIS IS AN EXPERIMENTAL API AND IS SUBJECT TO CHANGE ******
*/
void *sqlite_commit_hook(sqlite*, int(*)(void*), void*);
/*
** Open an encrypted SQLite database. If pKey==0 or nKey==0, this routine
** is the same as sqlite_open().
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
sqlite *sqlite_open_encrypted(
const char *zFilename, /* Name of the encrypted database */
const void *pKey, /* Pointer to the key */
int nKey, /* Number of bytes in the key */
int *pErrcode, /* Write error code here */
char **pzErrmsg /* Write error message here */
);
/*
** Change the key on an open database. If the current database is not
** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
** database is decrypted.
**
** The code to implement this API is not available in the public release
** of SQLite.
*/
int sqlite_rekey(
sqlite *db, /* Database to be rekeyed */
const void *pKey, int nKey /* The new key */
);
/*
** Encode a binary buffer "in" of size n bytes so that it contains
** no instances of characters '\'' or '\000'. The output is
** null-terminated and can be used as a string value in an INSERT
** or UPDATE statement. Use sqlite_decode_binary() to convert the
** string back into its original binary.
**
** The result is written into a preallocated output buffer "out".
** "out" must be able to hold at least 2 +(257*n)/254 bytes.
** In other words, the output will be expanded by as much as 3
** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.
** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)
**
** The return value is the number of characters in the encoded
** string, excluding the "\000" terminator.
**
** If out==NULL then no output is generated but the routine still returns
** the number of characters that would have been generated if out had
** not been NULL.
*/
int sqlite_encode_binary(const unsigned char *in, int n, unsigned char *out);
/*
** Decode the string "in" into binary data and write it into "out".
** This routine reverses the encoding created by sqlite_encode_binary().
** The output will always be a few bytes less than the input. The number
** of bytes of output is returned. If the input is not a well-formed
** encoding, -1 is returned.
**
** The "in" and "out" parameters may point to the same buffer in order
** to decode a string in place.
*/
int sqlite_decode_binary(const unsigned char *in, unsigned char *out);
#ifdef __cplusplus
} /* End of the 'extern "C"' block */
#endif

View file

@ -16,7 +16,6 @@
#include "config.h"
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
#include <stdio.h>
@ -106,6 +105,9 @@
#ifndef UINT8_TYPE
# define UINT8_TYPE unsigned char
#endif
#ifndef INT8_TYPE
# define INT8_TYPE signed char
#endif
#ifndef INTPTR_TYPE
# if SQLITE_PTR_SZ==4
# define INTPTR_TYPE int
@ -116,9 +118,15 @@
typedef UINT32_TYPE u32; /* 4-byte unsigned integer */
typedef UINT16_TYPE u16; /* 2-byte unsigned integer */
typedef UINT8_TYPE u8; /* 1-byte unsigned integer */
typedef UINT8_TYPE i8; /* 1-byte signed integer */
typedef INTPTR_TYPE ptr; /* Big enough to hold a pointer */
typedef unsigned INTPTR_TYPE uptr; /* Big enough to hold a pointer */
/*
** Defer sourcing vdbe.h until after the "u8" typedef is defined.
*/
#include "vdbe.h"
/*
** Most C compilers these days recognize "long double", don't they?
** Just in case we encounter one that does not, we will create a macro
@ -174,6 +182,7 @@ typedef unsigned INTPTR_TYPE uptr; /* Big enough to hold a pointer */
# define sqliteStrNDup(X,Y) sqliteStrNDup_(X,Y,__FILE__,__LINE__)
void sqliteStrRealloc(char**);
#else
# define sqliteRealloc_(X,Y) sqliteRealloc(X,Y)
# define sqliteStrRealloc(X)
#endif
@ -254,6 +263,8 @@ struct Db {
Hash aFKey; /* Foreign keys indexed by to-table */
u8 inTrans; /* 0: not writable. 1: Transaction. 2: Checkpoint */
u16 flags; /* Flags associated with this database */
void *pAux; /* Auxiliary data. Usually NULL */
void (*xFreeAux)(void*); /* Routine to free pAux */
};
/*
@ -307,6 +318,24 @@ struct Db {
** are stored. If 1, then a file is created to hold those tables. If
** 2, then they are held in memory. 0 means use the default value in
** the TEMP_STORE macro.
**
** The sqlite.lastRowid records the last insert rowid generated by an
** insert statement. Inserts on views do not affect its value. Each
** trigger has its own context, so that lastRowid can be updated inside
** triggers as usual. The previous value will be restored once the trigger
** exits. Upon entering a before or instead of trigger, lastRowid is no
** longer (since after version 2.8.12) reset to -1.
**
** The sqlite.nChange does not count changes within triggers and keeps no
** context. It is reset at start of sqlite_exec.
** The sqlite.lsChange represents the number of changes made by the last
** insert, update, or delete statement. It remains constant throughout the
** length of a statement and is then updated by OP_SetCounts. It keeps a
** context stack just like lastRowid so that the count of changes
** within a trigger is not seen outside the trigger. Changes to views do not
** affect the value of lsChange.
** The sqlite.csChange keeps track of the number of current changes (since
** the last statement) and is used to update sqlite_lsChange.
*/
struct sqlite {
int nDb; /* Number of backends currently in use */
@ -316,18 +345,27 @@ struct sqlite {
u8 file_format; /* What file format version is this database? */
u8 safety_level; /* How aggressive at synching data to disk */
u8 want_to_close; /* Close after all VDBEs are deallocated */
u8 temp_store; /* 1=file, 2=memory, 0=compile-time default */
u8 onError; /* Default conflict algorithm */
int next_cookie; /* Next value of aDb[0].schema_cookie */
int cache_size; /* Number of pages to use in the cache */
int temp_store; /* 1=file, 2=memory, 0=compile-time default */
int nTable; /* Number of tables in the database */
void *pBusyArg; /* 1st Argument to the busy callback */
int (*xBusyCallback)(void *,const char*,int); /* The busy callback */
void *pCommitArg; /* Argument to xCommitCallback() */
int (*xCommitCallback)(void*);/* Invoked at every commit. */
Hash aFunc; /* All functions that can be in SQL exprs */
int lastRowid; /* ROWID of most recent insert */
int lastRowid; /* ROWID of most recent insert (see above) */
int priorNewRowid; /* Last randomly generated ROWID */
int onError; /* Default conflict algorithm */
int magic; /* Magic number for detect library misuse */
int nChange; /* Number of rows changed */
int nChange; /* Number of rows changed (see above) */
int lsChange; /* Last statement change count (see above) */
int csChange; /* Current statement change count (see above) */
struct sqliteInitInfo { /* Information used during initialization */
int iDb; /* When back is being initialized */
int newTnum; /* Rootpage of table being initialized */
u8 busy; /* TRUE if currently initializing */
} init;
struct Vdbe *pVdbe; /* List of active virtual machines */
void (*xTrace)(void*,const char*); /* Trace function */
void *pTraceArg; /* Argument to the trace function */
@ -356,10 +394,11 @@ struct sqlite {
#define SQLITE_InTrans 0x00000008 /* True if in a transaction */
#define SQLITE_InternChanges 0x00000010 /* Uncommitted Hash table changes */
#define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */
#define SQLITE_CountRows 0x00000040 /* Count rows changed by INSERT, */
#define SQLITE_ShortColNames 0x00000040 /* Show short columns names */
#define SQLITE_CountRows 0x00000080 /* Count rows changed by INSERT, */
/* DELETE, or UPDATE and return */
/* the count using a callback. */
#define SQLITE_NullCallback 0x00000080 /* Invoke the callback once if the */
#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
/* result set is empty */
#define SQLITE_ReportTypes 0x00000200 /* Include information on datatypes */
/* in 4th argument of callback */
@ -384,10 +423,12 @@ struct FuncDef {
void (*xFunc)(sqlite_func*,int,const char**); /* Regular function */
void (*xStep)(sqlite_func*,int,const char**); /* Aggregate function step */
void (*xFinalize)(sqlite_func*); /* Aggregate function finializer */
int nArg; /* Number of arguments */
int dataType; /* Datatype of the result */
void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */
signed char nArg; /* Number of arguments. -1 means unlimited */
signed char dataType; /* Arg that determines datatype. -1=NUMERIC, */
/* -2=TEXT. -3=SQLITE_ARGS */
u8 includeTypes; /* Add datatypes to args of xFunc and xStep */
void *pUserData; /* User data parameter */
FuncDef *pNext; /* Next function with same name */
};
/*
@ -401,6 +442,7 @@ struct Column {
u8 notNull; /* True if there is a NOT NULL constraint */
u8 isPrimKey; /* True if this column is part of the PRIMARY KEY */
u8 sortOrder; /* Some combination of SQLITE_SO_... values */
u8 dottedName; /* True if zName contains a "." character */
};
/*
@ -585,6 +627,10 @@ struct Index {
/*
** Each token coming out of the lexer is an instance of
** this structure. Tokens are also used as part of an expression.
**
** Note if Token.z==0 then Token.dyn and Token.n are undefined and
** may contain random values. Do not make any assuptions about Token.dyn
** and Token.n when Token.z==0.
*/
struct Token {
const char *z; /* Text of the token. Not NULL-terminated! */
@ -859,8 +905,6 @@ struct AggExpr {
struct Parse {
sqlite *db; /* The main database structure */
int rc; /* Return code from execution */
sqlite_callback xCallback; /* The callback function */
void *pArg; /* First argument to the callback function */
char *zErrMsg; /* An error message */
Token sErrToken; /* The token at which the error occurred */
Token sFirstToken; /* The first token parsed */
@ -870,13 +914,9 @@ struct Parse {
Vdbe *pVdbe; /* An engine for executing database bytecode */
u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
u8 explain; /* True if the EXPLAIN flag is found on the query */
u8 initFlag; /* True if reparsing CREATE TABLEs */
u8 nameClash; /* A permanent table name clashes with temp table name */
u8 useAgg; /* If true, extract field values from the aggregator
** while generating expressions. Normally false */
u8 iDb; /* Index of database whose schema is being parsed */
u8 useCallback; /* True if callbacks should be used to report results */
int newTnum; /* Table number to use when reparsing CREATE TABLEs */
int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */
@ -898,6 +938,13 @@ struct AuthContext {
Parse *pParse; /* The Parse structure */
};
/*
** Bitfield flags for P2 value in OP_PutIntKey and OP_Delete
*/
#define OPFLAG_NCHANGE 1 /* Set to update db->nChange */
#define OPFLAG_LASTROWID 2 /* Set to update db->lastRowid */
#define OPFLAG_CSCHANGE 4 /* Set to update db->csChange */
/*
* Each trigger present in the database schema is stored as an instance of
* struct Trigger.
@ -1067,7 +1114,8 @@ void sqliteRealToSortable(double r, char *);
char *sqliteStrNDup(const char*, int);
# define sqliteCheckMemory(a,b)
#endif
char *sqliteMPrintf(const char *,...);
char *sqliteMPrintf(const char*, ...);
char *sqliteVMPrintf(const char*, va_list);
void sqliteSetString(char **, const char *, ...);
void sqliteSetNString(char **, ...);
void sqliteErrorMsg(Parse*, const char*, ...);
@ -1126,6 +1174,7 @@ void sqliteUpdate(Parse*, SrcList*, ExprList*, Expr*, int);
WhereInfo *sqliteWhereBegin(Parse*, SrcList*, Expr*, int, ExprList**);
void sqliteWhereEnd(WhereInfo*);
void sqliteExprCode(Parse*, Expr*);
int sqliteExprCodeExprList(Parse*, ExprList*, int);
void sqliteExprIfTrue(Parse*, Expr*, int, int);
void sqliteExprIfFalse(Parse*, Expr*, int, int);
Table *sqliteFindTable(sqlite*,const char*, const char*);
@ -1145,8 +1194,7 @@ int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, SrcList*, ExprList*, Expr*);
int sqliteExprAnalyzeAggregates(Parse*, Expr*);
Vdbe *sqliteGetVdbe(Parse*);
int sqliteRandomByte(void);
int sqliteRandomInteger(void);
void sqliteRandomness(int, void*);
void sqliteRollbackAll(sqlite*);
void sqliteCodeVerifySchema(Parse*, int);
void sqliteBeginTransaction(Parse*, int);
@ -1159,6 +1207,7 @@ void sqliteGenerateRowDelete(sqlite*, Vdbe*, Table*, int, int);
void sqliteGenerateRowIndexDelete(sqlite*, Vdbe*, Table*, int, char*);
void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int, int);
int sqliteOpenTableAndIndices(Parse*, Table*, int);
void sqliteBeginWriteOperation(Parse*, int, int);
void sqliteEndWriteOperation(Parse*);
Expr *sqliteExprDup(Expr*);
@ -1202,7 +1251,7 @@ void sqliteDeferForeignKey(Parse*, int);
# define sqliteAuthContextPush(a,b,c)
# define sqliteAuthContextPop(a) ((void)(a))
#endif
void sqliteAttach(Parse*, Token*, Token*);
void sqliteAttach(Parse*, Token*, Token*, Token*);
void sqliteDetach(Parse*, Token*);
int sqliteBtreeFactory(const sqlite *db, const char *zFilename,
int mode, int nPg, Btree **ppBtree);
@ -1212,6 +1261,6 @@ int sqliteFixSelect(DbFixer*, Select*);
int sqliteFixExpr(DbFixer*, Expr*);
int sqliteFixExprList(DbFixer*, ExprList*);
int sqliteFixTriggerStep(DbFixer*, TriggerStep*);
double sqliteAtoF(const char *z);
int sqlite_snprintf(int,char*,const char*,...);
double sqliteAtoF(const char *z, const char **);
char *sqlite_snprintf(int,char*,const char*,...);
int sqliteFitsIn32Bits(const char *);

View file

@ -474,7 +474,7 @@ abort_parse:
pParse->zErrMsg = 0;
if( !nErr ) nErr++;
}
if( pParse->pVdbe && (pParse->useCallback || pParse->nErr>0) ){
if( pParse->pVdbe && pParse->nErr>0 ){
sqliteVdbeDelete(pParse->pVdbe);
pParse->pVdbe = 0;
}

View file

@ -65,8 +65,8 @@ void sqliteBeginTrigger(
*/
if( sqlite_malloc_failed ) goto trigger_cleanup;
assert( pTableName->nSrc==1 );
if( pParse->initFlag
&& sqliteFixInit(&sFix, pParse, pParse->iDb, "trigger", pName)
if( db->init.busy
&& sqliteFixInit(&sFix, pParse, db->init.iDb, "trigger", pName)
&& sqliteFixSrcList(&sFix, pTableName)
){
goto trigger_cleanup;
@ -76,7 +76,7 @@ void sqliteBeginTrigger(
goto trigger_cleanup;
}
iDb = isTemp ? 1 : tab->iDb;
if( iDb>=2 && !pParse->initFlag ){
if( iDb>=2 && !db->init.busy ){
sqliteErrorMsg(pParse, "triggers may not be added to auxiliary "
"database %s", db->aDb[tab->iDb].zName);
goto trigger_cleanup;
@ -181,8 +181,8 @@ void sqliteFinishTrigger(
/* if we are not initializing, and this trigger is not on a TEMP table,
** build the sqlite_master entry
*/
if( !pParse->initFlag ){
static VdbeOp insertTrig[] = {
if( !db->init.busy ){
static VdbeOpList insertTrig[] = {
{ OP_NewRecno, 0, 0, 0 },
{ OP_String, 0, 0, "trigger" },
{ OP_String, 0, 0, 0 }, /* 2: trigger name */
@ -450,7 +450,7 @@ void sqliteDropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){
*/
if( pTable!=0 && !nested && (v = sqliteGetVdbe(pParse))!=0 ){
int base;
static VdbeOp dropTrigger[] = {
static VdbeOpList dropTrigger[] = {
{ OP_Rewind, 0, ADDR(9), 0},
{ OP_String, 0, 0, 0}, /* 1 */
{ OP_Column, 0, 1, 0},
@ -746,7 +746,9 @@ int sqliteCodeRowTrigger(
sqliteExprIfFalse(pParse, whenExpr, endTrigger, 1);
sqliteExprDelete(whenExpr);
sqliteVdbeAddOp(pParse->pVdbe, OP_ContextPush, 0, 0);
codeTriggerProgram(pParse, pTrigger->step_list, orconf);
sqliteVdbeAddOp(pParse->pVdbe, OP_ContextPop, 0, 0);
/* Pop the entry off the trigger stack */
pParse->trigStack = pParse->trigStack->pNext;

View file

@ -32,7 +32,8 @@ void sqliteUpdate(
){
int i, j; /* Loop counters */
Table *pTab; /* The table to be updated */
int addr; /* VDBE instruction address of the start of the loop */
int loopStart; /* VDBE instruction address of the start of the loop */
int jumpInst; /* Addr of VDBE instruction to jump out of loop */
WhereInfo *pWInfo; /* Information about the WHERE clause */
Vdbe *v; /* The virtual database engine */
Index *pIdx; /* For looping over indices */
@ -49,6 +50,7 @@ void sqliteUpdate(
Expr *pRecnoExpr; /* Expression defining the new record number */
int openAll; /* True if all indices need to be opened */
int isView; /* Trying to update a view */
int iStackDepth; /* Index of memory cell holding stack depth */
AuthContext sContext; /* The authorization context */
int before_triggers; /* True if there are any BEFORE triggers */
@ -62,6 +64,7 @@ void sqliteUpdate(
if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
db = pParse->db;
assert( pTabList->nSrc==1 );
iStackDepth = pParse->nMem++;
/* Locate the table which we want to update.
*/
@ -248,7 +251,11 @@ void sqliteUpdate(
/* The top of the update loop for when there are triggers.
*/
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
sqliteVdbeAddOp(v, OP_StackDepth, 0, 0);
sqliteVdbeAddOp(v, OP_MemStore, iStackDepth, 1);
loopStart = sqliteVdbeAddOp(v, OP_MemLoad, iStackDepth, 0);
sqliteVdbeAddOp(v, OP_StackReset, 0, 0);
jumpInst = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
/* Open a cursor and make it point to the record that is
@ -295,7 +302,7 @@ void sqliteUpdate(
/* Fire the BEFORE and INSTEAD OF triggers
*/
if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab,
newIdx, oldIdx, onError, addr) ){
newIdx, oldIdx, onError, loopStart) ){
goto update_cleanup;
}
}
@ -336,10 +343,10 @@ void sqliteUpdate(
*/
if( !row_triggers_exist ){
sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
jumpInst = loopStart = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
sqliteVdbeAddOp(v, OP_Dup, 0, 0);
}
sqliteVdbeAddOp(v, OP_NotExists, iCur, addr);
sqliteVdbeAddOp(v, OP_NotExists, iCur, loopStart);
/* If the record number will change, push the record number as it
** will be after the update. (The old record number is currently
@ -368,7 +375,7 @@ void sqliteUpdate(
/* Do constraint checks
*/
sqliteGenerateConstraintChecks(pParse, pTab, iCur, aIdxUsed, chngRecno, 1,
onError, addr);
onError, loopStart);
/* Delete the old indices for the current record.
*/
@ -404,7 +411,7 @@ void sqliteUpdate(
pParse->nTab = iCur;
}
if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_AFTER, pTab,
newIdx, oldIdx, onError, addr) ){
newIdx, oldIdx, onError, loopStart) ){
goto update_cleanup;
}
}
@ -412,8 +419,8 @@ void sqliteUpdate(
/* Repeat the above with the next record to be updated, until
** all record selected by the WHERE clause have been updated.
*/
sqliteVdbeAddOp(v, OP_Goto, 0, addr);
sqliteVdbeChangeP2(v, addr, sqliteVdbeCurrentAddr(v));
sqliteVdbeAddOp(v, OP_Goto, 0, loopStart);
sqliteVdbeChangeP2(v, jumpInst, sqliteVdbeCurrentAddr(v));
sqliteVdbeAddOp(v, OP_ListReset, 0, 0);
/* Close all tables if there were no FOR EACH ROW triggers */
@ -430,14 +437,14 @@ void sqliteUpdate(
sqliteVdbeAddOp(v, OP_Close, oldIdx, 0);
}
sqliteVdbeAddOp(v, OP_SetCounts, 0, 0);
sqliteEndWriteOperation(pParse);
/*
** Return the number of rows that were changed.
*/
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
sqliteVdbeAddOp(v, OP_ColumnName, 0, 0);
sqliteVdbeChangeP3(v, -1, "rows updated", P3_STATIC);
sqliteVdbeOp3(v, OP_ColumnName, 0, 1, "rows updated", P3_STATIC);
sqliteVdbeAddOp(v, OP_Callback, 1, 0);
}

View file

@ -417,120 +417,11 @@ void sqliteSetNString(char **pz, ...){
*/
void sqliteErrorMsg(Parse *pParse, const char *zFormat, ...){
va_list ap;
int nByte;
int i, j;
char *z;
static char zNull[] = "NULL";
pParse->nErr++;
nByte = 1 + strlen(zFormat);
va_start(ap, zFormat);
for(i=0; zFormat[i]; i++){
if( zFormat[i]!='%' || zFormat[i+1]==0 ) continue;
i++;
switch( zFormat[i] ){
case 'd': {
(void)va_arg(ap, int);
nByte += 20;
break;
}
case 'z':
case 's': {
char *z2 = va_arg(ap, char*);
if( z2==0 ) z2 = zNull;
nByte += strlen(z2);
break;
}
case 'T': {
Token *p = va_arg(ap, Token*);
nByte += p->n;
break;
}
case 'S': {
SrcList *p = va_arg(ap, SrcList*);
int k = va_arg(ap, int);
assert( p->nSrc>k && k>=0 );
nByte += strlen(p->a[k].zName);
if( p->a[k].zDatabase && p->a[k].zDatabase[0] ){
nByte += strlen(p->a[k].zDatabase)+1;
}
break;
}
default: {
nByte++;
break;
}
}
}
va_end(ap);
z = sqliteMalloc( nByte );
if( z==0 ) return;
sqliteFree(pParse->zErrMsg);
pParse->zErrMsg = z;
va_start(ap, zFormat);
for(i=j=0; zFormat[i]; i++){
if( zFormat[i]!='%' || zFormat[i+1]==0 ) continue;
if( i>j ){
memcpy(z, &zFormat[j], i-j);
z += i-j;
}
j = i+2;
i++;
switch( zFormat[i] ){
case 'd': {
int x = va_arg(ap, int);
sprintf(z, "%d", x);
z += strlen(z);
break;
}
case 'z':
case 's': {
int len;
char *z2 = va_arg(ap, char*);
if( z2==0 ) z2 = zNull;
len = strlen(z2);
memcpy(z, z2, len);
z += len;
if( zFormat[i]=='z' && z2!=zNull ){
sqliteFree(z2);
}
break;
}
case 'T': {
Token *p = va_arg(ap, Token*);
memcpy(z, p->z, p->n);
z += p->n;
break;
}
case 'S': {
int len;
SrcList *p = va_arg(ap, SrcList*);
int k = va_arg(ap, int);
assert( p->nSrc>k && k>=0 );
if( p->a[k].zDatabase && p->a[k].zDatabase[0] ){
len = strlen(p->a[k].zDatabase);
memcpy(z, p->a[k].zDatabase, len);
z += len;
*(z++) = '.';
}
len = strlen(p->a[k].zName);
memcpy(z, p->a[k].zName, len);
z += len;
break;
}
default: {
*(z++) = zFormat[i];
break;
}
}
}
pParse->zErrMsg = sqliteVMPrintf(zFormat, ap);
va_end(ap);
if( i>j ){
memcpy(z, &zFormat[j], i-j);
z += i-j;
}
assert( (z - pParse->zErrMsg) < nByte );
*z = 0;
}
/*
@ -662,7 +553,7 @@ int sqliteIsNumber(const char *z){
** of "." depending on how locale is set. But that would cause problems
** for SQL. So this routine always uses "." regardless of locale.
*/
double sqliteAtoF(const char *z){
double sqliteAtoF(const char *z, const char **pzEnd){
int sign = 1;
LONGDOUBLE_TYPE v1 = 0.0;
if( *z=='-' ){
@ -710,6 +601,7 @@ double sqliteAtoF(const char *z){
v1 *= scale;
}
}
if( pzEnd ) *pzEnd = z;
return sign<0 ? -v1 : v1;
}
@ -759,8 +651,8 @@ int sqliteCompare(const char *atext, const char *btext){
result = -1;
}else{
double rA, rB;
rA = sqliteAtoF(atext);
rB = sqliteAtoF(btext);
rA = sqliteAtoF(atext, 0);
rB = sqliteAtoF(btext, 0);
if( rA<rB ){
result = -1;
}else if( rA>rB ){
@ -852,8 +744,8 @@ int sqliteSortCompare(const char *a, const char *b){
res = -1;
break;
}
rA = sqliteAtoF(&a[1]);
rB = sqliteAtoF(&b[1]);
rA = sqliteAtoF(&a[1], 0);
rB = sqliteAtoF(&b[1], 0);
if( rA<rB ){
res = -1;
break;

View file

@ -108,7 +108,6 @@ static int execsql(char **pzErrMsg, sqlite *db, const char *zSql){
*/
static int vacuumCallback2(void *pArg, int argc, char **argv, char **NotUsed){
vacuumStruct *p = (vacuumStruct*)pArg;
int rc = 0;
const char *zSep = "(";
int i;
@ -127,8 +126,8 @@ static int vacuumCallback2(void *pArg, int argc, char **argv, char **NotUsed){
}
}
appendText(&p->s2,")", 1);
rc = execsql(p->pzErrMsg, p->dbNew, p->s2.z);
return rc;
p->rc = execsql(p->pzErrMsg, p->dbNew, p->s2.z);
return p->rc;
}
/*
@ -160,6 +159,7 @@ static int vacuumCallback1(void *pArg, int argc, char **argv, char **NotUsed){
sqlite_freemem(zErrMsg);
}
}
if( rc!=SQLITE_ABORT ) p->rc = rc;
return rc;
}
@ -170,7 +170,6 @@ static int vacuumCallback1(void *pArg, int argc, char **argv, char **NotUsed){
*/
static int vacuumCallback3(void *pArg, int argc, char **argv, char **NotUsed){
vacuumStruct *p = (vacuumStruct*)pArg;
int rc = 0;
char zBuf[200];
assert( argc==1 );
if( argv==0 ) return 0;
@ -178,21 +177,21 @@ static int vacuumCallback3(void *pArg, int argc, char **argv, char **NotUsed){
assert( strlen(p->zPragma)<100 );
assert( strlen(argv[0])<30 );
sprintf(zBuf,"PRAGMA %s=%s;", p->zPragma, argv[0]);
rc = execsql(p->pzErrMsg, p->dbNew, zBuf);
return rc;
p->rc = execsql(p->pzErrMsg, p->dbNew, zBuf);
return p->rc;
}
/*
** Generate a random name of 20 character in length.
*/
static void randomName(char *zBuf){
static const char zChars[] =
static void randomName(unsigned char *zBuf){
static const unsigned char zChars[] =
"abcdefghijklmnopqrstuvwxyz"
"0123456789";
int i;
sqliteRandomness(20, zBuf);
for(i=0; i<20; i++){
int n = sqliteRandomByte() % (sizeof(zChars)-1);
zBuf[i] = zChars[n];
zBuf[i] = zChars[ zBuf[i]%(sizeof(zChars)-1) ];
}
}
#endif
@ -240,6 +239,9 @@ int sqliteRunVacuum(char **pzErrMsg, sqlite *db){
(char*)0);
return SQLITE_ERROR;
}
if( db->flags & SQLITE_Interrupt ){
return SQLITE_INTERRUPT;
}
memset(&sVac, 0, sizeof(sVac));
/* Get the full pathname of the database file and create two
@ -257,7 +259,7 @@ int sqliteRunVacuum(char **pzErrMsg, sqlite *db){
strcpy(zTemp, zFilename);
for(i=0; i<10; i++){
zTemp[nFilename] = '-';
randomName(&zTemp[nFilename+1]);
randomName((unsigned char*)&zTemp[nFilename+1]);
if( !sqliteOsFileExists(zTemp) ) break;
}
if( i>=10 ){
@ -273,8 +275,8 @@ int sqliteRunVacuum(char **pzErrMsg, sqlite *db){
zTemp, " - ", zErrMsg, (char*)0);
goto end_of_vacuum;
}
if( execsql(pzErrMsg, db, "BEGIN") ) goto end_of_vacuum;
if( execsql(pzErrMsg, dbNew, "PRAGMA synchronous=off; BEGIN") ){
if( (rc = execsql(pzErrMsg, db, "BEGIN"))!=0 ) goto end_of_vacuum;
if( (rc = execsql(pzErrMsg, dbNew, "PRAGMA synchronous=off; BEGIN"))!=0 ){
goto end_of_vacuum;
}
@ -309,13 +311,17 @@ end_of_vacuum:
zErrMsg, (char*)0);
}
sqlite_exec(db, "ROLLBACK", 0, 0, 0);
if( (dbNew && (dbNew->flags & SQLITE_Interrupt))
|| (db->flags & SQLITE_Interrupt) ){
rc = SQLITE_INTERRUPT;
}
if( dbNew ) sqlite_close(dbNew);
sqliteOsDelete(zTemp);
sqliteFree(zTemp);
sqliteFree(sVac.s1.z);
sqliteFree(sVac.s2.z);
if( zErrMsg ) sqlite_freemem(zErrMsg);
if( rc==SQLITE_ABORT ) rc = SQLITE_ERROR;
return rc;
if( rc==SQLITE_ABORT && sVac.rc!=SQLITE_INTERRUPT ) sVac.rc = SQLITE_ERROR;
return sVac.rc;
#endif
}

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,7 @@ typedef struct Vdbe Vdbe;
** as an instance of the following structure:
*/
struct VdbeOp {
int opcode; /* What operation to perform */
u8 opcode; /* What operation to perform */
int p1; /* First operand */
int p2; /* Second parameter (often the jump destination) */
char *p3; /* Third parameter */
@ -46,6 +46,18 @@ struct VdbeOp {
};
typedef struct VdbeOp VdbeOp;
/*
** A smaller version of VdbeOp used for the VdbeAddOpList() function because
** it takes up less space.
*/
struct VdbeOpList {
u8 opcode; /* What operation to perform */
signed char p1; /* First operand */
short int p2; /* Second parameter (often the jump destination) */
char *p3; /* Third parameter */
};
typedef struct VdbeOpList VdbeOpList;
/*
** Allowed values of VdbeOp.p3type
*/
@ -75,7 +87,9 @@ typedef struct VdbeOp VdbeOp;
Vdbe *sqliteVdbeCreate(sqlite*);
void sqliteVdbeCreateCallback(Vdbe*, int*);
int sqliteVdbeAddOp(Vdbe*,int,int,int);
int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOp const *aOp);
int sqliteVdbeOp3(Vdbe*,int,int,int,const char *zP3,int);
int sqliteVdbeCode(Vdbe*,...);
int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
void sqliteVdbeChangeP1(Vdbe*, int addr, int P1);
void sqliteVdbeChangeP2(Vdbe*, int addr, int P2);
void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
@ -84,7 +98,7 @@ int sqliteVdbeFindOp(Vdbe*, int, int);
VdbeOp *sqliteVdbeGetOp(Vdbe*, int);
int sqliteVdbeMakeLabel(Vdbe*);
void sqliteVdbeDelete(Vdbe*);
void sqliteVdbeMakeReady(Vdbe*,int,sqlite_callback,void*,int);
void sqliteVdbeMakeReady(Vdbe*,int,int);
int sqliteVdbeExec(Vdbe*);
int sqliteVdbeList(Vdbe*);
int sqliteVdbeFinalize(Vdbe*,char**);

View file

@ -106,47 +106,36 @@ struct Sorter {
#define NBFS 32
/*
** A single level of the stack is an instance of the following
** structure. Except, string values are stored on a separate
** list of of pointers to character. The reason for storing
** strings separately is so that they can be easily passed
** to the callback function.
*/
struct Stack {
int i; /* Integer value */
int n; /* Number of characters in string value, including '\0' */
int flags; /* Some combination of STK_Null, STK_Str, STK_Dyn, etc. */
double r; /* Real value */
char z[NBFS]; /* Space for short strings */
};
typedef struct Stack Stack;
/*
** Memory cells use the same structure as the stack except that space
** for an arbitrary string is added.
** A single level of the stack or a single memory cell
** is an instance of the following structure.
*/
struct Mem {
Stack s; /* All values of the memory cell besides string */
char *z; /* String value for this memory cell */
int i; /* Integer value */
int n; /* Number of characters in string value, including '\0' */
int flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
double r; /* Real value */
char *z; /* String value */
char zShort[NBFS]; /* Space for short strings */
};
typedef struct Mem Mem;
/*
** Allowed values for Stack.flags
** Allowed values for Mem.flags
*/
#define STK_Null 0x0001 /* Value is NULL */
#define STK_Str 0x0002 /* Value is a string */
#define STK_Int 0x0004 /* Value is an integer */
#define STK_Real 0x0008 /* Value is a real number */
#define STK_Dyn 0x0010 /* Need to call sqliteFree() on zStack[] */
#define STK_Static 0x0020 /* zStack[] points to a static string */
#define STK_Ephem 0x0040 /* zStack[] points to an ephemeral string */
#define MEM_Null 0x0001 /* Value is NULL */
#define MEM_Str 0x0002 /* Value is a string */
#define MEM_Int 0x0004 /* Value is an integer */
#define MEM_Real 0x0008 /* Value is a real number */
#define MEM_Dyn 0x0010 /* Need to call sqliteFree() on Mem.z */
#define MEM_Static 0x0020 /* Mem.z points to a static string */
#define MEM_Ephem 0x0040 /* Mem.z points to an ephemeral string */
#define MEM_Short 0x0080 /* Mem.z points to Mem.zShort */
/* The following STK_ value appears only in AggElem.aMem.s.flag fields.
/* The following MEM_ value appears only in AggElem.aMem.s.flag fields.
** It indicates that the corresponding AggElem.aMem.z points to a
** aggregate function context that needs to be finalized.
*/
#define STK_AggCtx 0x0040 /* zStack[] points to an agg function context */
#define MEM_AggCtx 0x0100 /* Mem.z points to an agg function context */
/*
** The "context" argument for a installable function. A pointer to an
@ -159,12 +148,11 @@ typedef struct Mem Mem;
** structure are known.
**
** This structure is defined inside of vdbe.c because it uses substructures
** (Stack) which are only defined there.
** (Mem) which are only defined there.
*/
struct sqlite_func {
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
Stack s; /* Small strings, ints, and double values go here */
char *z; /* Space for holding dynamic string results */
Mem s; /* The return value is stored here */
void *pAgg; /* Aggregate context */
u8 isError; /* Set to true for an error */
u8 isStep; /* Current in the step function */
@ -219,6 +207,19 @@ struct Keylist {
int aKey[1]; /* One or more keys. Extra space allocated as needed */
};
/*
** A Context stores the last insert rowid, the last statement change count,
** and the current statement change count (i.e. changes since last statement).
** Elements of Context structure type make up the ContextStack, which is
** updated by the ContextPush and ContextPop opcodes (used by triggers)
*/
typedef struct Context Context;
struct Context {
int lastRowid; /* Last insert rowid (from db->lastRowid) */
int lsChange; /* Last statement change count (from db->lsChange) */
int csChange; /* Current statement change count (from db->csChange) */
};
/*
** An instance of the virtual machine. This structure contains the complete
** state of the virtual machine.
@ -236,9 +237,9 @@ struct Vdbe {
int nLabel; /* Number of labels used */
int nLabelAlloc; /* Number of slots allocated in aLabel[] */
int *aLabel; /* Space to hold the labels */
int tos; /* Index of top of stack */
Stack *aStack; /* The operand stack, except string values */
char **zStack; /* Text or binary values of the stack */
Mem *aStack; /* The operand stack, except string values */
Mem *pTos; /* Top entry in the operand stack */
char **zArgv; /* Text values used by the callback */
char **azColName; /* Becomes the 4th parameter to callbacks */
int nCursor; /* Number of slots in aCsr[] */
Cursor *aCsr; /* One element of this array for each open cursor */
@ -262,6 +263,8 @@ struct Vdbe {
Keylist *pList; /* A list of ROWIDs */
int keylistStackDepth; /* The size of the "keylist" stack */
Keylist **keylistStack; /* The stack used by opcodes ListPush & ListPop */
int contextStackDepth; /* The size of the "context" stack */
Context *contextStack; /* Stack used by opcodes ContextPush & ContextPop*/
int pc; /* The program counter */
int rc; /* Value to return */
unsigned uniqueCnt; /* Used by OP_MakeRecord when P2!=0 */
@ -271,9 +274,7 @@ struct Vdbe {
int returnStack[100]; /* Return address stack for OP_Gosub & OP_Return */
int returnDepth; /* Next unused element in returnStack[] */
int nResColumn; /* Number of columns in one row of the result set */
char **azResColumn; /* Values for one row of result */
int (*xCallback)(void*,int,char**,char**); /* Callback for SELECT results */
void *pCbArg; /* First argument to xCallback() */
char **azResColumn; /* Values for one row of result */
int popStack; /* Pop the stack this much on entry to VdbeExec() */
char *zErrMsg; /* Error message written here */
u8 explain; /* True if EXPLAIN present on SQL command */
@ -287,16 +288,6 @@ struct Vdbe {
#define VDBE_MAGIC_HALT 0x519c2973 /* VDBE has completed execution */
#define VDBE_MAGIC_DEAD 0xb606c3c8 /* The VDBE has been deallocated */
/*
** Here is a macro to handle the common case of popping the stack
** once. This macro only works from within the sqliteVdbeExec()
** function.
*/
#define POPSTACK \
assert(p->tos>=0); \
if( aStack[p->tos].flags & STK_Dyn ) sqliteFree(zStack[p->tos]); \
p->tos--;
/*
** Function prototypes
*/

View file

@ -73,6 +73,7 @@ void sqliteVdbeTrace(Vdbe *p, FILE *trace){
*/
int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){
int i;
VdbeOp *pOp;
i = p->nOp;
p->nOp++;
@ -89,20 +90,50 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2){
p->aOp = aNew;
memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));
}
p->aOp[i].opcode = op;
p->aOp[i].p1 = p1;
pOp = &p->aOp[i];
pOp->opcode = op;
pOp->p1 = p1;
if( p2<0 && (-1-p2)<p->nLabel && p->aLabel[-1-p2]>=0 ){
p2 = p->aLabel[-1-p2];
}
p->aOp[i].p2 = p2;
p->aOp[i].p3 = 0;
p->aOp[i].p3type = P3_NOTUSED;
pOp->p2 = p2;
pOp->p3 = 0;
pOp->p3type = P3_NOTUSED;
#ifndef NDEBUG
if( sqlite_vdbe_addop_trace ) sqliteVdbePrintOp(0, i, &p->aOp[i]);
#endif
return i;
}
/*
** Add an opcode that includes the p3 value.
*/
int sqliteVdbeOp3(Vdbe *p, int op, int p1, int p2, const char *zP3, int p3type){
int addr = sqliteVdbeAddOp(p, op, p1, p2);
sqliteVdbeChangeP3(p, addr, zP3, p3type);
return addr;
}
/*
** Add multiple opcodes. The list is terminated by an opcode of 0.
*/
int sqliteVdbeCode(Vdbe *p, ...){
int addr;
va_list ap;
int opcode, p1, p2;
va_start(ap, p);
addr = p->nOp;
while( (opcode = va_arg(ap,int))!=0 ){
p1 = va_arg(ap,int);
p2 = va_arg(ap,int);
sqliteVdbeAddOp(p, opcode, p1, p2);
}
va_end(ap);
return addr;
}
/*
** Create a new symbolic label for an instruction that has yet to be
** coded. The symbolic label is really just a negative number. The
@ -167,7 +198,7 @@ int sqliteVdbeCurrentAddr(Vdbe *p){
** Add a whole list of operations to the operation stack. Return the
** address of the first operation added.
*/
int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){
int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
int addr;
assert( p->magic==VDBE_MAGIC_INIT );
if( p->nOp + nOp >= p->nOpAlloc ){
@ -185,11 +216,15 @@ int sqliteVdbeAddOpList(Vdbe *p, int nOp, VdbeOp const *aOp){
addr = p->nOp;
if( nOp>0 ){
int i;
for(i=0; i<nOp; i++){
int p2 = aOp[i].p2;
p->aOp[i+addr] = aOp[i];
if( p2<0 ) p->aOp[i+addr].p2 = addr + ADDR(p2);
p->aOp[i+addr].p3type = aOp[i].p3 ? P3_STATIC : P3_NOTUSED;
VdbeOpList const *pIn = aOp;
for(i=0; i<nOp; i++, pIn++){
int p2 = pIn->p2;
VdbeOp *pOut = &p->aOp[i+addr];
pOut->opcode = pIn->opcode;
pOut->p1 = pIn->p1;
pOut->p2 = p2<0 ? addr + ADDR(p2) : p2;
pOut->p3 = pIn->p3;
pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED;
#ifndef NDEBUG
if( sqlite_vdbe_addop_trace ){
sqliteVdbePrintOp(0, i+addr, &p->aOp[i+addr]);
@ -280,7 +315,11 @@ void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
void sqliteVdbeDequoteP3(Vdbe *p, int addr){
Op *pOp;
assert( p->magic==VDBE_MAGIC_INIT );
if( p->aOp==0 || addr<0 || addr>=p->nOp ) return;
if( p->aOp==0 ) return;
if( addr<0 || addr>=p->nOp ){
addr = p->nOp - 1;
if( addr<0 ) return;
}
pOp = &p->aOp[addr];
if( pOp->p3==0 || pOp->p3[0]==0 ) return;
if( pOp->p3type==P3_POINTER ) return;
@ -371,48 +410,48 @@ VdbeOp *sqliteVdbeGetOp(Vdbe *p, int addr){
*/
char *sqlite_set_result_string(sqlite_func *p, const char *zResult, int n){
assert( !p->isStep );
if( p->s.flags & STK_Dyn ){
sqliteFree(p->z);
if( p->s.flags & MEM_Dyn ){
sqliteFree(p->s.z);
}
if( zResult==0 ){
p->s.flags = STK_Null;
p->s.flags = MEM_Null;
n = 0;
p->z = 0;
p->s.z = 0;
p->s.n = 0;
}else{
if( n<0 ) n = strlen(zResult);
if( n<NBFS-1 ){
memcpy(p->s.z, zResult, n);
p->s.z[n] = 0;
p->s.flags = STK_Str;
p->z = p->s.z;
memcpy(p->s.zShort, zResult, n);
p->s.zShort[n] = 0;
p->s.flags = MEM_Str | MEM_Short;
p->s.z = p->s.zShort;
}else{
p->z = sqliteMallocRaw( n+1 );
if( p->z ){
memcpy(p->z, zResult, n);
p->z[n] = 0;
p->s.z = sqliteMallocRaw( n+1 );
if( p->s.z ){
memcpy(p->s.z, zResult, n);
p->s.z[n] = 0;
}
p->s.flags = STK_Str | STK_Dyn;
p->s.flags = MEM_Str | MEM_Dyn;
}
p->s.n = n+1;
}
return p->z;
return p->s.z;
}
void sqlite_set_result_int(sqlite_func *p, int iResult){
assert( !p->isStep );
if( p->s.flags & STK_Dyn ){
sqliteFree(p->z);
if( p->s.flags & MEM_Dyn ){
sqliteFree(p->s.z);
}
p->s.i = iResult;
p->s.flags = STK_Int;
p->s.flags = MEM_Int;
}
void sqlite_set_result_double(sqlite_func *p, double rResult){
assert( !p->isStep );
if( p->s.flags & STK_Dyn ){
sqliteFree(p->z);
if( p->s.flags & MEM_Dyn ){
sqliteFree(p->s.z);
}
p->s.r = rResult;
p->s.flags = STK_Real;
p->s.flags = MEM_Real;
}
void sqlite_set_result_error(sqlite_func *p, const char *zMsg, int n){
assert( !p->isStep );
@ -442,7 +481,8 @@ void *sqlite_aggregate_context(sqlite_func *p, int nByte){
assert( p && p->pFunc && p->pFunc->xStep );
if( p->pAgg==0 ){
if( nByte<=NBFS ){
p->pAgg = (void*)p->z;
p->pAgg = (void*)p->s.z;
memset(p->pAgg, 0, nByte);
}else{
p->pAgg = sqliteMalloc( nByte );
}
@ -495,6 +535,7 @@ int sqliteVdbeList(
){
sqlite *db = p->db;
int i;
int rc = SQLITE_OK;
static char *azColumnNames[] = {
"addr", "opcode", "p1", "p2", "p3",
"int", "text", "int", "int", "text",
@ -504,48 +545,39 @@ int sqliteVdbeList(
assert( p->popStack==0 );
assert( p->explain );
p->azColName = azColumnNames;
p->azResColumn = p->zStack;
for(i=0; i<5; i++) p->zStack[i] = p->aStack[i].z;
p->rc = SQLITE_OK;
for(i=p->pc; p->rc==SQLITE_OK && i<p->nOp; i++){
if( db->flags & SQLITE_Interrupt ){
db->flags &= ~SQLITE_Interrupt;
if( db->magic!=SQLITE_MAGIC_BUSY ){
p->rc = SQLITE_MISUSE;
}else{
p->rc = SQLITE_INTERRUPT;
}
sqliteSetString(&p->zErrMsg, sqlite_error_string(p->rc), (char*)0);
break;
}
sprintf(p->zStack[0],"%d",i);
sprintf(p->zStack[2],"%d", p->aOp[i].p1);
sprintf(p->zStack[3],"%d", p->aOp[i].p2);
if( p->aOp[i].p3type==P3_POINTER ){
sprintf(p->aStack[4].z, "ptr(%#lx)", (long)p->aOp[i].p3);
p->zStack[4] = p->aStack[4].z;
p->azResColumn = p->zArgv;
for(i=0; i<5; i++) p->zArgv[i] = p->aStack[i].zShort;
i = p->pc;
if( i>=p->nOp ){
p->rc = SQLITE_OK;
rc = SQLITE_DONE;
}else if( db->flags & SQLITE_Interrupt ){
db->flags &= ~SQLITE_Interrupt;
if( db->magic!=SQLITE_MAGIC_BUSY ){
p->rc = SQLITE_MISUSE;
}else{
p->zStack[4] = p->aOp[i].p3;
p->rc = SQLITE_INTERRUPT;
}
p->zStack[1] = sqliteOpcodeNames[p->aOp[i].opcode];
if( p->xCallback==0 ){
p->pc = i+1;
p->azResColumn = p->zStack;
p->nResColumn = 5;
return SQLITE_ROW;
}
if( sqliteSafetyOff(db) ){
p->rc = SQLITE_MISUSE;
break;
}
if( p->xCallback(p->pCbArg, 5, p->zStack, p->azColName) ){
p->rc = SQLITE_ABORT;
}
if( sqliteSafetyOn(db) ){
p->rc = SQLITE_MISUSE;
rc = SQLITE_ERROR;
sqliteSetString(&p->zErrMsg, sqlite_error_string(p->rc), (char*)0);
}else{
sprintf(p->zArgv[0],"%d",i);
sprintf(p->zArgv[2],"%d", p->aOp[i].p1);
sprintf(p->zArgv[3],"%d", p->aOp[i].p2);
if( p->aOp[i].p3type==P3_POINTER ){
sprintf(p->aStack[4].zShort, "ptr(%#lx)", (long)p->aOp[i].p3);
p->zArgv[4] = p->aStack[4].zShort;
}else{
p->zArgv[4] = p->aOp[i].p3;
}
p->zArgv[1] = sqliteOpcodeNames[p->aOp[i].opcode];
p->pc = i+1;
p->azResColumn = p->zArgv;
p->nResColumn = 5;
p->rc = SQLITE_OK;
rc = SQLITE_ROW;
}
return p->rc==SQLITE_OK ? SQLITE_DONE : SQLITE_ERROR;
return rc;
}
/*
@ -553,20 +585,10 @@ int sqliteVdbeList(
** as allocating stack space and initializing the program counter.
** After the VDBE has be prepped, it can be executed by one or more
** calls to sqliteVdbeExec().
**
** The behavior of sqliteVdbeExec() is influenced by the parameters to
** this routine. If xCallback is NULL, then sqliteVdbeExec() will return
** with SQLITE_ROW whenever there is a row of the result set ready
** to be delivered. p->azResColumn will point to the row and
** p->nResColumn gives the number of columns in the row. If xCallback
** is not NULL, then the xCallback() routine is invoked to process each
** row in the result set.
*/
void sqliteVdbeMakeReady(
Vdbe *p, /* The VDBE */
int nVar, /* Number of '?' see in the SQL statement */
sqlite_callback xCallback, /* Result callback */
void *pCallbackArg, /* 1st argument to xCallback() */
int isExplain /* True if the EXPLAIN keywords is present */
){
int n;
@ -592,11 +614,11 @@ void sqliteVdbeMakeReady(
assert( nVar>=0 );
n = isExplain ? 10 : p->nOp;
p->aStack = sqliteMalloc(
n*(sizeof(p->aStack[0]) + 2*sizeof(char*)) /* aStack and zStack */
+ p->nVar*(sizeof(char*)+sizeof(int)+1) /* azVar, anVar, abVar */
n*(sizeof(p->aStack[0]) + 2*sizeof(char*)) /* aStack and zArgv */
+ p->nVar*(sizeof(char*)+sizeof(int)+1) /* azVar, anVar, abVar */
);
p->zStack = (char**)&p->aStack[n];
p->azColName = (char**)&p->zStack[n];
p->zArgv = (char**)&p->aStack[n];
p->azColName = (char**)&p->zArgv[n];
p->azVar = (char**)&p->azColName[n];
p->anVar = (int*)&p->azVar[p->nVar];
p->abVar = (u8*)&p->anVar[p->nVar];
@ -609,15 +631,13 @@ void sqliteVdbeMakeReady(
p->trace = stdout;
}
#endif
p->tos = -1;
p->pTos = &p->aStack[-1];
p->pc = 0;
p->rc = SQLITE_OK;
p->uniqueCnt = 0;
p->returnDepth = 0;
p->errorAction = OE_Abort;
p->undoTransOnError = 0;
p->xCallback = xCallback;
p->pCbArg = pCallbackArg;
p->popStack = 0;
p->explain |= isExplain;
p->magic = VDBE_MAGIC_RUN;
@ -646,25 +666,6 @@ void sqliteVdbeSorterReset(Vdbe *p){
}
}
/*
** Pop the stack N times. Free any memory associated with the
** popped stack elements.
*/
void sqliteVdbePopStack(Vdbe *p, int N){
assert( N>=0 );
if( p->zStack==0 ) return;
assert( p->aStack || sqlite_malloc_failed );
if( p->aStack==0 ) return;
while( N-- > 0 ){
if( p->aStack[p->tos].flags & STK_Dyn ){
sqliteFree(p->zStack[p->tos]);
}
p->aStack[p->tos].flags = 0;
p->zStack[p->tos] = 0;
p->tos--;
}
}
/*
** Reset an Agg structure. Delete all its contents.
**
@ -682,20 +683,22 @@ void sqliteVdbeAggReset(Agg *pAgg){
assert( pAgg->apFunc!=0 );
for(i=0; i<pAgg->nMem; i++){
Mem *pMem = &pElem->aMem[i];
if( pAgg->apFunc[i] && (pMem->s.flags & STK_AggCtx)!=0 ){
if( pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
sqlite_func ctx;
ctx.pFunc = pAgg->apFunc[i];
ctx.s.flags = STK_Null;
ctx.z = 0;
ctx.s.flags = MEM_Null;
ctx.pAgg = pMem->z;
ctx.cnt = pMem->s.i;
ctx.cnt = pMem->i;
ctx.isStep = 0;
ctx.isError = 0;
(*pAgg->apFunc[i]->xFinalize)(&ctx);
if( pMem->z!=0 && pMem->z!=pMem->s.z ){
if( pMem->z!=0 && pMem->z!=pMem->zShort ){
sqliteFree(pMem->z);
}
}else if( pMem->s.flags & STK_Dyn ){
if( ctx.s.flags & MEM_Dyn ){
sqliteFree(ctx.s.z);
}
}else if( pMem->flags & MEM_Dyn ){
sqliteFree(pMem->z);
}
}
@ -757,11 +760,20 @@ static void closeAllCursors(Vdbe *p){
*/
static void Cleanup(Vdbe *p){
int i;
sqliteVdbePopStack(p, p->tos+1);
if( p->aStack ){
Mem *pTos = p->pTos;
while( pTos>=p->aStack ){
if( pTos->flags & MEM_Dyn ){
sqliteFree(pTos->z);
}
pTos--;
}
p->pTos = pTos;
}
closeAllCursors(p);
if( p->aMem ){
for(i=0; i<p->nMem; i++){
if( p->aMem[i].s.flags & STK_Dyn ){
if( p->aMem[i].flags & MEM_Dyn ){
sqliteFree(p->aMem[i].z);
}
}
@ -806,6 +818,8 @@ static void Cleanup(Vdbe *p){
p->keylistStackDepth = 0;
p->keylistStack = 0;
}
sqliteFree(p->contextStack);
p->contextStack = 0;
sqliteFree(p->zErrMsg);
p->zErrMsg = 0;
}
@ -832,6 +846,8 @@ int sqliteVdbeReset(Vdbe *p, char **pzErrMsg){
sqliteFree(p->zErrMsg);
}
p->zErrMsg = 0;
}else if( p->rc ){
sqliteSetString(pzErrMsg, sqlite_error_string(p->rc), (char*)0);
}
Cleanup(p);
if( p->rc!=SQLITE_OK ){
@ -870,7 +886,7 @@ int sqliteVdbeReset(Vdbe *p, char **pzErrMsg){
db->aDb[i].inTrans = 1;
}
}
assert( p->tos<p->pc || sqlite_malloc_failed==1 );
assert( p->pTos<&p->aStack[p->pc] || sqlite_malloc_failed==1 );
#ifdef VDBE_PROFILE
{
FILE *out = fopen("vdbe_profile.out", "a");
@ -915,6 +931,9 @@ int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){
if( db->want_to_close && db->pVdbe==0 ){
sqlite_close(db);
}
if( rc==SQLITE_SCHEMA ){
sqliteResetInternalSchema(db, 0);
}
return rc;
}

View file

@ -380,11 +380,8 @@ WhereInfo *sqliteWhereBegin(
memset(aExpr, 0, sizeof(aExpr));
nExpr = exprSplit(ARRAYSIZE(aExpr), aExpr, pWhere);
if( nExpr==ARRAYSIZE(aExpr) ){
char zBuf[50];
sprintf(zBuf, "%d", (int)ARRAYSIZE(aExpr)-1);
sqliteSetString(&pParse->zErrMsg, "WHERE clause too complex - no more "
"than ", zBuf, " terms allowed", (char*)0);
pParse->nErr++;
sqliteErrorMsg(pParse, "WHERE clause too complex - no more "
"than %d terms allowed", (int)ARRAYSIZE(aExpr)-1);
return 0;
}
@ -672,18 +669,17 @@ WhereInfo *sqliteWhereBegin(
*/
for(i=0; i<pTabList->nSrc; i++){
Table *pTab;
Index *pIx;
pTab = pTabList->a[i].pTab;
if( pTab->isTransient || pTab->pSelect ) continue;
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
sqliteVdbeOp3(v, OP_OpenRead, pTabList->a[i].iCursor, pTab->tnum,
pTab->zName, P3_STATIC);
sqliteCodeVerifySchema(pParse, pTab->iDb);
if( pWInfo->a[i].pIdx!=0 ){
sqliteVdbeAddOp(v, OP_Integer, pWInfo->a[i].pIdx->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead,
pWInfo->a[i].iCur, pWInfo->a[i].pIdx->tnum);
sqliteVdbeChangeP3(v, -1, pWInfo->a[i].pIdx->zName, P3_STATIC);
if( (pIx = pWInfo->a[i].pIdx)!=0 ){
sqliteVdbeAddOp(v, OP_Integer, pIx->iDb, 0);
sqliteVdbeOp3(v, OP_OpenRead, pWInfo->a[i].iCur, pIx->tnum, pIx->zName,0);
}
}
@ -855,10 +851,8 @@ WhereInfo *sqliteWhereBegin(
}else{
sqliteExprCode(pParse, aExpr[k].p->pLeft);
}
sqliteVdbeAddOp(v, OP_IsNumeric, 1, brk);
if( aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT ){
sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
}
sqliteVdbeAddOp(v, OP_ForceInt,
aExpr[k].p->op==TK_LT || aExpr[k].p->op==TK_GT, brk);
sqliteVdbeAddOp(v, OP_MoveTo, iCur, brk);
aExpr[k].p = 0;
}else{