mirror of
https://github.com/php/php-src.git
synced 2025-08-20 01:14:28 +02:00
Update bundled libsqlite3 to version 3.2.7
This commit is contained in:
parent
74c7eb7723
commit
94d1e56360
40 changed files with 4884 additions and 4207 deletions
|
@ -1 +1 @@
|
||||||
3.2.5
|
3.2.7
|
||||||
|
|
|
@ -88,8 +88,8 @@ static void analyzeOneTable(
|
||||||
int addr; /* The address of an instruction */
|
int addr; /* The address of an instruction */
|
||||||
|
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
if( pTab==0 || pTab->pIndex==0 || pTab->pIndex->pNext==0 ){
|
if( pTab==0 || pTab->pIndex==0 ){
|
||||||
/* Do no analysis for tables with fewer than 2 indices */
|
/* Do no analysis for tables that have no indices */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,13 +127,11 @@ static void analyzeOneTable(
|
||||||
** Cells iMem through iMem+nCol are initialized to 0. The others
|
** Cells iMem through iMem+nCol are initialized to 0. The others
|
||||||
** are initialized to NULL.
|
** are initialized to NULL.
|
||||||
*/
|
*/
|
||||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
|
||||||
for(i=0; i<=nCol; i++){
|
for(i=0; i<=nCol; i++){
|
||||||
sqlite3VdbeAddOp(v, OP_MemStore, iMem+i, i==nCol);
|
sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem+i);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
|
|
||||||
for(i=0; i<nCol; i++){
|
for(i=0; i<nCol; i++){
|
||||||
sqlite3VdbeAddOp(v, OP_MemStore, iMem+nCol+i+1, i==nCol-1);
|
sqlite3VdbeAddOp(v, OP_MemNull, iMem+nCol+i+1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do the analysis.
|
/* Do the analysis.
|
||||||
|
@ -198,7 +196,7 @@ static void analyzeOneTable(
|
||||||
}
|
}
|
||||||
sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "ttt", 0);
|
sqlite3VdbeOp3(v, OP_MakeRecord, 3, 0, "ttt", 0);
|
||||||
sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0);
|
sqlite3VdbeAddOp(v, OP_Insert, iStatCur, 0);
|
||||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +331,7 @@ static int analysisLoader(void *pData, int argc, char **argv, char **azNotUsed){
|
||||||
const char *z;
|
const char *z;
|
||||||
|
|
||||||
assert( argc==2 );
|
assert( argc==2 );
|
||||||
if( argv[0]==0 || argv[1]==0 ){
|
if( argv==0 || argv[0]==0 || argv[1]==0 ){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase);
|
pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase);
|
||||||
|
|
|
@ -494,7 +494,7 @@ static int ptrmapPut(Btree *pBt, Pgno key, u8 eType, Pgno parent){
|
||||||
|
|
||||||
assert( pBt->autoVacuum );
|
assert( pBt->autoVacuum );
|
||||||
if( key==0 ){
|
if( key==0 ){
|
||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
|
iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);
|
||||||
rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
|
rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);
|
||||||
|
@ -540,7 +540,7 @@ static int ptrmapGet(Btree *pBt, Pgno key, u8 *pEType, Pgno *pPgno){
|
||||||
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
|
if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);
|
||||||
|
|
||||||
sqlite3pager_unref(pPtrmap);
|
sqlite3pager_unref(pPtrmap);
|
||||||
if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT;
|
if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1030,7 +1030,7 @@ static int initPage(
|
||||||
assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );
|
assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );
|
||||||
if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
|
if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){
|
||||||
/* The parent page should never change unless the file is corrupt */
|
/* The parent page should never change unless the file is corrupt */
|
||||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
if( pPage->isInit ) return SQLITE_OK;
|
if( pPage->isInit ) return SQLITE_OK;
|
||||||
if( pPage->pParent==0 && pParent!=0 ){
|
if( pPage->pParent==0 && pParent!=0 ){
|
||||||
|
@ -1048,11 +1048,11 @@ static int initPage(
|
||||||
pPage->nCell = get2byte(&data[hdr+3]);
|
pPage->nCell = get2byte(&data[hdr+3]);
|
||||||
if( pPage->nCell>MX_CELL(pBt) ){
|
if( pPage->nCell>MX_CELL(pBt) ){
|
||||||
/* To many cells for a single page. The page must be corrupt */
|
/* To many cells for a single page. The page must be corrupt */
|
||||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){
|
if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){
|
||||||
/* All pages must have at least one cell, except for root pages */
|
/* All pages must have at least one cell, except for root pages */
|
||||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute the total free space on the page */
|
/* Compute the total free space on the page */
|
||||||
|
@ -1062,13 +1062,13 @@ static int initPage(
|
||||||
int next, size;
|
int next, size;
|
||||||
if( pc>usableSize-4 ){
|
if( pc>usableSize-4 ){
|
||||||
/* Free block is off the page */
|
/* Free block is off the page */
|
||||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
next = get2byte(&data[pc]);
|
next = get2byte(&data[pc]);
|
||||||
size = get2byte(&data[pc+2]);
|
size = get2byte(&data[pc+2]);
|
||||||
if( next>0 && next<=pc+size+3 ){
|
if( next>0 && next<=pc+size+3 ){
|
||||||
/* Free blocks must be in accending order */
|
/* Free blocks must be in accending order */
|
||||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
nFree += size;
|
nFree += size;
|
||||||
pc = next;
|
pc = next;
|
||||||
|
@ -1076,7 +1076,7 @@ static int initPage(
|
||||||
pPage->nFree = nFree;
|
pPage->nFree = nFree;
|
||||||
if( nFree>=usableSize ){
|
if( nFree>=usableSize ){
|
||||||
/* Free space cannot exceed total page size */
|
/* Free space cannot exceed total page size */
|
||||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
pPage->isInit = 1;
|
pPage->isInit = 1;
|
||||||
|
@ -1146,7 +1146,7 @@ static int getAndInitPage(
|
||||||
){
|
){
|
||||||
int rc;
|
int rc;
|
||||||
if( pgno==0 ){
|
if( pgno==0 ){
|
||||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
rc = getPage(pBt, pgno, ppPage);
|
rc = getPage(pBt, pgno, ppPage);
|
||||||
if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
|
if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){
|
||||||
|
@ -1714,7 +1714,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
||||||
if( eType==PTRMAP_OVERFLOW2 ){
|
if( eType==PTRMAP_OVERFLOW2 ){
|
||||||
/* The pointer is always the first 4 bytes of the page in this case. */
|
/* The pointer is always the first 4 bytes of the page in this case. */
|
||||||
if( get4byte(pPage->aData)!=iFrom ){
|
if( get4byte(pPage->aData)!=iFrom ){
|
||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
put4byte(pPage->aData, iTo);
|
put4byte(pPage->aData, iTo);
|
||||||
}else{
|
}else{
|
||||||
|
@ -1747,7 +1747,7 @@ static int modifyPagePointer(MemPage *pPage, Pgno iFrom, Pgno iTo, u8 eType){
|
||||||
if( i==nCell ){
|
if( i==nCell ){
|
||||||
if( eType!=PTRMAP_BTREE ||
|
if( eType!=PTRMAP_BTREE ||
|
||||||
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
|
get4byte(&pPage->aData[pPage->hdrOffset+8])!=iFrom ){
|
||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
|
put4byte(&pPage->aData[pPage->hdrOffset+8], iTo);
|
||||||
}
|
}
|
||||||
|
@ -1860,7 +1860,7 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
|
||||||
|
|
||||||
assert( pBt->autoVacuum );
|
assert( pBt->autoVacuum );
|
||||||
if( PTRMAP_ISPAGE(pgsz, sqlite3pager_pagecount(pPager)) ){
|
if( PTRMAP_ISPAGE(pgsz, sqlite3pager_pagecount(pPager)) ){
|
||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out how many free-pages are in the database. If there are no
|
/* Figure out how many free-pages are in the database. If there are no
|
||||||
|
@ -1875,7 +1875,7 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
|
||||||
origSize = sqlite3pager_pagecount(pPager);
|
origSize = sqlite3pager_pagecount(pPager);
|
||||||
nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5);
|
nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pgsz, origSize)+pgsz/5)/(pgsz/5);
|
||||||
finSize = origSize - nFreeList - nPtrMap;
|
finSize = origSize - nFreeList - nPtrMap;
|
||||||
if( origSize>PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
|
if( origSize>=PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
|
||||||
finSize--;
|
finSize--;
|
||||||
if( PTRMAP_ISPAGE(pBt->usableSize, finSize) ){
|
if( PTRMAP_ISPAGE(pBt->usableSize, finSize) ){
|
||||||
finSize--;
|
finSize--;
|
||||||
|
@ -1898,7 +1898,7 @@ static int autoVacuumCommit(Btree *pBt, Pgno *nTrunc){
|
||||||
rc = ptrmapGet(pBt, iDbPage, &eType, &iPtrPage);
|
rc = ptrmapGet(pBt, iDbPage, &eType, &iPtrPage);
|
||||||
if( rc!=SQLITE_OK ) goto autovacuum_out;
|
if( rc!=SQLITE_OK ) goto autovacuum_out;
|
||||||
if( eType==PTRMAP_ROOTPAGE ){
|
if( eType==PTRMAP_ROOTPAGE ){
|
||||||
rc = SQLITE_CORRUPT;
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
goto autovacuum_out;
|
goto autovacuum_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2414,7 +2414,7 @@ static int getPayload(
|
||||||
}
|
}
|
||||||
|
|
||||||
if( amt>0 ){
|
if( amt>0 ){
|
||||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
@ -2432,7 +2432,7 @@ int sqlite3BtreeKey(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
|
||||||
assert( pCur->isValid );
|
assert( pCur->isValid );
|
||||||
assert( pCur->pPage!=0 );
|
assert( pCur->pPage!=0 );
|
||||||
if( pCur->pPage->intKey ){
|
if( pCur->pPage->intKey ){
|
||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
assert( pCur->pPage->intKey==0 );
|
assert( pCur->pPage->intKey==0 );
|
||||||
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
assert( pCur->idx>=0 && pCur->idx<pCur->pPage->nCell );
|
||||||
|
@ -2481,13 +2481,11 @@ static const unsigned char *fetchPayload(
|
||||||
){
|
){
|
||||||
unsigned char *aPayload;
|
unsigned char *aPayload;
|
||||||
MemPage *pPage;
|
MemPage *pPage;
|
||||||
Btree *pBt;
|
|
||||||
u32 nKey;
|
u32 nKey;
|
||||||
int nLocal;
|
int nLocal;
|
||||||
|
|
||||||
assert( pCur!=0 && pCur->pPage!=0 );
|
assert( pCur!=0 && pCur->pPage!=0 );
|
||||||
assert( pCur->isValid );
|
assert( pCur->isValid );
|
||||||
pBt = pCur->pBt;
|
|
||||||
pPage = pCur->pPage;
|
pPage = pCur->pPage;
|
||||||
pageIntegrity(pPage);
|
pageIntegrity(pPage);
|
||||||
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
assert( pCur->idx>=0 && pCur->idx<pPage->nCell );
|
||||||
|
@ -2554,7 +2552,7 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
|
||||||
pCur->idx = 0;
|
pCur->idx = 0;
|
||||||
pCur->info.nSize = 0;
|
pCur->info.nSize = 0;
|
||||||
if( pNewPage->nCell<1 ){
|
if( pNewPage->nCell<1 ){
|
||||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
@ -2585,7 +2583,6 @@ static int isRootPage(MemPage *pPage){
|
||||||
** the largest cell index.
|
** the largest cell index.
|
||||||
*/
|
*/
|
||||||
static void moveToParent(BtCursor *pCur){
|
static void moveToParent(BtCursor *pCur){
|
||||||
Pgno oldPgno;
|
|
||||||
MemPage *pParent;
|
MemPage *pParent;
|
||||||
MemPage *pPage;
|
MemPage *pPage;
|
||||||
int idxParent;
|
int idxParent;
|
||||||
|
@ -2600,7 +2597,6 @@ static void moveToParent(BtCursor *pCur){
|
||||||
pageIntegrity(pParent);
|
pageIntegrity(pParent);
|
||||||
idxParent = pPage->idxParent;
|
idxParent = pPage->idxParent;
|
||||||
sqlite3pager_ref(pParent->aData);
|
sqlite3pager_ref(pParent->aData);
|
||||||
oldPgno = pPage->pgno;
|
|
||||||
releasePage(pPage);
|
releasePage(pPage);
|
||||||
pCur->pPage = pParent;
|
pCur->pPage = pParent;
|
||||||
pCur->info.nSize = 0;
|
pCur->info.nSize = 0;
|
||||||
|
@ -2765,7 +2761,7 @@ int sqlite3BtreeMoveto(BtCursor *pCur, const void *pKey, i64 nKey, int *pRes){
|
||||||
lwr = 0;
|
lwr = 0;
|
||||||
upr = pPage->nCell-1;
|
upr = pPage->nCell-1;
|
||||||
if( !pPage->intKey && pKey==0 ){
|
if( !pPage->intKey && pKey==0 ){
|
||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
pageIntegrity(pPage);
|
pageIntegrity(pPage);
|
||||||
while( lwr<=upr ){
|
while( lwr<=upr ){
|
||||||
|
@ -3050,7 +3046,7 @@ static int allocatePage(
|
||||||
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
|
TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
|
||||||
}else if( k>pBt->usableSize/4 - 8 ){
|
}else if( k>pBt->usableSize/4 - 8 ){
|
||||||
/* Value of k is out of range. Database corruption */
|
/* Value of k is out of range. Database corruption */
|
||||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
return SQLITE_CORRUPT_BKPT;
|
||||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||||
}else if( searchList && nearby==iTrunk ){
|
}else if( searchList && nearby==iTrunk ){
|
||||||
/* The list is being searched and this trunk page is the page
|
/* The list is being searched and this trunk page is the page
|
||||||
|
@ -3125,7 +3121,7 @@ static int allocatePage(
|
||||||
*pPgno = iPage;
|
*pPgno = iPage;
|
||||||
if( *pPgno>sqlite3pager_pagecount(pBt->pPager) ){
|
if( *pPgno>sqlite3pager_pagecount(pBt->pPager) ){
|
||||||
/* Free page off the end of the file */
|
/* Free page off the end of the file */
|
||||||
return SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
|
TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
|
||||||
": %d more free pages\n",
|
": %d more free pages\n",
|
||||||
|
@ -3266,7 +3262,7 @@ static int clearCell(MemPage *pPage, unsigned char *pCell){
|
||||||
while( ovflPgno!=0 ){
|
while( ovflPgno!=0 ){
|
||||||
MemPage *pOvfl;
|
MemPage *pOvfl;
|
||||||
if( ovflPgno>sqlite3pager_pagecount(pBt->pPager) ){
|
if( ovflPgno>sqlite3pager_pagecount(pBt->pPager) ){
|
||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
rc = getPage(pBt, ovflPgno, &pOvfl);
|
rc = getPage(pBt, ovflPgno, &pOvfl);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
|
@ -4672,7 +4668,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){
|
||||||
rc = sqlite3BtreeNext(&leafCur, ¬Used);
|
rc = sqlite3BtreeNext(&leafCur, ¬Used);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
if( rc!=SQLITE_NOMEM ){
|
if( rc!=SQLITE_NOMEM ){
|
||||||
rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
|
@ -4858,7 +4854,7 @@ static int clearDatabasePage(
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( pgno>sqlite3pager_pagecount(pBt->pPager) ){
|
if( pgno>sqlite3pager_pagecount(pBt->pPager) ){
|
||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = getAndInitPage(pBt, pgno, &pPage, pParent);
|
rc = getAndInitPage(pBt, pgno, &pPage, pParent);
|
||||||
|
@ -5480,7 +5476,7 @@ static int checkTreePage(
|
||||||
u8 *data;
|
u8 *data;
|
||||||
BtCursor cur;
|
BtCursor cur;
|
||||||
Btree *pBt;
|
Btree *pBt;
|
||||||
int maxLocal, usableSize;
|
int usableSize;
|
||||||
char zContext[100];
|
char zContext[100];
|
||||||
char *hit;
|
char *hit;
|
||||||
|
|
||||||
|
@ -5497,7 +5493,6 @@ static int checkTreePage(
|
||||||
"unable to get the page. error code=%d", rc);
|
"unable to get the page. error code=%d", rc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
maxLocal = pPage->leafData ? pBt->maxLeaf : pBt->maxLocal;
|
|
||||||
if( (rc = initPage(pPage, pParent))!=0 ){
|
if( (rc = initPage(pPage, pParent))!=0 ){
|
||||||
checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc);
|
checkAppendMsg(pCheck, zContext, "initPage() returns error code %d", rc);
|
||||||
releasePage(pPage);
|
releasePage(pPage);
|
||||||
|
@ -5744,7 +5739,7 @@ const char *sqlite3BtreeGetJournalname(Btree *pBt){
|
||||||
*/
|
*/
|
||||||
int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
|
int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
Pgno i, nPage, nToPage;
|
Pgno i, nPage, nToPage, iSkip;
|
||||||
|
|
||||||
if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){
|
if( pBtTo->inTrans!=TRANS_WRITE || pBtFrom->inTrans!=TRANS_WRITE ){
|
||||||
return SQLITE_ERROR;
|
return SQLITE_ERROR;
|
||||||
|
@ -5752,8 +5747,10 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
|
||||||
if( pBtTo->pCursor ) return SQLITE_BUSY;
|
if( pBtTo->pCursor ) return SQLITE_BUSY;
|
||||||
nToPage = sqlite3pager_pagecount(pBtTo->pPager);
|
nToPage = sqlite3pager_pagecount(pBtTo->pPager);
|
||||||
nPage = sqlite3pager_pagecount(pBtFrom->pPager);
|
nPage = sqlite3pager_pagecount(pBtFrom->pPager);
|
||||||
|
iSkip = PENDING_BYTE_PAGE(pBtTo);
|
||||||
for(i=1; rc==SQLITE_OK && i<=nPage; i++){
|
for(i=1; rc==SQLITE_OK && i<=nPage; i++){
|
||||||
void *pPage;
|
void *pPage;
|
||||||
|
if( i==iSkip ) continue;
|
||||||
rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage);
|
rc = sqlite3pager_get(pBtFrom->pPager, i, &pPage);
|
||||||
if( rc ) break;
|
if( rc ) break;
|
||||||
rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage);
|
rc = sqlite3pager_overwrite(pBtTo->pPager, i, pPage);
|
||||||
|
@ -5762,6 +5759,7 @@ int sqlite3BtreeCopyFile(Btree *pBtTo, Btree *pBtFrom){
|
||||||
}
|
}
|
||||||
for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
|
for(i=nPage+1; rc==SQLITE_OK && i<=nToPage; i++){
|
||||||
void *pPage;
|
void *pPage;
|
||||||
|
if( i==iSkip ) continue;
|
||||||
rc = sqlite3pager_get(pBtTo->pPager, i, &pPage);
|
rc = sqlite3pager_get(pBtTo->pPager, i, &pPage);
|
||||||
if( rc ) break;
|
if( rc ) break;
|
||||||
rc = sqlite3pager_write(pPage);
|
rc = sqlite3pager_write(pPage);
|
||||||
|
|
|
@ -76,7 +76,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||||
if( pParse->cookieGoto>0 ){
|
if( pParse->cookieGoto>0 ){
|
||||||
u32 mask;
|
u32 mask;
|
||||||
int iDb;
|
int iDb;
|
||||||
sqlite3VdbeChangeP2(v, pParse->cookieGoto-1, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
|
||||||
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
|
||||||
if( (mask & pParse->cookieMask)==0 ) continue;
|
if( (mask & pParse->cookieMask)==0 ) continue;
|
||||||
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
|
sqlite3VdbeAddOp(v, OP_Transaction, iDb, (mask & pParse->writeMask)!=0);
|
||||||
|
@ -85,6 +85,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||||
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
|
sqlite3VdbeAddOp(v, OP_Goto, 0, pParse->cookieGoto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_TRACE
|
||||||
/* Add a No-op that contains the complete text of the compiled SQL
|
/* Add a No-op that contains the complete text of the compiled SQL
|
||||||
** statement as its P3 argument. This does not change the functionality
|
** statement as its P3 argument. This does not change the functionality
|
||||||
** of the program.
|
** of the program.
|
||||||
|
@ -92,6 +93,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||||
** This is used to implement sqlite3_trace().
|
** This is used to implement sqlite3_trace().
|
||||||
*/
|
*/
|
||||||
sqlite3VdbeOp3(v, OP_Noop, 0, 0, pParse->zSql, pParse->zTail-pParse->zSql);
|
sqlite3VdbeOp3(v, OP_Noop, 0, 0, pParse->zSql, pParse->zTail-pParse->zSql);
|
||||||
|
#endif /* SQLITE_OMIT_TRACE */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,7 +103,7 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||||
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
|
FILE *trace = (db->flags & SQLITE_VdbeTrace)!=0 ? stdout : 0;
|
||||||
sqlite3VdbeTrace(v, trace);
|
sqlite3VdbeTrace(v, trace);
|
||||||
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
|
sqlite3VdbeMakeReady(v, pParse->nVar, pParse->nMem+3,
|
||||||
pParse->nTab+3, pParse->nMaxDepth+1, pParse->explain);
|
pParse->nTab+3, pParse->explain);
|
||||||
pParse->rc = SQLITE_DONE;
|
pParse->rc = SQLITE_DONE;
|
||||||
pParse->colNamesSet = 0;
|
pParse->colNamesSet = 0;
|
||||||
}else if( pParse->rc==SQLITE_OK ){
|
}else if( pParse->rc==SQLITE_OK ){
|
||||||
|
@ -130,7 +132,6 @@ void sqlite3FinishCoding(Parse *pParse){
|
||||||
void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char *zSql;
|
char *zSql;
|
||||||
int rc;
|
|
||||||
# define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar))
|
# define SAVE_SZ (sizeof(Parse) - offsetof(Parse,nVar))
|
||||||
char saveBuf[SAVE_SZ];
|
char saveBuf[SAVE_SZ];
|
||||||
|
|
||||||
|
@ -145,7 +146,7 @@ void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){
|
||||||
pParse->nested++;
|
pParse->nested++;
|
||||||
memcpy(saveBuf, &pParse->nVar, SAVE_SZ);
|
memcpy(saveBuf, &pParse->nVar, SAVE_SZ);
|
||||||
memset(&pParse->nVar, 0, SAVE_SZ);
|
memset(&pParse->nVar, 0, SAVE_SZ);
|
||||||
rc = sqlite3RunParser(pParse, zSql, 0);
|
sqlite3RunParser(pParse, zSql, 0);
|
||||||
sqliteFree(zSql);
|
sqliteFree(zSql);
|
||||||
memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
|
memcpy(&pParse->nVar, saveBuf, SAVE_SZ);
|
||||||
pParse->nested--;
|
pParse->nested--;
|
||||||
|
@ -634,7 +635,6 @@ void sqlite3StartTable(
|
||||||
int isView /* True if this is a VIEW */
|
int isView /* True if this is a VIEW */
|
||||||
){
|
){
|
||||||
Table *pTable;
|
Table *pTable;
|
||||||
Index *pIdx;
|
|
||||||
char *zName = 0; /* The name of the new table */
|
char *zName = 0; /* The name of the new table */
|
||||||
sqlite3 *db = pParse->db;
|
sqlite3 *db = pParse->db;
|
||||||
Vdbe *v;
|
Vdbe *v;
|
||||||
|
@ -713,8 +713,7 @@ void sqlite3StartTable(
|
||||||
sqlite3ErrorMsg(pParse, "table %T already exists", pName);
|
sqlite3ErrorMsg(pParse, "table %T already exists", pName);
|
||||||
goto begin_table_error;
|
goto begin_table_error;
|
||||||
}
|
}
|
||||||
if( (pIdx = sqlite3FindIndex(db, zName, 0))!=0 &&
|
if( sqlite3FindIndex(db, zName, 0)!=0 && (iDb==0 || !db->init.busy) ){
|
||||||
( iDb==0 || !db->init.busy) ){
|
|
||||||
sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
|
sqlite3ErrorMsg(pParse, "there is already an index named %s", zName);
|
||||||
goto begin_table_error;
|
goto begin_table_error;
|
||||||
}
|
}
|
||||||
|
@ -941,7 +940,7 @@ void sqlite3AddColumnType(Parse *pParse, Token *pType){
|
||||||
i = p->nCol-1;
|
i = p->nCol-1;
|
||||||
if( i<0 ) return;
|
if( i<0 ) return;
|
||||||
pCol = &p->aCol[i];
|
pCol = &p->aCol[i];
|
||||||
assert( pCol->zType==0 );
|
sqliteFree(pCol->zType);
|
||||||
pCol->zType = sqlite3NameFromToken(pType);
|
pCol->zType = sqlite3NameFromToken(pType);
|
||||||
pCol->affinity = sqlite3AffinityType(pType);
|
pCol->affinity = sqlite3AffinityType(pType);
|
||||||
}
|
}
|
||||||
|
@ -1016,7 +1015,9 @@ void sqlite3AddPrimaryKey(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( iCol<pTab->nCol ) pTab->aCol[iCol].isPrimKey = 1;
|
if( iCol<pTab->nCol ){
|
||||||
|
pTab->aCol[iCol].isPrimKey = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if( pList->nExpr>1 ) iCol = -1;
|
if( pList->nExpr>1 ) iCol = -1;
|
||||||
}
|
}
|
||||||
|
@ -2001,7 +2002,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0);
|
sqlite3VdbeAddOp(v, OP_IdxInsert, iIdx, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1);
|
sqlite3VdbeAddOp(v, OP_Next, iTab, addr1+1);
|
||||||
sqlite3VdbeChangeP2(v, addr1, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, addr1);
|
||||||
sqlite3VdbeAddOp(v, OP_Close, iTab, 0);
|
sqlite3VdbeAddOp(v, OP_Close, iTab, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_Close, iIdx, 0);
|
sqlite3VdbeAddOp(v, OP_Close, iIdx, 0);
|
||||||
}
|
}
|
||||||
|
@ -2114,14 +2115,12 @@ void sqlite3CreateIndex(
|
||||||
goto exit_create_index;
|
goto exit_create_index;
|
||||||
}
|
}
|
||||||
if( !db->init.busy ){
|
if( !db->init.busy ){
|
||||||
Index *pISameName; /* Another index with the same name */
|
|
||||||
Table *pTSameName; /* A table with same name as the index */
|
|
||||||
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
|
if( SQLITE_OK!=sqlite3ReadSchema(pParse) ) goto exit_create_index;
|
||||||
if( (pISameName = sqlite3FindIndex(db, zName, db->aDb[iDb].zName))!=0 ){
|
if( sqlite3FindIndex(db, zName, db->aDb[iDb].zName)!=0 ){
|
||||||
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
sqlite3ErrorMsg(pParse, "index %s already exists", zName);
|
||||||
goto exit_create_index;
|
goto exit_create_index;
|
||||||
}
|
}
|
||||||
if( (pTSameName = sqlite3FindTable(db, zName, 0))!=0 ){
|
if( sqlite3FindTable(db, zName, 0)!=0 ){
|
||||||
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
|
sqlite3ErrorMsg(pParse, "there is already a table named %s", zName);
|
||||||
goto exit_create_index;
|
goto exit_create_index;
|
||||||
}
|
}
|
||||||
|
@ -2171,7 +2170,7 @@ void sqlite3CreateIndex(
|
||||||
(sizeof(int)*2 + sizeof(CollSeq*))*pList->nExpr );
|
(sizeof(int)*2 + sizeof(CollSeq*))*pList->nExpr );
|
||||||
if( sqlite3_malloc_failed ) goto exit_create_index;
|
if( sqlite3_malloc_failed ) goto exit_create_index;
|
||||||
pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr];
|
pIndex->aiColumn = (int*)&pIndex->keyInfo.aColl[pList->nExpr];
|
||||||
pIndex->aiRowEst = &pIndex->aiColumn[pList->nExpr];
|
pIndex->aiRowEst = (unsigned*)&pIndex->aiColumn[pList->nExpr];
|
||||||
pIndex->zName = (char*)&pIndex->aiRowEst[pList->nExpr+1];
|
pIndex->zName = (char*)&pIndex->aiRowEst[pList->nExpr+1];
|
||||||
strcpy(pIndex->zName, zName);
|
strcpy(pIndex->zName, zName);
|
||||||
pIndex->pTable = pTab;
|
pIndex->pTable = pTab;
|
||||||
|
@ -2394,7 +2393,7 @@ exit_create_index:
|
||||||
** are based on typical values found in actual indices.
|
** are based on typical values found in actual indices.
|
||||||
*/
|
*/
|
||||||
void sqlite3DefaultRowEst(Index *pIdx){
|
void sqlite3DefaultRowEst(Index *pIdx){
|
||||||
int *a = pIdx->aiRowEst;
|
unsigned *a = pIdx->aiRowEst;
|
||||||
int i;
|
int i;
|
||||||
assert( a!=0 );
|
assert( a!=0 );
|
||||||
a[0] = 1000000;
|
a[0] = 1000000;
|
||||||
|
@ -2467,6 +2466,47 @@ exit_drop_index:
|
||||||
sqlite3SrcListDelete(pName);
|
sqlite3SrcListDelete(pName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** ppArray points into a structure where there is an array pointer
|
||||||
|
** followed by two integers. The first integer is the
|
||||||
|
** number of elements in the structure array. The second integer
|
||||||
|
** is the number of allocated slots in the array.
|
||||||
|
**
|
||||||
|
** In other words, the structure looks something like this:
|
||||||
|
**
|
||||||
|
** struct Example1 {
|
||||||
|
** struct subElem *aEntry;
|
||||||
|
** int nEntry;
|
||||||
|
** int nAlloc;
|
||||||
|
** }
|
||||||
|
**
|
||||||
|
** The pnEntry parameter points to the equivalent of Example1.nEntry.
|
||||||
|
**
|
||||||
|
** This routine allocates a new slot in the array, zeros it out,
|
||||||
|
** and returns its index. If malloc fails a negative number is returned.
|
||||||
|
**
|
||||||
|
** szEntry is the sizeof of a single array entry. initSize is the
|
||||||
|
** number of array entries allocated on the initial allocation.
|
||||||
|
*/
|
||||||
|
int sqlite3ArrayAllocate(void **ppArray, int szEntry, int initSize){
|
||||||
|
char *p;
|
||||||
|
int *an = (int*)&ppArray[1];
|
||||||
|
if( an[0]>=an[1] ){
|
||||||
|
void *pNew;
|
||||||
|
int newSize;
|
||||||
|
newSize = an[1]*2 + initSize;
|
||||||
|
pNew = sqliteRealloc(*ppArray, newSize*szEntry);
|
||||||
|
if( pNew==0 ){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
an[1] = newSize;
|
||||||
|
*ppArray = pNew;
|
||||||
|
}
|
||||||
|
p = *ppArray;
|
||||||
|
memset(&p[an[0]*szEntry], 0, szEntry);
|
||||||
|
return an[0]++;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Append a new element to the given IdList. Create a new IdList if
|
** Append a new element to the given IdList. Create a new IdList if
|
||||||
** need be.
|
** need be.
|
||||||
|
@ -2474,24 +2514,18 @@ exit_drop_index:
|
||||||
** A new IdList is returned, or NULL if malloc() fails.
|
** A new IdList is returned, or NULL if malloc() fails.
|
||||||
*/
|
*/
|
||||||
IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){
|
IdList *sqlite3IdListAppend(IdList *pList, Token *pToken){
|
||||||
|
int i;
|
||||||
if( pList==0 ){
|
if( pList==0 ){
|
||||||
pList = sqliteMalloc( sizeof(IdList) );
|
pList = sqliteMalloc( sizeof(IdList) );
|
||||||
if( pList==0 ) return 0;
|
if( pList==0 ) return 0;
|
||||||
pList->nAlloc = 0;
|
pList->nAlloc = 0;
|
||||||
}
|
}
|
||||||
if( pList->nId>=pList->nAlloc ){
|
i = sqlite3ArrayAllocate((void**)&pList->a, sizeof(pList->a[0]), 5);
|
||||||
struct IdList_item *a;
|
if( i<0 ){
|
||||||
pList->nAlloc = pList->nAlloc*2 + 5;
|
|
||||||
a = sqliteRealloc(pList->a, pList->nAlloc*sizeof(pList->a[0]) );
|
|
||||||
if( a==0 ){
|
|
||||||
sqlite3IdListDelete(pList);
|
sqlite3IdListDelete(pList);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pList->a = a;
|
pList->a[i].zName = sqlite3NameFromToken(pToken);
|
||||||
}
|
|
||||||
memset(&pList->a[pList->nId], 0, sizeof(pList->a[0]));
|
|
||||||
pList->a[pList->nId].zName = sqlite3NameFromToken(pToken);
|
|
||||||
pList->nId++;
|
|
||||||
return pList;
|
return pList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -178,12 +178,12 @@ void sqlite3DeleteFrom(
|
||||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||||
sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb);
|
sqlite3BeginWriteOperation(pParse, triggers_exist, pTab->iDb);
|
||||||
|
|
||||||
/* If we are trying to delete from a view, construct that view into
|
/* If we are trying to delete from a view, realize that view into
|
||||||
** a temporary table.
|
** a ephemeral table.
|
||||||
*/
|
*/
|
||||||
if( isView ){
|
if( isView ){
|
||||||
Select *pView = sqlite3SelectDup(pTab->pSelect);
|
Select *pView = sqlite3SelectDup(pTab->pSelect);
|
||||||
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
|
sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
|
||||||
sqlite3SelectDelete(pView);
|
sqlite3SelectDelete(pView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -380,7 +380,7 @@ void sqlite3GenerateRowDelete(
|
||||||
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
|
addr = sqlite3VdbeAddOp(v, OP_NotExists, iCur, 0);
|
||||||
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
|
sqlite3GenerateRowIndexDelete(db, v, pTab, iCur, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
|
sqlite3VdbeAddOp(v, OP_Delete, iCur, (count?OPFLAG_NCHANGE:0));
|
||||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -355,7 +355,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
|
||||||
pExpr->iTable = ++pParse->nVar;
|
pExpr->iTable = ++pParse->nVar;
|
||||||
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
|
if( pParse->nVarExpr>=pParse->nVarExprAlloc-1 ){
|
||||||
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
|
pParse->nVarExprAlloc += pParse->nVarExprAlloc + 10;
|
||||||
pParse->apVarExpr = sqliteRealloc(pParse->apVarExpr,
|
sqlite3ReallocOrFree((void**)&pParse->apVarExpr,
|
||||||
pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
|
pParse->nVarExprAlloc*sizeof(pParse->apVarExpr[0]) );
|
||||||
}
|
}
|
||||||
if( !sqlite3_malloc_failed ){
|
if( !sqlite3_malloc_failed ){
|
||||||
|
@ -546,9 +546,14 @@ Select *sqlite3SelectDup(Select *p){
|
||||||
pNew->pOffset = sqlite3ExprDup(p->pOffset);
|
pNew->pOffset = sqlite3ExprDup(p->pOffset);
|
||||||
pNew->iLimit = -1;
|
pNew->iLimit = -1;
|
||||||
pNew->iOffset = -1;
|
pNew->iOffset = -1;
|
||||||
pNew->ppOpenVirtual = 0;
|
|
||||||
pNew->isResolved = p->isResolved;
|
pNew->isResolved = p->isResolved;
|
||||||
pNew->isAgg = p->isAgg;
|
pNew->isAgg = p->isAgg;
|
||||||
|
pNew->usesVirt = 0;
|
||||||
|
pNew->disallowOrderBy = 0;
|
||||||
|
pNew->pRightmost = 0;
|
||||||
|
pNew->addrOpenVirt[0] = -1;
|
||||||
|
pNew->addrOpenVirt[1] = -1;
|
||||||
|
pNew->addrOpenVirt[2] = -1;
|
||||||
return pNew;
|
return pNew;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -692,6 +697,7 @@ static int exprNodeIsConstant(void *pArg, Expr *pExpr){
|
||||||
case TK_COLUMN:
|
case TK_COLUMN:
|
||||||
case TK_DOT:
|
case TK_DOT:
|
||||||
case TK_AGG_FUNCTION:
|
case TK_AGG_FUNCTION:
|
||||||
|
case TK_AGG_COLUMN:
|
||||||
#ifndef SQLITE_OMIT_SUBQUERY
|
#ifndef SQLITE_OMIT_SUBQUERY
|
||||||
case TK_SELECT:
|
case TK_SELECT:
|
||||||
case TK_EXISTS:
|
case TK_EXISTS:
|
||||||
|
@ -1227,11 +1233,19 @@ int sqlite3ExprResolveNames(
|
||||||
NameContext *pNC, /* Namespace to resolve expressions in. */
|
NameContext *pNC, /* Namespace to resolve expressions in. */
|
||||||
Expr *pExpr /* The expression to be analyzed. */
|
Expr *pExpr /* The expression to be analyzed. */
|
||||||
){
|
){
|
||||||
|
int savedHasAgg;
|
||||||
if( pExpr==0 ) return 0;
|
if( pExpr==0 ) return 0;
|
||||||
|
savedHasAgg = pNC->hasAgg;
|
||||||
|
pNC->hasAgg = 0;
|
||||||
walkExprTree(pExpr, nameResolverStep, pNC);
|
walkExprTree(pExpr, nameResolverStep, pNC);
|
||||||
if( pNC->nErr>0 ){
|
if( pNC->nErr>0 ){
|
||||||
ExprSetProperty(pExpr, EP_Error);
|
ExprSetProperty(pExpr, EP_Error);
|
||||||
}
|
}
|
||||||
|
if( pNC->hasAgg ){
|
||||||
|
ExprSetProperty(pExpr, EP_Agg);
|
||||||
|
}else if( savedHasAgg ){
|
||||||
|
pNC->hasAgg = 1;
|
||||||
|
}
|
||||||
return ExprHasProperty(pExpr, EP_Error);
|
return ExprHasProperty(pExpr, EP_Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1279,13 +1293,8 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||||
int mem = pParse->nMem++;
|
int mem = pParse->nMem++;
|
||||||
sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0);
|
sqlite3VdbeAddOp(v, OP_MemLoad, mem, 0);
|
||||||
testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0);
|
testAddr = sqlite3VdbeAddOp(v, OP_If, 0, 0);
|
||||||
assert( testAddr>0 );
|
assert( testAddr>0 || sqlite3_malloc_failed );
|
||||||
sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
|
sqlite3VdbeAddOp(v, OP_MemInt, 1, mem);
|
||||||
sqlite3VdbeAddOp(v, OP_MemStore, mem, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if( pExpr->pSelect ){
|
|
||||||
sqlite3VdbeAddOp(v, OP_AggContextPush, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch( pExpr->op ){
|
switch( pExpr->op ){
|
||||||
|
@ -1359,7 +1368,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||||
if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){
|
if( testAddr>0 && !sqlite3ExprIsConstant(pE2) ){
|
||||||
VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1);
|
VdbeOp *aOp = sqlite3VdbeGetOp(v, testAddr-1);
|
||||||
int i;
|
int i;
|
||||||
for(i=0; i<4; i++){
|
for(i=0; i<3; i++){
|
||||||
aOp[i].opcode = OP_Noop;
|
aOp[i].opcode = OP_Noop;
|
||||||
}
|
}
|
||||||
testAddr = 0;
|
testAddr = 0;
|
||||||
|
@ -1400,11 +1409,8 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( pExpr->pSelect ){
|
|
||||||
sqlite3VdbeAddOp(v, OP_AggContextPop, 0, 0);
|
|
||||||
}
|
|
||||||
if( testAddr ){
|
if( testAddr ){
|
||||||
sqlite3VdbeChangeP2(v, testAddr, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, testAddr);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1445,10 +1451,21 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||||
}
|
}
|
||||||
op = pExpr->op;
|
op = pExpr->op;
|
||||||
switch( op ){
|
switch( op ){
|
||||||
|
case TK_AGG_COLUMN: {
|
||||||
|
AggInfo *pAggInfo = pExpr->pAggInfo;
|
||||||
|
struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg];
|
||||||
|
if( !pAggInfo->directMode ){
|
||||||
|
sqlite3VdbeAddOp(v, OP_MemLoad, pCol->iMem, 0);
|
||||||
|
break;
|
||||||
|
}else if( pAggInfo->useSortingIdx ){
|
||||||
|
sqlite3VdbeAddOp(v, OP_Column, pAggInfo->sortingIdx,
|
||||||
|
pCol->iSorterColumn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Otherwise, fall thru into the TK_COLUMN case */
|
||||||
|
}
|
||||||
case TK_COLUMN: {
|
case TK_COLUMN: {
|
||||||
if( !pParse->fillAgg && pExpr->iAgg>=0 ){
|
if( pExpr->iColumn>=0 ){
|
||||||
sqlite3VdbeAddOp(v, OP_AggGet, pExpr->iAggCtx, pExpr->iAgg);
|
|
||||||
}else if( pExpr->iColumn>=0 ){
|
|
||||||
sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
|
sqlite3VdbeAddOp(v, OP_Column, pExpr->iTable, pExpr->iColumn);
|
||||||
sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn);
|
sqlite3ColumnDefault(v, pExpr->pTab, pExpr->iColumn);
|
||||||
}else{
|
}else{
|
||||||
|
@ -1597,7 +1614,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_AGG_FUNCTION: {
|
case TK_AGG_FUNCTION: {
|
||||||
sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg);
|
AggInfo *pInfo = pExpr->pAggInfo;
|
||||||
|
sqlite3VdbeAddOp(v, OP_MemLoad, pInfo->aFunc[pExpr->iAgg].iMem, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TK_CONST_FUNC:
|
case TK_CONST_FUNC:
|
||||||
|
@ -1607,7 +1625,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||||
FuncDef *pDef;
|
FuncDef *pDef;
|
||||||
int nId;
|
int nId;
|
||||||
const char *zId;
|
const char *zId;
|
||||||
int p2 = 0;
|
int constMask = 0;
|
||||||
int i;
|
int i;
|
||||||
u8 enc = pParse->db->enc;
|
u8 enc = pParse->db->enc;
|
||||||
CollSeq *pColl = 0;
|
CollSeq *pColl = 0;
|
||||||
|
@ -1618,7 +1636,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||||
nExpr = sqlite3ExprCodeExprList(pParse, pList);
|
nExpr = sqlite3ExprCodeExprList(pParse, pList);
|
||||||
for(i=0; i<nExpr && i<32; i++){
|
for(i=0; i<nExpr && i<32; i++){
|
||||||
if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
|
if( sqlite3ExprIsConstant(pList->a[i].pExpr) ){
|
||||||
p2 |= (1<<i);
|
constMask |= (1<<i);
|
||||||
}
|
}
|
||||||
if( pDef->needCollSeq && !pColl ){
|
if( pDef->needCollSeq && !pColl ){
|
||||||
pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
|
pColl = sqlite3ExprCollSeq(pParse, pList->a[i].pExpr);
|
||||||
|
@ -1628,7 +1646,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||||
if( !pColl ) pColl = pParse->db->pDfltColl;
|
if( !pColl ) pColl = pParse->db->pDfltColl;
|
||||||
sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
|
sqlite3VdbeOp3(v, OP_CollSeq, 0, 0, (char *)pColl, P3_COLLSEQ);
|
||||||
}
|
}
|
||||||
sqlite3VdbeOp3(v, OP_Function, nExpr, p2, (char*)pDef, P3_FUNCDEF);
|
sqlite3VdbeOp3(v, OP_Function, constMask, nExpr, (char*)pDef, P3_FUNCDEF);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifndef SQLITE_OMIT_SUBQUERY
|
#ifndef SQLITE_OMIT_SUBQUERY
|
||||||
|
@ -1692,7 +1710,6 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||||
case TK_CASE: {
|
case TK_CASE: {
|
||||||
int expr_end_label;
|
int expr_end_label;
|
||||||
int jumpInst;
|
int jumpInst;
|
||||||
int addr;
|
|
||||||
int nExpr;
|
int nExpr;
|
||||||
int i;
|
int i;
|
||||||
ExprList *pEList;
|
ExprList *pEList;
|
||||||
|
@ -1720,8 +1737,7 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){
|
||||||
}
|
}
|
||||||
sqlite3ExprCode(pParse, aListelem[i+1].pExpr);
|
sqlite3ExprCode(pParse, aListelem[i+1].pExpr);
|
||||||
sqlite3VdbeAddOp(v, OP_Goto, 0, expr_end_label);
|
sqlite3VdbeAddOp(v, OP_Goto, 0, expr_end_label);
|
||||||
addr = sqlite3VdbeCurrentAddr(v);
|
sqlite3VdbeJumpHere(v, jumpInst);
|
||||||
sqlite3VdbeChangeP2(v, jumpInst, addr);
|
|
||||||
}
|
}
|
||||||
if( pExpr->pLeft ){
|
if( pExpr->pLeft ){
|
||||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||||
|
@ -1888,7 +1904,7 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
|
||||||
codeCompare(pParse, pLeft, pRight, OP_Le, dest, jumpIfNull);
|
codeCompare(pParse, pLeft, pRight, OP_Le, dest, jumpIfNull);
|
||||||
|
|
||||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
sqlite3VdbeAddOp(v, OP_Pop, 1, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2021,6 +2037,7 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if( pA->op!=pB->op ) return 0;
|
if( pA->op!=pB->op ) return 0;
|
||||||
|
if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 0;
|
||||||
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
|
if( !sqlite3ExprCompare(pA->pLeft, pB->pLeft) ) return 0;
|
||||||
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
|
if( !sqlite3ExprCompare(pA->pRight, pB->pRight) ) return 0;
|
||||||
if( pA->pList ){
|
if( pA->pList ){
|
||||||
|
@ -2044,22 +2061,31 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Add a new element to the pParse->aAgg[] array and return its index.
|
** Add a new element to the pAggInfo->aCol[] array. Return the index of
|
||||||
** The new element is initialized to zero. The calling function is
|
** the new element. Return a negative number if malloc fails.
|
||||||
** expected to fill it in.
|
|
||||||
*/
|
*/
|
||||||
static int appendAggInfo(Parse *pParse){
|
static int addAggInfoColumn(AggInfo *pInfo){
|
||||||
if( (pParse->nAgg & 0x7)==0 ){
|
int i;
|
||||||
int amt = pParse->nAgg + 8;
|
i = sqlite3ArrayAllocate((void**)&pInfo->aCol, sizeof(pInfo->aCol[0]), 3);
|
||||||
AggExpr *aAgg = sqliteRealloc(pParse->aAgg, amt*sizeof(pParse->aAgg[0]));
|
if( i<0 ){
|
||||||
if( aAgg==0 ){
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pParse->aAgg = aAgg;
|
return i;
|
||||||
}
|
}
|
||||||
memset(&pParse->aAgg[pParse->nAgg], 0, sizeof(pParse->aAgg[0]));
|
|
||||||
return pParse->nAgg++;
|
/*
|
||||||
|
** Add a new element to the pAggInfo->aFunc[] array. Return the index of
|
||||||
|
** the new element. Return a negative number if malloc fails.
|
||||||
|
*/
|
||||||
|
static int addAggInfoFunc(AggInfo *pInfo){
|
||||||
|
int i;
|
||||||
|
i = sqlite3ArrayAllocate((void**)&pInfo->aFunc, sizeof(pInfo->aFunc[0]), 2);
|
||||||
|
if( i<0 ){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2071,60 +2097,118 @@ static int appendAggInfo(Parse *pParse){
|
||||||
*/
|
*/
|
||||||
static int analyzeAggregate(void *pArg, Expr *pExpr){
|
static int analyzeAggregate(void *pArg, Expr *pExpr){
|
||||||
int i;
|
int i;
|
||||||
AggExpr *aAgg;
|
|
||||||
NameContext *pNC = (NameContext *)pArg;
|
NameContext *pNC = (NameContext *)pArg;
|
||||||
Parse *pParse = pNC->pParse;
|
Parse *pParse = pNC->pParse;
|
||||||
SrcList *pSrcList = pNC->pSrcList;
|
SrcList *pSrcList = pNC->pSrcList;
|
||||||
|
AggInfo *pAggInfo = pNC->pAggInfo;
|
||||||
|
|
||||||
|
|
||||||
switch( pExpr->op ){
|
switch( pExpr->op ){
|
||||||
case TK_COLUMN: {
|
case TK_COLUMN: {
|
||||||
for(i=0; pSrcList && i<pSrcList->nSrc; i++){
|
/* Check to see if the column is in one of the tables in the FROM
|
||||||
if( pExpr->iTable==pSrcList->a[i].iCursor ){
|
** clause of the aggregate query */
|
||||||
aAgg = pParse->aAgg;
|
if( pSrcList ){
|
||||||
for(i=0; i<pParse->nAgg; i++){
|
struct SrcList_item *pItem = pSrcList->a;
|
||||||
if( aAgg[i].isAgg ) continue;
|
for(i=0; i<pSrcList->nSrc; i++, pItem++){
|
||||||
if( aAgg[i].pExpr->iTable==pExpr->iTable
|
struct AggInfo_col *pCol;
|
||||||
&& aAgg[i].pExpr->iColumn==pExpr->iColumn ){
|
if( pExpr->iTable==pItem->iCursor ){
|
||||||
|
/* If we reach this point, it means that pExpr refers to a table
|
||||||
|
** that is in the FROM clause of the aggregate query.
|
||||||
|
**
|
||||||
|
** Make an entry for the column in pAggInfo->aCol[] if there
|
||||||
|
** is not an entry there already.
|
||||||
|
*/
|
||||||
|
pCol = pAggInfo->aCol;
|
||||||
|
for(i=0; i<pAggInfo->nColumn; i++, pCol++){
|
||||||
|
if( pCol->iTable==pExpr->iTable &&
|
||||||
|
pCol->iColumn==pExpr->iColumn ){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( i>=pParse->nAgg ){
|
if( i>=pAggInfo->nColumn && (i = addAggInfoColumn(pAggInfo))>=0 ){
|
||||||
i = appendAggInfo(pParse);
|
pCol = &pAggInfo->aCol[i];
|
||||||
if( i<0 ) return 1;
|
pCol->iTable = pExpr->iTable;
|
||||||
pParse->aAgg[i].isAgg = 0;
|
pCol->iColumn = pExpr->iColumn;
|
||||||
pParse->aAgg[i].pExpr = pExpr;
|
pCol->iMem = pParse->nMem++;
|
||||||
|
pCol->iSorterColumn = -1;
|
||||||
|
pCol->pExpr = pExpr;
|
||||||
|
if( pAggInfo->pGroupBy ){
|
||||||
|
int j, n;
|
||||||
|
ExprList *pGB = pAggInfo->pGroupBy;
|
||||||
|
struct ExprList_item *pTerm = pGB->a;
|
||||||
|
n = pGB->nExpr;
|
||||||
|
for(j=0; j<n; j++, pTerm++){
|
||||||
|
Expr *pE = pTerm->pExpr;
|
||||||
|
if( pE->op==TK_COLUMN && pE->iTable==pExpr->iTable &&
|
||||||
|
pE->iColumn==pExpr->iColumn ){
|
||||||
|
pCol->iSorterColumn = j;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( pCol->iSorterColumn<0 ){
|
||||||
|
pCol->iSorterColumn = pAggInfo->nSortingColumn++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* There is now an entry for pExpr in pAggInfo->aCol[] (either
|
||||||
|
** because it was there before or because we just created it).
|
||||||
|
** Convert the pExpr to be a TK_AGG_COLUMN referring to that
|
||||||
|
** pAggInfo->aCol[] entry.
|
||||||
|
*/
|
||||||
|
pExpr->pAggInfo = pAggInfo;
|
||||||
|
pExpr->op = TK_AGG_COLUMN;
|
||||||
pExpr->iAgg = i;
|
pExpr->iAgg = i;
|
||||||
pExpr->iAggCtx = pNC->nDepth;
|
break;
|
||||||
return 1;
|
} /* endif pExpr->iTable==pItem->iCursor */
|
||||||
}
|
} /* end loop over pSrcList */
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
case TK_AGG_FUNCTION: {
|
case TK_AGG_FUNCTION: {
|
||||||
|
/* The pNC->nDepth==0 test causes aggregate functions in subqueries
|
||||||
|
** to be ignored */
|
||||||
if( pNC->nDepth==0 ){
|
if( pNC->nDepth==0 ){
|
||||||
aAgg = pParse->aAgg;
|
/* Check to see if pExpr is a duplicate of another aggregate
|
||||||
for(i=0; i<pParse->nAgg; i++){
|
** function that is already in the pAggInfo structure
|
||||||
if( !aAgg[i].isAgg ) continue;
|
*/
|
||||||
if( sqlite3ExprCompare(aAgg[i].pExpr, pExpr) ){
|
struct AggInfo_func *pItem = pAggInfo->aFunc;
|
||||||
|
for(i=0; i<pAggInfo->nFunc; i++, pItem++){
|
||||||
|
if( sqlite3ExprCompare(pItem->pExpr, pExpr) ){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if( i>=pParse->nAgg ){
|
if( i>=pAggInfo->nFunc ){
|
||||||
|
/* pExpr is original. Make a new entry in pAggInfo->aFunc[]
|
||||||
|
*/
|
||||||
u8 enc = pParse->db->enc;
|
u8 enc = pParse->db->enc;
|
||||||
i = appendAggInfo(pParse);
|
i = addAggInfoFunc(pAggInfo);
|
||||||
if( i<0 ) return 1;
|
if( i>=0 ){
|
||||||
pParse->aAgg[i].isAgg = 1;
|
pItem = &pAggInfo->aFunc[i];
|
||||||
pParse->aAgg[i].pExpr = pExpr;
|
pItem->pExpr = pExpr;
|
||||||
pParse->aAgg[i].pFunc = sqlite3FindFunction(pParse->db,
|
pItem->iMem = pParse->nMem++;
|
||||||
|
pItem->pFunc = sqlite3FindFunction(pParse->db,
|
||||||
pExpr->token.z, pExpr->token.n,
|
pExpr->token.z, pExpr->token.n,
|
||||||
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
|
pExpr->pList ? pExpr->pList->nExpr : 0, enc, 0);
|
||||||
|
if( pExpr->flags & EP_Distinct ){
|
||||||
|
pItem->iDistinct = pParse->nTab++;
|
||||||
|
}else{
|
||||||
|
pItem->iDistinct = -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Make pExpr point to the appropriate pAggInfo->aFunc[] entry
|
||||||
|
*/
|
||||||
pExpr->iAgg = i;
|
pExpr->iAgg = i;
|
||||||
|
pExpr->pAggInfo = pAggInfo;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Recursively walk subqueries looking for TK_COLUMN nodes that need
|
||||||
|
** to be changed to TK_AGG_COLUMN. But increment nDepth so that
|
||||||
|
** TK_AGG_FUNCTION nodes in subqueries will be unchanged.
|
||||||
|
*/
|
||||||
if( pExpr->pSelect ){
|
if( pExpr->pSelect ){
|
||||||
pNC->nDepth++;
|
pNC->nDepth++;
|
||||||
walkSelectExpr(pExpr->pSelect, analyzeAggregate, pNC);
|
walkSelectExpr(pExpr->pSelect, analyzeAggregate, pNC);
|
||||||
|
@ -2149,3 +2233,21 @@ int sqlite3ExprAnalyzeAggregates(NameContext *pNC, Expr *pExpr){
|
||||||
walkExprTree(pExpr, analyzeAggregate, pNC);
|
walkExprTree(pExpr, analyzeAggregate, pNC);
|
||||||
return pNC->pParse->nErr - nErr;
|
return pNC->pParse->nErr - nErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Call sqlite3ExprAnalyzeAggregates() for every expression in an
|
||||||
|
** expression list. Return the number of errors.
|
||||||
|
**
|
||||||
|
** If an error is found, the analysis is cut short.
|
||||||
|
*/
|
||||||
|
int sqlite3ExprAnalyzeAggList(NameContext *pNC, ExprList *pList){
|
||||||
|
struct ExprList_item *pItem;
|
||||||
|
int i;
|
||||||
|
int nErr = 0;
|
||||||
|
if( pList ){
|
||||||
|
for(pItem=pList->a, i=0; nErr==0 && i<pList->nExpr; i++, pItem++){
|
||||||
|
nErr += sqlite3ExprAnalyzeAggregates(pNC, pItem->pExpr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nErr;
|
||||||
|
}
|
||||||
|
|
|
@ -819,6 +819,7 @@ typedef struct SumCtx SumCtx;
|
||||||
struct SumCtx {
|
struct SumCtx {
|
||||||
double sum; /* Sum of terms */
|
double sum; /* Sum of terms */
|
||||||
int cnt; /* Number of elements summed */
|
int cnt; /* Number of elements summed */
|
||||||
|
u8 seenFloat; /* True if there has been any floating point value */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -826,21 +827,32 @@ struct SumCtx {
|
||||||
*/
|
*/
|
||||||
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
static void sumStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||||
SumCtx *p;
|
SumCtx *p;
|
||||||
if( argc<1 ) return;
|
int type;
|
||||||
|
assert( argc==1 );
|
||||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
p = sqlite3_aggregate_context(context, sizeof(*p));
|
||||||
if( p && SQLITE_NULL!=sqlite3_value_type(argv[0]) ){
|
type = sqlite3_value_type(argv[0]);
|
||||||
|
if( p && type!=SQLITE_NULL ){
|
||||||
p->sum += sqlite3_value_double(argv[0]);
|
p->sum += sqlite3_value_double(argv[0]);
|
||||||
p->cnt++;
|
p->cnt++;
|
||||||
|
if( type==SQLITE_FLOAT ){
|
||||||
|
p->seenFloat = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void sumFinalize(sqlite3_context *context){
|
static void sumFinalize(sqlite3_context *context){
|
||||||
SumCtx *p;
|
SumCtx *p;
|
||||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
p = sqlite3_aggregate_context(context, 0);
|
||||||
sqlite3_result_double(context, p ? p->sum : 0.0);
|
if( p && p->cnt>0 ){
|
||||||
|
if( p->seenFloat ){
|
||||||
|
sqlite3_result_double(context, p->sum);
|
||||||
|
}else{
|
||||||
|
sqlite3_result_int64(context, (i64)p->sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
static void avgFinalize(sqlite3_context *context){
|
static void avgFinalize(sqlite3_context *context){
|
||||||
SumCtx *p;
|
SumCtx *p;
|
||||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
p = sqlite3_aggregate_context(context, 0);
|
||||||
if( p && p->cnt>0 ){
|
if( p && p->cnt>0 ){
|
||||||
sqlite3_result_double(context, p->sum/(double)p->cnt);
|
sqlite3_result_double(context, p->sum/(double)p->cnt);
|
||||||
}
|
}
|
||||||
|
@ -878,7 +890,7 @@ static void countStep(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||||
}
|
}
|
||||||
static void countFinalize(sqlite3_context *context){
|
static void countFinalize(sqlite3_context *context){
|
||||||
CountCtx *p;
|
CountCtx *p;
|
||||||
p = sqlite3_aggregate_context(context, sizeof(*p));
|
p = sqlite3_aggregate_context(context, 0);
|
||||||
sqlite3_result_int(context, p ? p->n : 0);
|
sqlite3_result_int(context, p ? p->n : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -916,12 +928,14 @@ static void minmaxStep(sqlite3_context *context, int argc, sqlite3_value **argv)
|
||||||
}
|
}
|
||||||
static void minMaxFinalize(sqlite3_context *context){
|
static void minMaxFinalize(sqlite3_context *context){
|
||||||
sqlite3_value *pRes;
|
sqlite3_value *pRes;
|
||||||
pRes = (sqlite3_value *)sqlite3_aggregate_context(context, sizeof(Mem));
|
pRes = (sqlite3_value *)sqlite3_aggregate_context(context, 0);
|
||||||
|
if( pRes ){
|
||||||
if( pRes->flags ){
|
if( pRes->flags ){
|
||||||
sqlite3_result_value(context, pRes);
|
sqlite3_result_value(context, pRes);
|
||||||
}
|
}
|
||||||
sqlite3VdbeMemRelease(pRes);
|
sqlite3VdbeMemRelease(pRes);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1041,11 +1055,11 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
||||||
/*
|
/*
|
||||||
** Set the LIKEOPT flag on the 2-argument function with the given name.
|
** Set the LIKEOPT flag on the 2-argument function with the given name.
|
||||||
*/
|
*/
|
||||||
static void setLikeOptFlag(sqlite3 *db, const char *zName){
|
static void setLikeOptFlag(sqlite3 *db, const char *zName, int flagVal){
|
||||||
FuncDef *pDef;
|
FuncDef *pDef;
|
||||||
pDef = sqlite3FindFunction(db, zName, strlen(zName), 2, SQLITE_UTF8, 0);
|
pDef = sqlite3FindFunction(db, zName, strlen(zName), 2, SQLITE_UTF8, 0);
|
||||||
if( pDef ){
|
if( pDef ){
|
||||||
pDef->flags = SQLITE_FUNC_LIKEOPT;
|
pDef->flags = flagVal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1065,10 +1079,9 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
|
||||||
sqlite3_create_function(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
|
sqlite3_create_function(db, "like", 3, SQLITE_UTF8, pInfo, likeFunc, 0, 0);
|
||||||
sqlite3_create_function(db, "glob", 2, SQLITE_UTF8,
|
sqlite3_create_function(db, "glob", 2, SQLITE_UTF8,
|
||||||
(struct compareInfo*)&globInfo, likeFunc, 0,0);
|
(struct compareInfo*)&globInfo, likeFunc, 0,0);
|
||||||
setLikeOptFlag(db, "glob");
|
setLikeOptFlag(db, "glob", SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE);
|
||||||
if( caseSensitive ){
|
setLikeOptFlag(db, "like",
|
||||||
setLikeOptFlag(db, "like");
|
caseSensitive ? (SQLITE_FUNC_LIKE | SQLITE_FUNC_CASE) : SQLITE_FUNC_LIKE);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1078,7 +1091,7 @@ void sqlite3RegisterLikeFunctions(sqlite3 *db, int caseSensitive){
|
||||||
** return TRUE. If the function is not a LIKE-style function then
|
** return TRUE. If the function is not a LIKE-style function then
|
||||||
** return FALSE.
|
** return FALSE.
|
||||||
*/
|
*/
|
||||||
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, char *aWc){
|
int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, int *pIsNocase, char *aWc){
|
||||||
FuncDef *pDef;
|
FuncDef *pDef;
|
||||||
if( pExpr->op!=TK_FUNCTION ){
|
if( pExpr->op!=TK_FUNCTION ){
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1088,7 +1101,7 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, char *aWc){
|
||||||
}
|
}
|
||||||
pDef = sqlite3FindFunction(db, pExpr->token.z, pExpr->token.n, 2,
|
pDef = sqlite3FindFunction(db, pExpr->token.z, pExpr->token.n, 2,
|
||||||
SQLITE_UTF8, 0);
|
SQLITE_UTF8, 0);
|
||||||
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKEOPT)==0 ){
|
if( pDef==0 || (pDef->flags & SQLITE_FUNC_LIKE)==0 ){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1100,6 +1113,6 @@ int sqlite3IsLikeFunction(sqlite3 *db, Expr *pExpr, char *aWc){
|
||||||
assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
|
assert( (char*)&likeInfoAlt == (char*)&likeInfoAlt.matchAll );
|
||||||
assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
|
assert( &((char*)&likeInfoAlt)[1] == (char*)&likeInfoAlt.matchOne );
|
||||||
assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
|
assert( &((char*)&likeInfoAlt)[2] == (char*)&likeInfoAlt.matchSet );
|
||||||
|
*pIsNocase = (pDef->flags & SQLITE_FUNC_CASE)==0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -372,13 +372,13 @@ void sqlite3Insert(
|
||||||
** of the program jumps to it. Create the temporary table, then jump
|
** of the program jumps to it. Create the temporary table, then jump
|
||||||
** back up and execute the SELECT code above.
|
** back up and execute the SELECT code above.
|
||||||
*/
|
*/
|
||||||
sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, iInitCode);
|
||||||
sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0);
|
sqlite3VdbeAddOp(v, OP_OpenVirtual, srcTab, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn);
|
sqlite3VdbeAddOp(v, OP_SetNumColumns, srcTab, nColumn);
|
||||||
sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
|
sqlite3VdbeAddOp(v, OP_Goto, 0, iSelectLoop);
|
||||||
sqlite3VdbeResolveLabel(v, iCleanup);
|
sqlite3VdbeResolveLabel(v, iCleanup);
|
||||||
}else{
|
}else{
|
||||||
sqlite3VdbeChangeP2(v, iInitCode, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, iInitCode);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
/* This is the case if the data for the INSERT is coming from a VALUES
|
/* This is the case if the data for the INSERT is coming from a VALUES
|
||||||
|
@ -470,8 +470,7 @@ void sqlite3Insert(
|
||||||
*/
|
*/
|
||||||
if( db->flags & SQLITE_CountRows ){
|
if( db->flags & SQLITE_CountRows ){
|
||||||
iCntMem = pParse->nMem++;
|
iCntMem = pParse->nMem++;
|
||||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
sqlite3VdbeAddOp(v, OP_MemInt, 0, iCntMem);
|
||||||
sqlite3VdbeAddOp(v, OP_MemStore, iCntMem, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open tables and indices if there are no row triggers */
|
/* Open tables and indices if there are no row triggers */
|
||||||
|
@ -817,7 +816,6 @@ void sqlite3GenerateConstraintChecks(
|
||||||
Index *pIdx;
|
Index *pIdx;
|
||||||
int seenReplace = 0;
|
int seenReplace = 0;
|
||||||
int jumpInst1=0, jumpInst2;
|
int jumpInst1=0, jumpInst2;
|
||||||
int contAddr;
|
|
||||||
int hasTwoRowids = (isUpdate && rowidChng);
|
int hasTwoRowids = (isUpdate && rowidChng);
|
||||||
|
|
||||||
v = sqlite3GetVdbe(pParse);
|
v = sqlite3GetVdbe(pParse);
|
||||||
|
@ -867,7 +865,7 @@ void sqlite3GenerateConstraintChecks(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test all CHECK constraints
|
/* Test all CHECK constraints
|
||||||
|
@ -921,10 +919,9 @@ void sqlite3GenerateConstraintChecks(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contAddr = sqlite3VdbeCurrentAddr(v);
|
sqlite3VdbeJumpHere(v, jumpInst2);
|
||||||
sqlite3VdbeChangeP2(v, jumpInst2, contAddr);
|
|
||||||
if( isUpdate ){
|
if( isUpdate ){
|
||||||
sqlite3VdbeChangeP2(v, jumpInst1, contAddr);
|
sqlite3VdbeJumpHere(v, jumpInst1);
|
||||||
sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);
|
sqlite3VdbeAddOp(v, OP_Dup, nCol+1, 1);
|
||||||
sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
|
sqlite3VdbeAddOp(v, OP_MoveGe, base, 0);
|
||||||
}
|
}
|
||||||
|
@ -1018,11 +1015,10 @@ void sqlite3GenerateConstraintChecks(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contAddr = sqlite3VdbeCurrentAddr(v);
|
|
||||||
#if NULL_DISTINCT_FOR_UNIQUE
|
#if NULL_DISTINCT_FOR_UNIQUE
|
||||||
sqlite3VdbeChangeP2(v, jumpInst1, contAddr);
|
sqlite3VdbeJumpHere(v, jumpInst1);
|
||||||
#endif
|
#endif
|
||||||
sqlite3VdbeChangeP2(v, jumpInst2, contAddr);
|
sqlite3VdbeJumpHere(v, jumpInst2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -509,13 +509,14 @@ int sqlite3_create_function16(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_TRACE
|
||||||
/*
|
/*
|
||||||
** Register a trace function. The pArg from the previously registered trace
|
** Register a trace function. The pArg from the previously registered trace
|
||||||
** is returned.
|
** is returned.
|
||||||
**
|
**
|
||||||
** A NULL trace function means that no tracing is executes. A non-NULL
|
** A NULL trace function means that no tracing is executes. A non-NULL
|
||||||
** trace is a pointer to a function that is invoked at the start of each
|
** trace is a pointer to a function that is invoked at the start of each
|
||||||
** sqlite3_exec().
|
** SQL statement.
|
||||||
*/
|
*/
|
||||||
void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
|
void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
|
||||||
void *pOld = db->pTraceArg;
|
void *pOld = db->pTraceArg;
|
||||||
|
@ -523,6 +524,25 @@ void *sqlite3_trace(sqlite3 *db, void (*xTrace)(void*,const char*), void *pArg){
|
||||||
db->pTraceArg = pArg;
|
db->pTraceArg = pArg;
|
||||||
return pOld;
|
return pOld;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
** Register a profile function. The pArg from the previously registered
|
||||||
|
** profile function is returned.
|
||||||
|
**
|
||||||
|
** A NULL profile function means that no profiling is executes. A non-NULL
|
||||||
|
** profile is a pointer to a function that is invoked at the conclusion of
|
||||||
|
** each SQL statement that is run.
|
||||||
|
*/
|
||||||
|
void *sqlite3_profile(
|
||||||
|
sqlite3 *db,
|
||||||
|
void (*xProfile)(void*,const char*,sqlite_uint64),
|
||||||
|
void *pArg
|
||||||
|
){
|
||||||
|
void *pOld = db->pProfileArg;
|
||||||
|
db->xProfile = xProfile;
|
||||||
|
db->pProfileArg = pArg;
|
||||||
|
return pOld;
|
||||||
|
}
|
||||||
|
#endif /* SQLITE_OMIT_TRACE */
|
||||||
|
|
||||||
/*** EXPERIMENTAL ***
|
/*** EXPERIMENTAL ***
|
||||||
**
|
**
|
||||||
|
@ -694,6 +714,7 @@ static int openDatabase(
|
||||||
){
|
){
|
||||||
sqlite3 *db;
|
sqlite3 *db;
|
||||||
int rc, i;
|
int rc, i;
|
||||||
|
CollSeq *pColl;
|
||||||
|
|
||||||
/* Allocate the sqlite data structure */
|
/* Allocate the sqlite data structure */
|
||||||
db = sqliteMalloc( sizeof(sqlite3) );
|
db = sqliteMalloc( sizeof(sqlite3) );
|
||||||
|
@ -730,6 +751,13 @@ static int openDatabase(
|
||||||
/* Also add a UTF-8 case-insensitive collation sequence. */
|
/* Also add a UTF-8 case-insensitive collation sequence. */
|
||||||
sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
|
sqlite3_create_collation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc);
|
||||||
|
|
||||||
|
/* Set flags on the built-in collating sequences */
|
||||||
|
db->pDfltColl->type = SQLITE_COLL_BINARY;
|
||||||
|
pColl = sqlite3FindCollSeq(db, SQLITE_UTF8, "NOCASE", 6, 0);
|
||||||
|
if( pColl ){
|
||||||
|
pColl->type = SQLITE_COLL_NOCASE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Open the backend database driver */
|
/* Open the backend database driver */
|
||||||
rc = sqlite3BtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
|
rc = sqlite3BtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
|
@ -847,7 +875,7 @@ int sqlite3_reset(sqlite3_stmt *pStmt){
|
||||||
rc = SQLITE_OK;
|
rc = SQLITE_OK;
|
||||||
}else{
|
}else{
|
||||||
rc = sqlite3VdbeReset((Vdbe*)pStmt);
|
rc = sqlite3VdbeReset((Vdbe*)pStmt);
|
||||||
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0, 0);
|
sqlite3VdbeMakeReady((Vdbe*)pStmt, -1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -1019,3 +1047,14 @@ recover_out:
|
||||||
int sqlite3_get_autocommit(sqlite3 *db){
|
int sqlite3_get_autocommit(sqlite3 *db){
|
||||||
return db->autoCommit;
|
return db->autoCommit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SQLITE_DEBUG
|
||||||
|
/*
|
||||||
|
** The following routine is subtituted for constant SQLITE_CORRUPT in
|
||||||
|
** debugging builds. This provides a way to set a breakpoint for when
|
||||||
|
** corruption is first detected.
|
||||||
|
*/
|
||||||
|
int sqlite3Corrupt(void){
|
||||||
|
return SQLITE_CORRUPT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,144 +1,149 @@
|
||||||
/* Automatically generated. Do not edit */
|
/* Automatically generated. Do not edit */
|
||||||
/* See the mkopcodeh.awk script for details */
|
/* See the mkopcodeh.awk script for details */
|
||||||
#define OP_MemLoad 1
|
#define OP_MemLoad 1
|
||||||
#define OP_HexBlob 131 /* same as TK_BLOB */
|
#define OP_HexBlob 134 /* same as TK_BLOB */
|
||||||
#define OP_Column 2
|
#define OP_Column 2
|
||||||
#define OP_SetCookie 3
|
#define OP_SetCookie 3
|
||||||
#define OP_IfMemPos 4
|
#define OP_IfMemPos 4
|
||||||
#define OP_Real 130 /* same as TK_FLOAT */
|
#define OP_Real 133 /* same as TK_FLOAT */
|
||||||
#define OP_MoveGt 5
|
#define OP_Sequence 5
|
||||||
#define OP_Ge 77 /* same as TK_GE */
|
#define OP_MoveGt 6
|
||||||
#define OP_AggFocus 6
|
#define OP_Ge 80 /* same as TK_GE */
|
||||||
#define OP_RowKey 7
|
#define OP_RowKey 7
|
||||||
#define OP_AggNext 8
|
#define OP_Eq 76 /* same as TK_EQ */
|
||||||
#define OP_Eq 73 /* same as TK_EQ */
|
#define OP_OpenWrite 8
|
||||||
#define OP_OpenWrite 9
|
#define OP_NotNull 74 /* same as TK_NOTNULL */
|
||||||
#define OP_NotNull 71 /* same as TK_NOTNULL */
|
#define OP_If 9
|
||||||
#define OP_If 10
|
#define OP_ToInt 10
|
||||||
#define OP_ToInt 11
|
#define OP_String8 95 /* same as TK_STRING */
|
||||||
#define OP_String8 92 /* same as TK_STRING */
|
#define OP_Pop 11
|
||||||
#define OP_Pop 12
|
#define OP_CollSeq 12
|
||||||
#define OP_AggContextPush 13
|
#define OP_OpenRead 13
|
||||||
#define OP_CollSeq 14
|
#define OP_Expire 14
|
||||||
#define OP_OpenRead 15
|
#define OP_AutoCommit 15
|
||||||
#define OP_Expire 16
|
#define OP_Gt 77 /* same as TK_GT */
|
||||||
#define OP_SortReset 17
|
#define OP_IntegrityCk 16
|
||||||
#define OP_AutoCommit 18
|
#define OP_Sort 17
|
||||||
#define OP_Gt 74 /* same as TK_GT */
|
#define OP_Function 18
|
||||||
#define OP_Sort 19
|
#define OP_And 68 /* same as TK_AND */
|
||||||
#define OP_IntegrityCk 20
|
#define OP_Subtract 87 /* same as TK_MINUS */
|
||||||
#define OP_SortInsert 21
|
#define OP_Noop 19
|
||||||
#define OP_Function 22
|
#define OP_Return 20
|
||||||
#define OP_And 65 /* same as TK_AND */
|
#define OP_Remainder 90 /* same as TK_REM */
|
||||||
#define OP_Subtract 84 /* same as TK_MINUS */
|
#define OP_NewRowid 21
|
||||||
#define OP_Noop 23
|
#define OP_Multiply 88 /* same as TK_STAR */
|
||||||
#define OP_Return 24
|
#define OP_Variable 22
|
||||||
#define OP_Remainder 87 /* same as TK_REM */
|
#define OP_String 23
|
||||||
#define OP_NewRowid 25
|
#define OP_ParseSchema 24
|
||||||
#define OP_Multiply 85 /* same as TK_STAR */
|
#define OP_Close 25
|
||||||
#define OP_Variable 26
|
#define OP_CreateIndex 26
|
||||||
#define OP_String 27
|
#define OP_IsUnique 27
|
||||||
#define OP_ParseSchema 28
|
#define OP_IdxIsNull 28
|
||||||
#define OP_AggFunc 29
|
#define OP_NotFound 29
|
||||||
#define OP_Close 30
|
#define OP_Int64 30
|
||||||
#define OP_CreateIndex 31
|
#define OP_MustBeInt 31
|
||||||
#define OP_IsUnique 32
|
#define OP_Halt 32
|
||||||
#define OP_IdxIsNull 33
|
#define OP_Rowid 33
|
||||||
#define OP_NotFound 34
|
#define OP_IdxLT 34
|
||||||
#define OP_Int64 35
|
#define OP_AddImm 35
|
||||||
#define OP_MustBeInt 36
|
#define OP_Statement 36
|
||||||
#define OP_Halt 37
|
#define OP_RowData 37
|
||||||
#define OP_Rowid 38
|
#define OP_MemMax 38
|
||||||
#define OP_IdxLT 39
|
#define OP_Push 39
|
||||||
#define OP_AddImm 40
|
#define OP_Or 67 /* same as TK_OR */
|
||||||
#define OP_Statement 41
|
#define OP_NotExists 40
|
||||||
#define OP_RowData 42
|
#define OP_MemIncr 41
|
||||||
#define OP_MemMax 43
|
#define OP_Gosub 42
|
||||||
#define OP_Push 44
|
#define OP_Divide 89 /* same as TK_SLASH */
|
||||||
#define OP_Or 64 /* same as TK_OR */
|
#define OP_Integer 43
|
||||||
#define OP_NotExists 45
|
#define OP_ToNumeric 44
|
||||||
#define OP_MemIncr 46
|
#define OP_MemInt 45
|
||||||
#define OP_Gosub 47
|
#define OP_Prev 46
|
||||||
#define OP_Divide 86 /* same as TK_SLASH */
|
#define OP_Concat 91 /* same as TK_CONCAT */
|
||||||
#define OP_AggSet 48
|
#define OP_BitAnd 82 /* same as TK_BITAND */
|
||||||
#define OP_Integer 49
|
#define OP_CreateTable 47
|
||||||
#define OP_ToNumeric 50
|
#define OP_Last 48
|
||||||
#define OP_SortNext 51
|
#define OP_IsNull 73 /* same as TK_ISNULL */
|
||||||
#define OP_Prev 52
|
#define OP_IdxRowid 49
|
||||||
#define OP_Concat 88 /* same as TK_CONCAT */
|
#define OP_MakeIdxRec 50
|
||||||
#define OP_BitAnd 79 /* same as TK_BITAND */
|
#define OP_ShiftRight 85 /* same as TK_RSHIFT */
|
||||||
#define OP_CreateTable 53
|
#define OP_ResetCount 51
|
||||||
#define OP_Last 54
|
#define OP_FifoWrite 52
|
||||||
#define OP_IsNull 70 /* same as TK_ISNULL */
|
#define OP_Callback 53
|
||||||
#define OP_IdxRowid 55
|
#define OP_ContextPush 54
|
||||||
#define OP_MakeIdxRec 56
|
#define OP_DropTrigger 55
|
||||||
#define OP_ShiftRight 82 /* same as TK_RSHIFT */
|
#define OP_DropIndex 56
|
||||||
#define OP_ResetCount 57
|
#define OP_IdxGE 57
|
||||||
#define OP_FifoWrite 58
|
#define OP_IdxDelete 58
|
||||||
#define OP_Callback 59
|
#define OP_Vacuum 59
|
||||||
#define OP_ContextPush 60
|
#define OP_MoveLe 60
|
||||||
#define OP_DropTrigger 61
|
#define OP_IfNot 61
|
||||||
#define OP_DropIndex 62
|
#define OP_DropTable 62
|
||||||
#define OP_IdxGE 63
|
#define OP_MakeRecord 63
|
||||||
#define OP_IdxDelete 67
|
#define OP_ToBlob 64
|
||||||
#define OP_Vacuum 68
|
#define OP_Delete 65
|
||||||
#define OP_MoveLe 69
|
#define OP_AggFinal 66
|
||||||
#define OP_IfNot 78
|
#define OP_ShiftLeft 84 /* same as TK_LSHIFT */
|
||||||
#define OP_DropTable 90
|
#define OP_Dup 70
|
||||||
#define OP_MakeRecord 93
|
#define OP_Goto 71
|
||||||
#define OP_ToBlob 94
|
#define OP_FifoRead 72
|
||||||
#define OP_Delete 95
|
#define OP_Clear 81
|
||||||
#define OP_AggContextPop 96
|
#define OP_IdxGT 93
|
||||||
#define OP_ShiftLeft 81 /* same as TK_LSHIFT */
|
#define OP_MoveLt 96
|
||||||
#define OP_Dup 97
|
#define OP_Le 78 /* same as TK_LE */
|
||||||
#define OP_Goto 98
|
#define OP_VerifyCookie 97
|
||||||
#define OP_FifoRead 99
|
#define OP_AggStep 98
|
||||||
#define OP_Clear 100
|
#define OP_Pull 99
|
||||||
#define OP_IdxGT 101
|
#define OP_ToText 100
|
||||||
#define OP_MoveLt 102
|
#define OP_Not 69 /* same as TK_NOT */
|
||||||
#define OP_Le 75 /* same as TK_LE */
|
#define OP_SetNumColumns 101
|
||||||
#define OP_VerifyCookie 103
|
#define OP_AbsValue 102
|
||||||
#define OP_Pull 104
|
#define OP_Transaction 103
|
||||||
#define OP_ToText 105
|
#define OP_Negative 92 /* same as TK_UMINUS */
|
||||||
#define OP_Not 66 /* same as TK_NOT */
|
#define OP_Ne 75 /* same as TK_NE */
|
||||||
#define OP_SetNumColumns 106
|
#define OP_ContextPop 104
|
||||||
#define OP_AbsValue 107
|
#define OP_BitOr 83 /* same as TK_BITOR */
|
||||||
#define OP_Transaction 108
|
#define OP_Next 105
|
||||||
#define OP_Negative 89 /* same as TK_UMINUS */
|
#define OP_IdxInsert 106
|
||||||
#define OP_Ne 72 /* same as TK_NE */
|
#define OP_Distinct 107
|
||||||
#define OP_AggGet 109
|
#define OP_Lt 79 /* same as TK_LT */
|
||||||
#define OP_ContextPop 110
|
#define OP_Insert 108
|
||||||
#define OP_BitOr 80 /* same as TK_BITOR */
|
#define OP_Destroy 109
|
||||||
#define OP_Next 111
|
#define OP_ReadCookie 110
|
||||||
#define OP_AggInit 112
|
#define OP_ForceInt 111
|
||||||
#define OP_IdxInsert 113
|
#define OP_LoadAnalysis 112
|
||||||
#define OP_Distinct 114
|
#define OP_OpenVirtual 113
|
||||||
#define OP_Lt 76 /* same as TK_LT */
|
#define OP_Explain 114
|
||||||
#define OP_AggReset 115
|
#define OP_OpenPseudo 115
|
||||||
#define OP_Insert 116
|
#define OP_Null 116
|
||||||
#define OP_Destroy 117
|
#define OP_Blob 117
|
||||||
#define OP_ReadCookie 118
|
#define OP_Add 86 /* same as TK_PLUS */
|
||||||
#define OP_ForceInt 119
|
#define OP_MemStore 118
|
||||||
#define OP_LoadAnalysis 120
|
#define OP_Rewind 119
|
||||||
#define OP_OpenVirtual 121
|
#define OP_MoveGe 120
|
||||||
#define OP_OpenPseudo 122
|
#define OP_BitNot 94 /* same as TK_BITNOT */
|
||||||
#define OP_Null 123
|
#define OP_MemMove 121
|
||||||
#define OP_Blob 124
|
#define OP_MemNull 122
|
||||||
#define OP_Add 83 /* same as TK_PLUS */
|
#define OP_Found 123
|
||||||
#define OP_MemStore 125
|
#define OP_NullRow 124
|
||||||
#define OP_Rewind 126
|
|
||||||
#define OP_MoveGe 127
|
|
||||||
#define OP_BitNot 91 /* same as TK_BITNOT */
|
|
||||||
#define OP_Found 128
|
|
||||||
#define OP_NullRow 129
|
|
||||||
|
|
||||||
#define NOPUSH_MASK_0 65400
|
/* The following opcode values are never used */
|
||||||
#define NOPUSH_MASK_1 29103
|
#define OP_NotUsed_125 125
|
||||||
#define NOPUSH_MASK_2 64439
|
#define OP_NotUsed_126 126
|
||||||
#define NOPUSH_MASK_3 65109
|
#define OP_NotUsed_127 127
|
||||||
#define NOPUSH_MASK_4 65535
|
#define OP_NotUsed_128 128
|
||||||
#define NOPUSH_MASK_5 52991
|
#define OP_NotUsed_129 129
|
||||||
#define NOPUSH_MASK_6 55285
|
#define OP_NotUsed_130 130
|
||||||
#define NOPUSH_MASK_7 59295
|
#define OP_NotUsed_131 131
|
||||||
#define NOPUSH_MASK_8 3
|
#define OP_NotUsed_132 132
|
||||||
|
|
||||||
|
#define NOPUSH_MASK_0 65368
|
||||||
|
#define NOPUSH_MASK_1 47898
|
||||||
|
#define NOPUSH_MASK_2 22493
|
||||||
|
#define NOPUSH_MASK_3 32761
|
||||||
|
#define NOPUSH_MASK_4 65215
|
||||||
|
#define NOPUSH_MASK_5 30719
|
||||||
|
#define NOPUSH_MASK_6 40895
|
||||||
|
#define NOPUSH_MASK_7 6603
|
||||||
|
#define NOPUSH_MASK_8 0
|
||||||
#define NOPUSH_MASK_9 0
|
#define NOPUSH_MASK_9 0
|
||||||
|
|
|
@ -161,8 +161,13 @@
|
||||||
** 1GB boundary.
|
** 1GB boundary.
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
|
#ifndef SQLITE_TEST
|
||||||
#define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */
|
#define PENDING_BYTE 0x40000000 /* First byte past the 1GB boundary */
|
||||||
/* #define PENDING_BYTE 0x5400 // Page 22 - for testing */
|
#else
|
||||||
|
extern unsigned int sqlite3_pending_byte;
|
||||||
|
#define PENDING_BYTE sqlite3_pending_byte
|
||||||
|
#endif
|
||||||
|
|
||||||
#define RESERVED_BYTE (PENDING_BYTE+1)
|
#define RESERVED_BYTE (PENDING_BYTE+1)
|
||||||
#define SHARED_FIRST (PENDING_BYTE+2)
|
#define SHARED_FIRST (PENDING_BYTE+2)
|
||||||
#define SHARED_SIZE 510
|
#define SHARED_SIZE 510
|
||||||
|
@ -181,7 +186,7 @@ int sqlite3OsClose(OsFile*);
|
||||||
int sqlite3OsRead(OsFile*, void*, int amt);
|
int sqlite3OsRead(OsFile*, void*, int amt);
|
||||||
int sqlite3OsWrite(OsFile*, const void*, int amt);
|
int sqlite3OsWrite(OsFile*, const void*, int amt);
|
||||||
int sqlite3OsSeek(OsFile*, i64 offset);
|
int sqlite3OsSeek(OsFile*, i64 offset);
|
||||||
int sqlite3OsSync(OsFile*);
|
int sqlite3OsSync(OsFile*, int);
|
||||||
int sqlite3OsTruncate(OsFile*, i64 size);
|
int sqlite3OsTruncate(OsFile*, i64 size);
|
||||||
int sqlite3OsFileSize(OsFile*, i64 *pSize);
|
int sqlite3OsFileSize(OsFile*, i64 *pSize);
|
||||||
char *sqlite3OsFullPathname(const char*);
|
char *sqlite3OsFullPathname(const char*);
|
||||||
|
|
|
@ -28,6 +28,14 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When testing, this global variable stores the location of the
|
||||||
|
* pending-byte in the database file.
|
||||||
|
*/
|
||||||
|
#ifdef SQLITE_TEST
|
||||||
|
unsigned int sqlite3_pending_byte = 0x40000000;
|
||||||
|
#endif
|
||||||
|
|
||||||
int sqlite3_os_trace = 0;
|
int sqlite3_os_trace = 0;
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
static int last_page = 0;
|
static int last_page = 0;
|
||||||
|
@ -82,6 +90,7 @@ static unsigned int elapse;
|
||||||
#ifdef SQLITE_TEST
|
#ifdef SQLITE_TEST
|
||||||
int sqlite3_io_error_pending = 0;
|
int sqlite3_io_error_pending = 0;
|
||||||
int sqlite3_diskfull_pending = 0;
|
int sqlite3_diskfull_pending = 0;
|
||||||
|
int sqlite3_diskfull = 0;
|
||||||
#define SimulateIOError(A) \
|
#define SimulateIOError(A) \
|
||||||
if( sqlite3_io_error_pending ) \
|
if( sqlite3_io_error_pending ) \
|
||||||
if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
|
if( sqlite3_io_error_pending-- == 1 ){ local_ioerr(); return A; }
|
||||||
|
@ -89,8 +98,15 @@ static void local_ioerr(){
|
||||||
sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */
|
sqlite3_io_error_pending = 0; /* Really just a place to set a breakpoint */
|
||||||
}
|
}
|
||||||
#define SimulateDiskfullError \
|
#define SimulateDiskfullError \
|
||||||
if( sqlite3_diskfull_pending ) \
|
if( sqlite3_diskfull_pending ){ \
|
||||||
if( sqlite3_diskfull_pending-- == 1 ){ local_ioerr(); return SQLITE_FULL; }
|
if( sqlite3_diskfull_pending == 1 ){ \
|
||||||
|
local_ioerr(); \
|
||||||
|
sqlite3_diskfull = 1; \
|
||||||
|
return SQLITE_FULL; \
|
||||||
|
}else{ \
|
||||||
|
sqlite3_diskfull_pending--; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#define SimulateIOError(A)
|
#define SimulateIOError(A)
|
||||||
#define SimulateDiskfullError
|
#define SimulateDiskfullError
|
||||||
|
|
|
@ -391,12 +391,12 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
||||||
** Sync the file. First flush the write-cache to disk, then call the
|
** Sync the file. First flush the write-cache to disk, then call the
|
||||||
** real sync() function.
|
** real sync() function.
|
||||||
*/
|
*/
|
||||||
int sqlite3OsSync(OsFile *id){
|
int sqlite3OsSync(OsFile *id, int dataOnly){
|
||||||
int rc;
|
int rc;
|
||||||
/* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
|
/* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */
|
||||||
rc = writeCache(*id);
|
rc = writeCache(*id);
|
||||||
if( rc!=SQLITE_OK ) return rc;
|
if( rc!=SQLITE_OK ) return rc;
|
||||||
rc = sqlite3RealSync(&(*id)->fd);
|
rc = sqlite3RealSync(&(*id)->fd, dataOnly);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
@ -771,6 +772,9 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
||||||
int sqlite3OsSeek(OsFile *id, i64 offset){
|
int sqlite3OsSeek(OsFile *id, i64 offset){
|
||||||
assert( id->isOpen );
|
assert( id->isOpen );
|
||||||
SEEK(offset/1024 + 1);
|
SEEK(offset/1024 + 1);
|
||||||
|
#ifdef SQLITE_TEST
|
||||||
|
if( offset ) SimulateDiskfullError
|
||||||
|
#endif
|
||||||
lseek(id->h, offset, SEEK_SET);
|
lseek(id->h, offset, SEEK_SET);
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
@ -796,7 +800,7 @@ int sqlite3_fullsync_count = 0;
|
||||||
** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
|
** enabled, however, since with SQLITE_NO_SYNC enabled, an OS crash
|
||||||
** or power failure will likely corrupt the database file.
|
** or power failure will likely corrupt the database file.
|
||||||
*/
|
*/
|
||||||
static int full_fsync(int fd, int fullSync){
|
static int full_fsync(int fd, int fullSync, int dataOnly){
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Record the number of times that we do a normal fsync() and
|
/* Record the number of times that we do a normal fsync() and
|
||||||
|
@ -824,8 +828,15 @@ static int full_fsync(int fd, int fullSync){
|
||||||
/* If the FULLSYNC failed, try to do a normal fsync() */
|
/* If the FULLSYNC failed, try to do a normal fsync() */
|
||||||
if( rc ) rc = fsync(fd);
|
if( rc ) rc = fsync(fd);
|
||||||
|
|
||||||
#else
|
#else /* if !defined(F_FULLSYNC) */
|
||||||
|
#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO>0
|
||||||
|
if( dataOnly ){
|
||||||
|
rc = fdatasync(fd);
|
||||||
|
}else
|
||||||
|
#endif /* _POSIX_SYNCHRONIZED_IO > 0 */
|
||||||
|
{
|
||||||
rc = fsync(fd);
|
rc = fsync(fd);
|
||||||
|
}
|
||||||
#endif /* defined(F_FULLFSYNC) */
|
#endif /* defined(F_FULLFSYNC) */
|
||||||
#endif /* defined(SQLITE_NO_SYNC) */
|
#endif /* defined(SQLITE_NO_SYNC) */
|
||||||
|
|
||||||
|
@ -835,6 +846,10 @@ static int full_fsync(int fd, int fullSync){
|
||||||
/*
|
/*
|
||||||
** Make sure all writes to a particular file are committed to disk.
|
** Make sure all writes to a particular file are committed to disk.
|
||||||
**
|
**
|
||||||
|
** If dataOnly==0 then both the file itself and its metadata (file
|
||||||
|
** size, access time, etc) are synced. If dataOnly!=0 then only the
|
||||||
|
** file data is synced.
|
||||||
|
**
|
||||||
** Under Unix, also make sure that the directory entry for the file
|
** Under Unix, also make sure that the directory entry for the file
|
||||||
** has been created by fsync-ing the directory that contains the file.
|
** has been created by fsync-ing the directory that contains the file.
|
||||||
** If we do not do this and we encounter a power failure, the directory
|
** If we do not do this and we encounter a power failure, the directory
|
||||||
|
@ -843,16 +858,16 @@ static int full_fsync(int fd, int fullSync){
|
||||||
** the directory entry for the journal was never created) and the transaction
|
** the directory entry for the journal was never created) and the transaction
|
||||||
** will not roll back - possibly leading to database corruption.
|
** will not roll back - possibly leading to database corruption.
|
||||||
*/
|
*/
|
||||||
int sqlite3OsSync(OsFile *id){
|
int sqlite3OsSync(OsFile *id, int dataOnly){
|
||||||
assert( id->isOpen );
|
assert( id->isOpen );
|
||||||
SimulateIOError(SQLITE_IOERR);
|
SimulateIOError(SQLITE_IOERR);
|
||||||
TRACE2("SYNC %-3d\n", id->h);
|
TRACE2("SYNC %-3d\n", id->h);
|
||||||
if( full_fsync(id->h, id->fullSync) ){
|
if( full_fsync(id->h, id->fullSync, dataOnly) ){
|
||||||
return SQLITE_IOERR;
|
return SQLITE_IOERR;
|
||||||
}
|
}
|
||||||
if( id->dirfd>=0 ){
|
if( id->dirfd>=0 ){
|
||||||
TRACE2("DIRSYNC %-3d\n", id->dirfd);
|
TRACE2("DIRSYNC %-3d\n", id->dirfd);
|
||||||
full_fsync(id->dirfd, id->fullSync);
|
full_fsync(id->dirfd, id->fullSync, 0);
|
||||||
close(id->dirfd); /* Only need to sync once, so close the directory */
|
close(id->dirfd); /* Only need to sync once, so close the directory */
|
||||||
id->dirfd = -1; /* when we are done. */
|
id->dirfd = -1; /* when we are done. */
|
||||||
}
|
}
|
||||||
|
@ -1310,10 +1325,14 @@ char *sqlite3OsFullPathname(const char *zRelative){
|
||||||
if( zRelative[0]=='/' ){
|
if( zRelative[0]=='/' ){
|
||||||
sqlite3SetString(&zFull, zRelative, (char*)0);
|
sqlite3SetString(&zFull, zRelative, (char*)0);
|
||||||
}else{
|
}else{
|
||||||
char zBuf[5000];
|
char *zBuf = sqliteMalloc(5000);
|
||||||
|
if( zBuf==0 ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
zBuf[0] = 0;
|
zBuf[0] = 0;
|
||||||
sqlite3SetString(&zFull, getcwd(zBuf, sizeof(zBuf)), "/", zRelative,
|
sqlite3SetString(&zFull, getcwd(zBuf, 5000), "/", zRelative,
|
||||||
(char*)0);
|
(char*)0);
|
||||||
|
sqliteFree(zBuf);
|
||||||
}
|
}
|
||||||
return zFull;
|
return zFull;
|
||||||
}
|
}
|
||||||
|
@ -1420,9 +1439,16 @@ int sqlite3_current_time = 0;
|
||||||
** return 0. Return 1 if the time and date cannot be found.
|
** return 0. Return 1 if the time and date cannot be found.
|
||||||
*/
|
*/
|
||||||
int sqlite3OsCurrentTime(double *prNow){
|
int sqlite3OsCurrentTime(double *prNow){
|
||||||
|
#ifdef NO_GETTOD
|
||||||
time_t t;
|
time_t t;
|
||||||
time(&t);
|
time(&t);
|
||||||
*prNow = t/86400.0 + 2440587.5;
|
*prNow = t/86400.0 + 2440587.5;
|
||||||
|
#else
|
||||||
|
struct timeval sNow;
|
||||||
|
struct timezone sTz; /* Not used */
|
||||||
|
gettimeofday(&sNow, &sTz);
|
||||||
|
*prNow = 2440587.5 + sNow.tv_sec/86400.0 + sNow.tv_usec/86400000000.0;
|
||||||
|
#endif
|
||||||
#ifdef SQLITE_TEST
|
#ifdef SQLITE_TEST
|
||||||
if( sqlite3_current_time ){
|
if( sqlite3_current_time ){
|
||||||
*prNow = sqlite3_current_time/86400.0 + 2440587.5;
|
*prNow = sqlite3_current_time/86400.0 + 2440587.5;
|
||||||
|
|
|
@ -41,11 +41,99 @@
|
||||||
*/
|
*/
|
||||||
#ifndef SQLITE_OMIT_DISKIO
|
#ifndef SQLITE_OMIT_DISKIO
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following variable is (normally) set once and never changes
|
||||||
|
** thereafter. It records whether the operating system is Win95
|
||||||
|
** or WinNT.
|
||||||
|
**
|
||||||
|
** 0: Operating system unknown.
|
||||||
|
** 1: Operating system is Win95.
|
||||||
|
** 2: Operating system is WinNT.
|
||||||
|
**
|
||||||
|
** In order to facilitate testing on a WinNT system, the test fixture
|
||||||
|
** can manually set this value to 1 to emulate Win98 behavior.
|
||||||
|
*/
|
||||||
|
int sqlite3_os_type = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
|
||||||
|
** Return false (zero) for Win95, Win98, or WinME.
|
||||||
|
**
|
||||||
|
** Here is an interesting observation: Win95, Win98, and WinME lack
|
||||||
|
** the LockFileEx() API. But we can still statically link against that
|
||||||
|
** API as long as we don't call it win running Win95/98/ME. A call to
|
||||||
|
** this routine is used to determine if the host is Win95/98/ME or
|
||||||
|
** WinNT/2K/XP so that we will know whether or not we can safely call
|
||||||
|
** the LockFileEx() API.
|
||||||
|
*/
|
||||||
|
static int isNT(void){
|
||||||
|
if( sqlite3_os_type==0 ){
|
||||||
|
OSVERSIONINFO sInfo;
|
||||||
|
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
|
||||||
|
GetVersionEx(&sInfo);
|
||||||
|
sqlite3_os_type = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
|
||||||
|
}
|
||||||
|
return sqlite3_os_type==2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Convert a UTF-8 string to UTF-32. Space to hold the returned string
|
||||||
|
** is obtained from sqliteMalloc.
|
||||||
|
*/
|
||||||
|
static WCHAR *utf8ToUnicode(const char *zFilename){
|
||||||
|
int nByte;
|
||||||
|
WCHAR *zWideFilename;
|
||||||
|
|
||||||
|
if( !isNT() ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, NULL, 0)*sizeof(WCHAR);
|
||||||
|
zWideFilename = sqliteMalloc( nByte*sizeof(zWideFilename[0]) );
|
||||||
|
if( zWideFilename==0 ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
nByte = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nByte);
|
||||||
|
if( nByte==0 ){
|
||||||
|
sqliteFree(zWideFilename);
|
||||||
|
zWideFilename = 0;
|
||||||
|
}
|
||||||
|
return zWideFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Convert UTF-32 to UTF-8. Space to hold the returned string is
|
||||||
|
** obtained from sqliteMalloc().
|
||||||
|
*/
|
||||||
|
static char *unicodeToUtf8(const WCHAR *zWideFilename){
|
||||||
|
int nByte;
|
||||||
|
char *zFilename;
|
||||||
|
|
||||||
|
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0);
|
||||||
|
zFilename = sqliteMalloc( nByte );
|
||||||
|
if( zFilename==0 ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte,
|
||||||
|
0, 0);
|
||||||
|
if( nByte == 0 ){
|
||||||
|
sqliteFree(zFilename);
|
||||||
|
zFilename = 0;
|
||||||
|
}
|
||||||
|
return zFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Delete the named file
|
** Delete the named file
|
||||||
*/
|
*/
|
||||||
int sqlite3OsDelete(const char *zFilename){
|
int sqlite3OsDelete(const char *zFilename){
|
||||||
|
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||||
|
if( zWide ){
|
||||||
|
DeleteFileW(zWide);
|
||||||
|
sqliteFree(zWide);
|
||||||
|
}else{
|
||||||
DeleteFileA(zFilename);
|
DeleteFileA(zFilename);
|
||||||
|
}
|
||||||
TRACE2("DELETE \"%s\"\n", zFilename);
|
TRACE2("DELETE \"%s\"\n", zFilename);
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +142,15 @@ int sqlite3OsDelete(const char *zFilename){
|
||||||
** Return TRUE if the named file exists.
|
** Return TRUE if the named file exists.
|
||||||
*/
|
*/
|
||||||
int sqlite3OsFileExists(const char *zFilename){
|
int sqlite3OsFileExists(const char *zFilename){
|
||||||
return GetFileAttributesA(zFilename) != 0xffffffff;
|
int exists = 0;
|
||||||
|
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||||
|
if( zWide ){
|
||||||
|
exists = GetFileAttributesW(zWide) != 0xffffffff;
|
||||||
|
sqliteFree(zWide);
|
||||||
|
}else{
|
||||||
|
exists = GetFileAttributesA(zFilename) != 0xffffffff;
|
||||||
|
}
|
||||||
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -76,7 +172,36 @@ int sqlite3OsOpenReadWrite(
|
||||||
int *pReadonly
|
int *pReadonly
|
||||||
){
|
){
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
|
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||||
assert( !id->isOpen );
|
assert( !id->isOpen );
|
||||||
|
if( zWide ){
|
||||||
|
h = CreateFileW(zWide,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
NULL,
|
||||||
|
OPEN_ALWAYS,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if( h==INVALID_HANDLE_VALUE ){
|
||||||
|
h = CreateFileW(zWide,
|
||||||
|
GENERIC_READ,
|
||||||
|
FILE_SHARE_READ,
|
||||||
|
NULL,
|
||||||
|
OPEN_ALWAYS,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if( h==INVALID_HANDLE_VALUE ){
|
||||||
|
sqliteFree(zWide);
|
||||||
|
return SQLITE_CANTOPEN;
|
||||||
|
}
|
||||||
|
*pReadonly = 1;
|
||||||
|
}else{
|
||||||
|
*pReadonly = 0;
|
||||||
|
}
|
||||||
|
sqliteFree(zWide);
|
||||||
|
}else{
|
||||||
h = CreateFileA(zFilename,
|
h = CreateFileA(zFilename,
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||||
|
@ -101,6 +226,7 @@ int sqlite3OsOpenReadWrite(
|
||||||
}else{
|
}else{
|
||||||
*pReadonly = 0;
|
*pReadonly = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
id->h = h;
|
id->h = h;
|
||||||
id->locktype = NO_LOCK;
|
id->locktype = NO_LOCK;
|
||||||
id->sharedLockByte = 0;
|
id->sharedLockByte = 0;
|
||||||
|
@ -128,6 +254,7 @@ int sqlite3OsOpenReadWrite(
|
||||||
int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
int fileflags;
|
int fileflags;
|
||||||
|
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||||
assert( !id->isOpen );
|
assert( !id->isOpen );
|
||||||
if( delFlag ){
|
if( delFlag ){
|
||||||
fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS
|
fileflags = FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_RANDOM_ACCESS
|
||||||
|
@ -135,6 +262,17 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||||
}else{
|
}else{
|
||||||
fileflags = FILE_FLAG_RANDOM_ACCESS;
|
fileflags = FILE_FLAG_RANDOM_ACCESS;
|
||||||
}
|
}
|
||||||
|
if( zWide ){
|
||||||
|
h = CreateFileW(zWide,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
CREATE_ALWAYS,
|
||||||
|
fileflags,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
sqliteFree(zWide);
|
||||||
|
}else{
|
||||||
h = CreateFileA(zFilename,
|
h = CreateFileA(zFilename,
|
||||||
GENERIC_READ | GENERIC_WRITE,
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
0,
|
0,
|
||||||
|
@ -143,6 +281,7 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||||
fileflags,
|
fileflags,
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
}
|
||||||
if( h==INVALID_HANDLE_VALUE ){
|
if( h==INVALID_HANDLE_VALUE ){
|
||||||
return SQLITE_CANTOPEN;
|
return SQLITE_CANTOPEN;
|
||||||
}
|
}
|
||||||
|
@ -164,7 +303,19 @@ int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){
|
||||||
*/
|
*/
|
||||||
int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
|
int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
|
WCHAR *zWide = utf8ToUnicode(zFilename);
|
||||||
assert( !id->isOpen );
|
assert( !id->isOpen );
|
||||||
|
if( zWide ){
|
||||||
|
h = CreateFileW(zWide,
|
||||||
|
GENERIC_READ,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
sqliteFree(zWide);
|
||||||
|
}else{
|
||||||
h = CreateFileA(zFilename,
|
h = CreateFileA(zFilename,
|
||||||
GENERIC_READ,
|
GENERIC_READ,
|
||||||
0,
|
0,
|
||||||
|
@ -173,6 +324,7 @@ int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){
|
||||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||||||
NULL
|
NULL
|
||||||
);
|
);
|
||||||
|
}
|
||||||
if( h==INVALID_HANDLE_VALUE ){
|
if( h==INVALID_HANDLE_VALUE ){
|
||||||
return SQLITE_CANTOPEN;
|
return SQLITE_CANTOPEN;
|
||||||
}
|
}
|
||||||
|
@ -229,6 +381,16 @@ int sqlite3OsTempFileName(char *zBuf){
|
||||||
if( sqlite3_temp_directory ){
|
if( sqlite3_temp_directory ){
|
||||||
strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30);
|
strncpy(zTempPath, sqlite3_temp_directory, SQLITE_TEMPNAME_SIZE-30);
|
||||||
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
|
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
|
||||||
|
}else if( isNT() ){
|
||||||
|
char *zMulti;
|
||||||
|
WCHAR zWidePath[SQLITE_TEMPNAME_SIZE];
|
||||||
|
GetTempPathW(SQLITE_TEMPNAME_SIZE-30, zWidePath);
|
||||||
|
zMulti = unicodeToUtf8(zWidePath);
|
||||||
|
if( zMulti ){
|
||||||
|
strncpy(zTempPath, zMulti, SQLITE_TEMPNAME_SIZE-30);
|
||||||
|
zTempPath[SQLITE_TEMPNAME_SIZE-30] = 0;
|
||||||
|
sqliteFree(zMulti);
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath);
|
GetTempPathA(SQLITE_TEMPNAME_SIZE-30, zTempPath);
|
||||||
}
|
}
|
||||||
|
@ -303,6 +465,13 @@ int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Some microsoft compilers lack this definition.
|
||||||
|
*/
|
||||||
|
#ifndef INVALID_SET_FILE_POINTER
|
||||||
|
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Move the read/write pointer in a file.
|
** Move the read/write pointer in a file.
|
||||||
*/
|
*/
|
||||||
|
@ -311,16 +480,22 @@ int sqlite3OsSeek(OsFile *id, i64 offset){
|
||||||
LONG lowerBits = offset & 0xffffffff;
|
LONG lowerBits = offset & 0xffffffff;
|
||||||
DWORD rc;
|
DWORD rc;
|
||||||
assert( id->isOpen );
|
assert( id->isOpen );
|
||||||
|
#ifdef SQLITE_TEST
|
||||||
|
if( offset ) SimulateDiskfullError
|
||||||
|
#endif
|
||||||
SEEK(offset/1024 + 1);
|
SEEK(offset/1024 + 1);
|
||||||
rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
|
rc = SetFilePointer(id->h, lowerBits, &upperBits, FILE_BEGIN);
|
||||||
TRACE3("SEEK %d %lld\n", id->h, offset);
|
TRACE3("SEEK %d %lld\n", id->h, offset);
|
||||||
|
if( rc==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR ){
|
||||||
|
return SQLITE_FULL;
|
||||||
|
}
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Make sure all writes to a particular file are committed to disk.
|
** Make sure all writes to a particular file are committed to disk.
|
||||||
*/
|
*/
|
||||||
int sqlite3OsSync(OsFile *id){
|
int sqlite3OsSync(OsFile *id, int dataOnly){
|
||||||
assert( id->isOpen );
|
assert( id->isOpen );
|
||||||
TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
|
TRACE3("SYNC %d lock=%d\n", id->h, id->locktype);
|
||||||
if( FlushFileBuffers(id->h) ){
|
if( FlushFileBuffers(id->h) ){
|
||||||
|
@ -364,28 +539,6 @@ int sqlite3OsFileSize(OsFile *id, i64 *pSize){
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** Return true (non-zero) if we are running under WinNT, Win2K or WinXP.
|
|
||||||
** Return false (zero) for Win95, Win98, or WinME.
|
|
||||||
**
|
|
||||||
** Here is an interesting observation: Win95, Win98, and WinME lack
|
|
||||||
** the LockFileEx() API. But we can still statically link against that
|
|
||||||
** API as long as we don't call it win running Win95/98/ME. A call to
|
|
||||||
** this routine is used to determine if the host is Win95/98/ME or
|
|
||||||
** WinNT/2K/XP so that we will know whether or not we can safely call
|
|
||||||
** the LockFileEx() API.
|
|
||||||
*/
|
|
||||||
static int isNT(void){
|
|
||||||
static int osType = 0; /* 0=unknown 1=win95 2=winNT */
|
|
||||||
if( osType==0 ){
|
|
||||||
OSVERSIONINFO sInfo;
|
|
||||||
sInfo.dwOSVersionInfoSize = sizeof(sInfo);
|
|
||||||
GetVersionEx(&sInfo);
|
|
||||||
osType = sInfo.dwPlatformId==VER_PLATFORM_WIN32_NT ? 2 : 1;
|
|
||||||
}
|
|
||||||
return osType==2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Acquire a reader lock.
|
** Acquire a reader lock.
|
||||||
** Different API routines are called depending on whether or not this
|
** Different API routines are called depending on whether or not this
|
||||||
|
@ -426,11 +579,18 @@ static int unlockReadLock(OsFile *id){
|
||||||
** Check that a given pathname is a directory and is writable
|
** Check that a given pathname is a directory and is writable
|
||||||
**
|
**
|
||||||
*/
|
*/
|
||||||
int sqlite3OsIsDirWritable(char *zBuf){
|
int sqlite3OsIsDirWritable(char *zDirname){
|
||||||
int fileAttr;
|
int fileAttr;
|
||||||
if(! zBuf ) return 0;
|
WCHAR *zWide;
|
||||||
if(! isNT() && strlen(zBuf) > MAX_PATH ) return 0;
|
if( zDirname==0 ) return 0;
|
||||||
fileAttr = GetFileAttributesA(zBuf);
|
if( !isNT() && strlen(zDirname)>MAX_PATH ) return 0;
|
||||||
|
zWide = utf8ToUnicode(zDirname);
|
||||||
|
if( zWide ){
|
||||||
|
fileAttr = GetFileAttributesW(zWide);
|
||||||
|
sqliteFree(zWide);
|
||||||
|
}else{
|
||||||
|
fileAttr = GetFileAttributesA(zDirname);
|
||||||
|
}
|
||||||
if( fileAttr == 0xffffffff ) return 0;
|
if( fileAttr == 0xffffffff ) return 0;
|
||||||
if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
|
if( (fileAttr & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY ){
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -641,6 +801,7 @@ int sqlite3OsUnlock(OsFile *id, int locktype){
|
||||||
char *sqlite3OsFullPathname(const char *zRelative){
|
char *sqlite3OsFullPathname(const char *zRelative){
|
||||||
char *zNotUsed;
|
char *zNotUsed;
|
||||||
char *zFull;
|
char *zFull;
|
||||||
|
WCHAR *zWide;
|
||||||
int nByte;
|
int nByte;
|
||||||
#ifdef __CYGWIN__
|
#ifdef __CYGWIN__
|
||||||
nByte = strlen(zRelative) + MAX_PATH + 1001;
|
nByte = strlen(zRelative) + MAX_PATH + 1001;
|
||||||
|
@ -648,10 +809,22 @@ char *sqlite3OsFullPathname(const char *zRelative){
|
||||||
if( zFull==0 ) return 0;
|
if( zFull==0 ) return 0;
|
||||||
if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0;
|
if( cygwin_conv_to_full_win32_path(zRelative, zFull) ) return 0;
|
||||||
#else
|
#else
|
||||||
|
zWide = utf8ToUnicode(zRelative);
|
||||||
|
if( zWide ){
|
||||||
|
WCHAR *zTemp, *zNotUsedW;
|
||||||
|
nByte = GetFullPathNameW(zWide, 0, 0, &zNotUsedW) + 1;
|
||||||
|
zTemp = sqliteMalloc( nByte*sizeof(zTemp[0]) );
|
||||||
|
if( zTemp==0 ) return 0;
|
||||||
|
GetFullPathNameW(zWide, nByte, zTemp, &zNotUsedW);
|
||||||
|
sqliteFree(zWide);
|
||||||
|
zFull = unicodeToUtf8(zTemp);
|
||||||
|
sqliteFree(zTemp);
|
||||||
|
}else{
|
||||||
nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
|
nByte = GetFullPathNameA(zRelative, 0, 0, &zNotUsed) + 1;
|
||||||
zFull = sqliteMalloc( nByte );
|
zFull = sqliteMalloc( nByte*sizeof(zFull[0]) );
|
||||||
if( zFull==0 ) return 0;
|
if( zFull==0 ) return 0;
|
||||||
GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
|
GetFullPathNameA(zRelative, nByte, zFull, &zNotUsed);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return zFull;
|
return zFull;
|
||||||
}
|
}
|
||||||
|
|
|
@ -657,9 +657,11 @@ static int writeJournalHdr(Pager *pPager){
|
||||||
** file descriptor to the end of the journal header sector.
|
** file descriptor to the end of the journal header sector.
|
||||||
*/
|
*/
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1);
|
rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff-1);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3OsWrite(&pPager->jfd, "\000", 1);
|
rc = sqlite3OsWrite(&pPager->jfd, "\000", 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1038,8 +1040,10 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
|
||||||
assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
|
assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 );
|
||||||
TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
|
TRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno);
|
||||||
if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
|
if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){
|
||||||
sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
|
rc = sqlite3OsWrite(&pPager->fd, aData, pPager->pageSize);
|
||||||
|
}
|
||||||
if( pPg ) pPg->dirty = 0;
|
if( pPg ) pPg->dirty = 0;
|
||||||
}
|
}
|
||||||
if( pPg ){
|
if( pPg ){
|
||||||
|
@ -1168,8 +1172,10 @@ static int pager_reload_cache(Pager *pPager){
|
||||||
char zBuf[SQLITE_MAX_PAGE_SIZE];
|
char zBuf[SQLITE_MAX_PAGE_SIZE];
|
||||||
if( !pPg->dirty ) continue;
|
if( !pPg->dirty ) continue;
|
||||||
if( (int)pPg->pgno <= pPager->origDbSize ){
|
if( (int)pPg->pgno <= pPager->origDbSize ){
|
||||||
sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
|
rc = sqlite3OsSeek(&pPager->fd, pPager->pageSize*(i64)(pPg->pgno-1));
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
|
rc = sqlite3OsRead(&pPager->fd, zBuf, pPager->pageSize);
|
||||||
|
}
|
||||||
TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
|
TRACE3("REFETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||||
if( rc ) break;
|
if( rc ) break;
|
||||||
CODEC(pPager, zBuf, pPg->pgno, 2);
|
CODEC(pPager, zBuf, pPg->pgno, 2);
|
||||||
|
@ -1485,7 +1491,7 @@ static int pager_stmt_playback(Pager *pPager){
|
||||||
end_stmt_playback:
|
end_stmt_playback:
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
pPager->errMask |= PAGER_ERR_CORRUPT;
|
pPager->errMask |= PAGER_ERR_CORRUPT;
|
||||||
rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
rc = SQLITE_CORRUPT;
|
||||||
}else{
|
}else{
|
||||||
pPager->journalOff = szJ;
|
pPager->journalOff = szJ;
|
||||||
/* pager_reload_cache(pPager); */
|
/* pager_reload_cache(pPager); */
|
||||||
|
@ -1747,13 +1753,18 @@ void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){
|
||||||
/*
|
/*
|
||||||
** Return the total number of pages in the disk file associated with
|
** Return the total number of pages in the disk file associated with
|
||||||
** pPager.
|
** pPager.
|
||||||
|
**
|
||||||
|
** If the PENDING_BYTE lies on the page directly after the end of the
|
||||||
|
** file, then consider this page part of the file too. For example, if
|
||||||
|
** PENDING_BYTE is byte 4096 (the first byte of page 5) and the size of the
|
||||||
|
** file is 4096 bytes, 5 is returned instead of 4.
|
||||||
*/
|
*/
|
||||||
int sqlite3pager_pagecount(Pager *pPager){
|
int sqlite3pager_pagecount(Pager *pPager){
|
||||||
i64 n;
|
i64 n;
|
||||||
assert( pPager!=0 );
|
assert( pPager!=0 );
|
||||||
if( pPager->dbSize>=0 ){
|
if( pPager->dbSize>=0 ){
|
||||||
return pPager->dbSize;
|
n = pPager->dbSize;
|
||||||
}
|
} else {
|
||||||
if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
|
if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){
|
||||||
pPager->errMask |= PAGER_ERR_DISK;
|
pPager->errMask |= PAGER_ERR_DISK;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1763,12 +1774,13 @@ int sqlite3pager_pagecount(Pager *pPager){
|
||||||
}else{
|
}else{
|
||||||
n /= pPager->pageSize;
|
n /= pPager->pageSize;
|
||||||
}
|
}
|
||||||
if( !MEMDB && n==PENDING_BYTE/pPager->pageSize ){
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
if( pPager->state!=PAGER_UNLOCK ){
|
if( pPager->state!=PAGER_UNLOCK ){
|
||||||
pPager->dbSize = n;
|
pPager->dbSize = n;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if( n==(PENDING_BYTE/pPager->pageSize) ){
|
||||||
|
n++;
|
||||||
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2121,17 +2133,20 @@ static int syncJournal(Pager *pPager){
|
||||||
*/
|
*/
|
||||||
if( pPager->fullSync ){
|
if( pPager->fullSync ){
|
||||||
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
|
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
|
||||||
rc = sqlite3OsSync(&pPager->jfd);
|
rc = sqlite3OsSync(&pPager->jfd, 0);
|
||||||
if( rc!=0 ) return rc;
|
if( rc!=0 ) return rc;
|
||||||
}
|
}
|
||||||
sqlite3OsSeek(&pPager->jfd, pPager->journalHdr + sizeof(aJournalMagic));
|
rc = sqlite3OsSeek(&pPager->jfd,
|
||||||
|
pPager->journalHdr + sizeof(aJournalMagic));
|
||||||
|
if( rc ) return rc;
|
||||||
rc = write32bits(&pPager->jfd, pPager->nRec);
|
rc = write32bits(&pPager->jfd, pPager->nRec);
|
||||||
if( rc ) return rc;
|
if( rc ) return rc;
|
||||||
|
|
||||||
sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
|
rc = sqlite3OsSeek(&pPager->jfd, pPager->journalOff);
|
||||||
|
if( rc ) return rc;
|
||||||
}
|
}
|
||||||
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
|
TRACE2("SYNC journal of %d\n", PAGERID(pPager));
|
||||||
rc = sqlite3OsSync(&pPager->jfd);
|
rc = sqlite3OsSync(&pPager->jfd, pPager->fullSync);
|
||||||
if( rc!=0 ) return rc;
|
if( rc!=0 ) return rc;
|
||||||
pPager->journalStarted = 1;
|
pPager->journalStarted = 1;
|
||||||
}
|
}
|
||||||
|
@ -2196,7 +2211,8 @@ static int pager_write_pagelist(PgHdr *pList){
|
||||||
|
|
||||||
while( pList ){
|
while( pList ){
|
||||||
assert( pList->dirty );
|
assert( pList->dirty );
|
||||||
sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
|
rc = sqlite3OsSeek(&pPager->fd, (pList->pgno-1)*(i64)pPager->pageSize);
|
||||||
|
if( rc ) return rc;
|
||||||
/* If there are dirty pages in the page cache with page numbers greater
|
/* If there are dirty pages in the page cache with page numbers greater
|
||||||
** than Pager.dbSize, this means sqlite3pager_truncate() was called to
|
** than Pager.dbSize, this means sqlite3pager_truncate() was called to
|
||||||
** make the file smaller (presumably by auto-vacuum code). Do not write
|
** make the file smaller (presumably by auto-vacuum code). Do not write
|
||||||
|
@ -2291,8 +2307,8 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||||
/* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
|
/* The maximum page number is 2^31. Return SQLITE_CORRUPT if a page
|
||||||
** number greater than this, or zero, is requested.
|
** number greater than this, or zero, is requested.
|
||||||
*/
|
*/
|
||||||
if( pgno>PAGER_MAX_PGNO || pgno==0 ){
|
if( pgno>PAGER_MAX_PGNO || pgno==0 || pgno==PAGER_MJ_PGNO(pPager) ){
|
||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure we have not hit any critical errors.
|
/* Make sure we have not hit any critical errors.
|
||||||
|
@ -2506,8 +2522,10 @@ int sqlite3pager_get(Pager *pPager, Pgno pgno, void **ppPage){
|
||||||
}else{
|
}else{
|
||||||
int rc;
|
int rc;
|
||||||
assert( MEMDB==0 );
|
assert( MEMDB==0 );
|
||||||
sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
rc = sqlite3OsSeek(&pPager->fd, (pgno-1)*(i64)pPager->pageSize);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
|
rc = sqlite3OsRead(&pPager->fd, PGHDR_TO_DATA(pPg), pPager->pageSize);
|
||||||
|
}
|
||||||
TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
|
TRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
|
||||||
CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
|
CODEC(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
|
@ -2815,6 +2833,10 @@ int sqlite3pager_write(void *pData){
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
u32 cksum;
|
u32 cksum;
|
||||||
|
/* We should never write to the journal file the page that
|
||||||
|
** contains the database locks. The following assert verifies
|
||||||
|
** that we do not. */
|
||||||
|
assert( pPg->pgno!=PAGER_MJ_PGNO(pPager) );
|
||||||
CODEC(pPager, pData, pPg->pgno, 7);
|
CODEC(pPager, pData, pPg->pgno, 7);
|
||||||
cksum = pager_cksum(pPager, pPg->pgno, pData);
|
cksum = pager_cksum(pPager, pPg->pgno, pData);
|
||||||
saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
|
saved = *(u32*)PGHDR_TO_EXTRA(pPg, pPager);
|
||||||
|
@ -3171,7 +3193,7 @@ int sqlite3pager_rollback(Pager *pPager){
|
||||||
rc = pager_playback(pPager);
|
rc = pager_playback(pPager);
|
||||||
}
|
}
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
pPager->errMask |= PAGER_ERR_CORRUPT;
|
pPager->errMask |= PAGER_ERR_CORRUPT;
|
||||||
}
|
}
|
||||||
pPager->dbSize = -1;
|
pPager->dbSize = -1;
|
||||||
|
@ -3441,8 +3463,9 @@ int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
|
||||||
*/
|
*/
|
||||||
Pgno i;
|
Pgno i;
|
||||||
void *pPage;
|
void *pPage;
|
||||||
|
int iSkip = PAGER_MJ_PGNO(pPager);
|
||||||
for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
|
for( i=nTrunc+1; i<=pPager->origDbSize; i++ ){
|
||||||
if( !(pPager->aInJournal[i/8] & (1<<(i&7))) ){
|
if( !(pPager->aInJournal[i/8] & (1<<(i&7))) && i!=iSkip ){
|
||||||
rc = sqlite3pager_get(pPager, i, &pPage);
|
rc = sqlite3pager_get(pPager, i, &pPage);
|
||||||
if( rc!=SQLITE_OK ) goto sync_exit;
|
if( rc!=SQLITE_OK ) goto sync_exit;
|
||||||
rc = sqlite3pager_write(pPage);
|
rc = sqlite3pager_write(pPage);
|
||||||
|
@ -3472,7 +3495,7 @@ int sqlite3pager_sync(Pager *pPager, const char *zMaster, Pgno nTrunc){
|
||||||
|
|
||||||
/* Sync the database file. */
|
/* Sync the database file. */
|
||||||
if( !pPager->noSync ){
|
if( !pPager->noSync ){
|
||||||
rc = sqlite3OsSync(&pPager->fd);
|
rc = sqlite3OsSync(&pPager->fd, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pPager->state = PAGER_SYNCED;
|
pPager->state = PAGER_SYNCED;
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
** reasonable, like 1024.
|
** reasonable, like 1024.
|
||||||
*/
|
*/
|
||||||
#ifndef SQLITE_MAX_PAGE_SIZE
|
#ifndef SQLITE_MAX_PAGE_SIZE
|
||||||
# define SQLITE_MAX_PAGE_SIZE 8192
|
# define SQLITE_MAX_PAGE_SIZE 32768
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -6,137 +6,140 @@
|
||||||
#define TK_FUNCTION 6
|
#define TK_FUNCTION 6
|
||||||
#define TK_COLUMN 7
|
#define TK_COLUMN 7
|
||||||
#define TK_AGG_FUNCTION 8
|
#define TK_AGG_FUNCTION 8
|
||||||
#define TK_CONST_FUNC 9
|
#define TK_AGG_COLUMN 9
|
||||||
#define TK_SEMI 10
|
#define TK_CONST_FUNC 10
|
||||||
#define TK_EXPLAIN 11
|
#define TK_SEMI 11
|
||||||
#define TK_BEGIN 12
|
#define TK_EXPLAIN 12
|
||||||
#define TK_TRANSACTION 13
|
#define TK_QUERY 13
|
||||||
#define TK_DEFERRED 14
|
#define TK_PLAN 14
|
||||||
#define TK_IMMEDIATE 15
|
#define TK_BEGIN 15
|
||||||
#define TK_EXCLUSIVE 16
|
#define TK_TRANSACTION 16
|
||||||
#define TK_COMMIT 17
|
#define TK_DEFERRED 17
|
||||||
#define TK_END 18
|
#define TK_IMMEDIATE 18
|
||||||
#define TK_ROLLBACK 19
|
#define TK_EXCLUSIVE 19
|
||||||
#define TK_CREATE 20
|
#define TK_COMMIT 20
|
||||||
#define TK_TABLE 21
|
#define TK_END 21
|
||||||
#define TK_TEMP 22
|
#define TK_ROLLBACK 22
|
||||||
#define TK_LP 23
|
#define TK_CREATE 23
|
||||||
#define TK_RP 24
|
#define TK_TABLE 24
|
||||||
#define TK_AS 25
|
#define TK_TEMP 25
|
||||||
#define TK_COMMA 26
|
#define TK_LP 26
|
||||||
#define TK_ID 27
|
#define TK_RP 27
|
||||||
#define TK_ABORT 28
|
#define TK_AS 28
|
||||||
#define TK_AFTER 29
|
#define TK_COMMA 29
|
||||||
#define TK_ANALYZE 30
|
#define TK_ID 30
|
||||||
#define TK_ASC 31
|
#define TK_ABORT 31
|
||||||
#define TK_ATTACH 32
|
#define TK_AFTER 32
|
||||||
#define TK_BEFORE 33
|
#define TK_ANALYZE 33
|
||||||
#define TK_CASCADE 34
|
#define TK_ASC 34
|
||||||
#define TK_CAST 35
|
#define TK_ATTACH 35
|
||||||
#define TK_CONFLICT 36
|
#define TK_BEFORE 36
|
||||||
#define TK_DATABASE 37
|
#define TK_CASCADE 37
|
||||||
#define TK_DESC 38
|
#define TK_CAST 38
|
||||||
#define TK_DETACH 39
|
#define TK_CONFLICT 39
|
||||||
#define TK_EACH 40
|
#define TK_DATABASE 40
|
||||||
#define TK_FAIL 41
|
#define TK_DESC 41
|
||||||
#define TK_FOR 42
|
#define TK_DETACH 42
|
||||||
#define TK_IGNORE 43
|
#define TK_EACH 43
|
||||||
#define TK_INITIALLY 44
|
#define TK_FAIL 44
|
||||||
#define TK_INSTEAD 45
|
#define TK_FOR 45
|
||||||
#define TK_LIKE_KW 46
|
#define TK_IGNORE 46
|
||||||
#define TK_MATCH 47
|
#define TK_INITIALLY 47
|
||||||
#define TK_KEY 48
|
#define TK_INSTEAD 48
|
||||||
#define TK_OF 49
|
#define TK_LIKE_KW 49
|
||||||
#define TK_OFFSET 50
|
#define TK_MATCH 50
|
||||||
#define TK_PRAGMA 51
|
#define TK_KEY 51
|
||||||
#define TK_RAISE 52
|
#define TK_OF 52
|
||||||
#define TK_REPLACE 53
|
#define TK_OFFSET 53
|
||||||
#define TK_RESTRICT 54
|
#define TK_PRAGMA 54
|
||||||
#define TK_ROW 55
|
#define TK_RAISE 55
|
||||||
#define TK_STATEMENT 56
|
#define TK_REPLACE 56
|
||||||
#define TK_TRIGGER 57
|
#define TK_RESTRICT 57
|
||||||
#define TK_VACUUM 58
|
#define TK_ROW 58
|
||||||
#define TK_VIEW 59
|
#define TK_STATEMENT 59
|
||||||
#define TK_REINDEX 60
|
#define TK_TRIGGER 60
|
||||||
#define TK_RENAME 61
|
#define TK_VACUUM 61
|
||||||
#define TK_CTIME_KW 62
|
#define TK_VIEW 62
|
||||||
#define TK_ALTER 63
|
#define TK_REINDEX 63
|
||||||
#define TK_OR 64
|
#define TK_RENAME 64
|
||||||
#define TK_AND 65
|
#define TK_CTIME_KW 65
|
||||||
#define TK_NOT 66
|
#define TK_ALTER 66
|
||||||
#define TK_IS 67
|
#define TK_OR 67
|
||||||
#define TK_BETWEEN 68
|
#define TK_AND 68
|
||||||
#define TK_IN 69
|
#define TK_NOT 69
|
||||||
#define TK_ISNULL 70
|
#define TK_IS 70
|
||||||
#define TK_NOTNULL 71
|
#define TK_BETWEEN 71
|
||||||
#define TK_NE 72
|
#define TK_IN 72
|
||||||
#define TK_EQ 73
|
#define TK_ISNULL 73
|
||||||
#define TK_GT 74
|
#define TK_NOTNULL 74
|
||||||
#define TK_LE 75
|
#define TK_NE 75
|
||||||
#define TK_LT 76
|
#define TK_EQ 76
|
||||||
#define TK_GE 77
|
#define TK_GT 77
|
||||||
#define TK_ESCAPE 78
|
#define TK_LE 78
|
||||||
#define TK_BITAND 79
|
#define TK_LT 79
|
||||||
#define TK_BITOR 80
|
#define TK_GE 80
|
||||||
#define TK_LSHIFT 81
|
#define TK_ESCAPE 81
|
||||||
#define TK_RSHIFT 82
|
#define TK_BITAND 82
|
||||||
#define TK_PLUS 83
|
#define TK_BITOR 83
|
||||||
#define TK_MINUS 84
|
#define TK_LSHIFT 84
|
||||||
#define TK_STAR 85
|
#define TK_RSHIFT 85
|
||||||
#define TK_SLASH 86
|
#define TK_PLUS 86
|
||||||
#define TK_REM 87
|
#define TK_MINUS 87
|
||||||
#define TK_CONCAT 88
|
#define TK_STAR 88
|
||||||
#define TK_UMINUS 89
|
#define TK_SLASH 89
|
||||||
#define TK_UPLUS 90
|
#define TK_REM 90
|
||||||
#define TK_BITNOT 91
|
#define TK_CONCAT 91
|
||||||
#define TK_STRING 92
|
#define TK_UMINUS 92
|
||||||
#define TK_JOIN_KW 93
|
#define TK_UPLUS 93
|
||||||
#define TK_CONSTRAINT 94
|
#define TK_BITNOT 94
|
||||||
#define TK_DEFAULT 95
|
#define TK_STRING 95
|
||||||
#define TK_NULL 96
|
#define TK_JOIN_KW 96
|
||||||
#define TK_PRIMARY 97
|
#define TK_CONSTRAINT 97
|
||||||
#define TK_UNIQUE 98
|
#define TK_DEFAULT 98
|
||||||
#define TK_CHECK 99
|
#define TK_NULL 99
|
||||||
#define TK_REFERENCES 100
|
#define TK_PRIMARY 100
|
||||||
#define TK_COLLATE 101
|
#define TK_UNIQUE 101
|
||||||
#define TK_AUTOINCR 102
|
#define TK_CHECK 102
|
||||||
#define TK_ON 103
|
#define TK_REFERENCES 103
|
||||||
#define TK_DELETE 104
|
#define TK_COLLATE 104
|
||||||
#define TK_UPDATE 105
|
#define TK_AUTOINCR 105
|
||||||
#define TK_INSERT 106
|
#define TK_ON 106
|
||||||
#define TK_SET 107
|
#define TK_DELETE 107
|
||||||
#define TK_DEFERRABLE 108
|
#define TK_UPDATE 108
|
||||||
#define TK_FOREIGN 109
|
#define TK_INSERT 109
|
||||||
#define TK_DROP 110
|
#define TK_SET 110
|
||||||
#define TK_UNION 111
|
#define TK_DEFERRABLE 111
|
||||||
#define TK_ALL 112
|
#define TK_FOREIGN 112
|
||||||
#define TK_INTERSECT 113
|
#define TK_DROP 113
|
||||||
#define TK_EXCEPT 114
|
#define TK_UNION 114
|
||||||
#define TK_SELECT 115
|
#define TK_ALL 115
|
||||||
#define TK_DISTINCT 116
|
#define TK_INTERSECT 116
|
||||||
#define TK_DOT 117
|
#define TK_EXCEPT 117
|
||||||
#define TK_FROM 118
|
#define TK_SELECT 118
|
||||||
#define TK_JOIN 119
|
#define TK_DISTINCT 119
|
||||||
#define TK_USING 120
|
#define TK_DOT 120
|
||||||
#define TK_ORDER 121
|
#define TK_FROM 121
|
||||||
#define TK_BY 122
|
#define TK_JOIN 122
|
||||||
#define TK_GROUP 123
|
#define TK_USING 123
|
||||||
#define TK_HAVING 124
|
#define TK_ORDER 124
|
||||||
#define TK_LIMIT 125
|
#define TK_BY 125
|
||||||
#define TK_WHERE 126
|
#define TK_GROUP 126
|
||||||
#define TK_INTO 127
|
#define TK_HAVING 127
|
||||||
#define TK_VALUES 128
|
#define TK_LIMIT 128
|
||||||
#define TK_INTEGER 129
|
#define TK_WHERE 129
|
||||||
#define TK_FLOAT 130
|
#define TK_INTO 130
|
||||||
#define TK_BLOB 131
|
#define TK_VALUES 131
|
||||||
#define TK_REGISTER 132
|
#define TK_INTEGER 132
|
||||||
#define TK_VARIABLE 133
|
#define TK_FLOAT 133
|
||||||
#define TK_EXISTS 134
|
#define TK_BLOB 134
|
||||||
#define TK_CASE 135
|
#define TK_REGISTER 135
|
||||||
#define TK_WHEN 136
|
#define TK_VARIABLE 136
|
||||||
#define TK_THEN 137
|
#define TK_EXISTS 137
|
||||||
#define TK_ELSE 138
|
#define TK_CASE 138
|
||||||
#define TK_INDEX 139
|
#define TK_WHEN 139
|
||||||
#define TK_TO 140
|
#define TK_THEN 140
|
||||||
#define TK_ADD 141
|
#define TK_ELSE 141
|
||||||
#define TK_COLUMNKW 142
|
#define TK_INDEX 142
|
||||||
|
#define TK_TO 143
|
||||||
|
#define TK_ADD 144
|
||||||
|
#define TK_COLUMNKW 145
|
||||||
|
|
|
@ -93,7 +93,7 @@ struct AttachKey { int type; Token key; };
|
||||||
// add them to the parse.h output file.
|
// add them to the parse.h output file.
|
||||||
//
|
//
|
||||||
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
|
%nonassoc END_OF_FILE ILLEGAL SPACE UNCLOSED_STRING COMMENT FUNCTION
|
||||||
COLUMN AGG_FUNCTION CONST_FUNC.
|
COLUMN AGG_FUNCTION AGG_COLUMN CONST_FUNC.
|
||||||
|
|
||||||
// Input is a single SQL command
|
// Input is a single SQL command
|
||||||
input ::= cmdlist.
|
input ::= cmdlist.
|
||||||
|
@ -105,6 +105,7 @@ ecmd ::= explain cmdx SEMI.
|
||||||
explain ::= . { sqlite3BeginParse(pParse, 0); }
|
explain ::= . { sqlite3BeginParse(pParse, 0); }
|
||||||
%ifndef SQLITE_OMIT_EXPLAIN
|
%ifndef SQLITE_OMIT_EXPLAIN
|
||||||
explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
|
explain ::= EXPLAIN. { sqlite3BeginParse(pParse, 1); }
|
||||||
|
explain ::= EXPLAIN QUERY PLAN. { sqlite3BeginParse(pParse, 2); }
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
///////////////////// Begin and end transactions. ////////////////////////////
|
///////////////////// Begin and end transactions. ////////////////////////////
|
||||||
|
@ -172,7 +173,7 @@ id(A) ::= ID(X). {A = X;}
|
||||||
%fallback ID
|
%fallback ID
|
||||||
ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
|
ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
|
||||||
DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
|
DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
|
||||||
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH KEY
|
IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH PLAN QUERY KEY
|
||||||
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
|
OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
|
||||||
TEMP TRIGGER VACUUM VIEW
|
TEMP TRIGGER VACUUM VIEW
|
||||||
%ifdef SQLITE_OMIT_COMPOUND_SELECT
|
%ifdef SQLITE_OMIT_COMPOUND_SELECT
|
||||||
|
@ -660,9 +661,12 @@ expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
|
||||||
sqlite3ExprSpan(A,&X,&Y);
|
sqlite3ExprSpan(A,&X,&Y);
|
||||||
}
|
}
|
||||||
%endif // SQLITE_OMIT_CAST
|
%endif // SQLITE_OMIT_CAST
|
||||||
expr(A) ::= ID(X) LP exprlist(Y) RP(E). {
|
expr(A) ::= ID(X) LP distinct(D) exprlist(Y) RP(E). {
|
||||||
A = sqlite3ExprFunction(Y, &X);
|
A = sqlite3ExprFunction(Y, &X);
|
||||||
sqlite3ExprSpan(A,&X,&E);
|
sqlite3ExprSpan(A,&X,&E);
|
||||||
|
if( D ){
|
||||||
|
A->flags |= EP_Distinct;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
expr(A) ::= ID(X) LP STAR RP(E). {
|
expr(A) ::= ID(X) LP STAR RP(E). {
|
||||||
A = sqlite3ExprFunction(0, &X);
|
A = sqlite3ExprFunction(0, &X);
|
||||||
|
@ -752,7 +756,11 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||||
ExprList *pList = sqlite3ExprListAppend(0, X, 0);
|
ExprList *pList = sqlite3ExprListAppend(0, X, 0);
|
||||||
pList = sqlite3ExprListAppend(pList, Y, 0);
|
pList = sqlite3ExprListAppend(pList, Y, 0);
|
||||||
A = sqlite3Expr(TK_BETWEEN, W, 0, 0);
|
A = sqlite3Expr(TK_BETWEEN, W, 0, 0);
|
||||||
if( A ) A->pList = pList;
|
if( A ){
|
||||||
|
A->pList = pList;
|
||||||
|
}else{
|
||||||
|
sqlite3ExprListDelete(pList);
|
||||||
|
}
|
||||||
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
|
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
|
||||||
sqlite3ExprSpan(A,&W->span,&Y->span);
|
sqlite3ExprSpan(A,&W->span,&Y->span);
|
||||||
}
|
}
|
||||||
|
@ -772,21 +780,31 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||||
}
|
}
|
||||||
expr(A) ::= LP(B) select(X) RP(E). {
|
expr(A) ::= LP(B) select(X) RP(E). {
|
||||||
A = sqlite3Expr(TK_SELECT, 0, 0, 0);
|
A = sqlite3Expr(TK_SELECT, 0, 0, 0);
|
||||||
if( A ) A->pSelect = X;
|
if( A ){
|
||||||
if( !A ) sqlite3SelectDelete(X);
|
A->pSelect = X;
|
||||||
|
}else{
|
||||||
|
sqlite3SelectDelete(X);
|
||||||
|
}
|
||||||
sqlite3ExprSpan(A,&B,&E);
|
sqlite3ExprSpan(A,&B,&E);
|
||||||
}
|
}
|
||||||
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
|
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] {
|
||||||
A = sqlite3Expr(TK_IN, X, 0, 0);
|
A = sqlite3Expr(TK_IN, X, 0, 0);
|
||||||
if( A ) A->pSelect = Y;
|
if( A ){
|
||||||
if( !A ) sqlite3SelectDelete(Y);
|
A->pSelect = Y;
|
||||||
|
}else{
|
||||||
|
sqlite3SelectDelete(Y);
|
||||||
|
}
|
||||||
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
|
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
|
||||||
sqlite3ExprSpan(A,&X->span,&E);
|
sqlite3ExprSpan(A,&X->span,&E);
|
||||||
}
|
}
|
||||||
expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] {
|
expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] {
|
||||||
SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z);
|
SrcList *pSrc = sqlite3SrcListAppend(0,&Y,&Z);
|
||||||
A = sqlite3Expr(TK_IN, X, 0, 0);
|
A = sqlite3Expr(TK_IN, X, 0, 0);
|
||||||
if( A ) A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
|
if( A ){
|
||||||
|
A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
|
||||||
|
}else{
|
||||||
|
sqlite3SrcListDelete(pSrc);
|
||||||
|
}
|
||||||
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
|
if( N ) A = sqlite3Expr(TK_NOT, A, 0, 0);
|
||||||
sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y);
|
sqlite3ExprSpan(A,&X->span,Z.z?&Z:&Y);
|
||||||
}
|
}
|
||||||
|
@ -795,15 +813,20 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
|
||||||
if( p ){
|
if( p ){
|
||||||
p->pSelect = Y;
|
p->pSelect = Y;
|
||||||
sqlite3ExprSpan(p,&B,&E);
|
sqlite3ExprSpan(p,&B,&E);
|
||||||
|
}else{
|
||||||
|
sqlite3SelectDelete(Y);
|
||||||
}
|
}
|
||||||
if( !p ) sqlite3SelectDelete(Y);
|
|
||||||
}
|
}
|
||||||
%endif // SQLITE_OMIT_SUBQUERY
|
%endif // SQLITE_OMIT_SUBQUERY
|
||||||
|
|
||||||
/* CASE expressions */
|
/* CASE expressions */
|
||||||
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
|
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
|
||||||
A = sqlite3Expr(TK_CASE, X, Z, 0);
|
A = sqlite3Expr(TK_CASE, X, Z, 0);
|
||||||
if( A ) A->pList = Y;
|
if( A ){
|
||||||
|
A->pList = Y;
|
||||||
|
}else{
|
||||||
|
sqlite3ExprListDelete(Y);
|
||||||
|
}
|
||||||
sqlite3ExprSpan(A, &C, &E);
|
sqlite3ExprSpan(A, &C, &E);
|
||||||
}
|
}
|
||||||
%type case_exprlist {ExprList*}
|
%type case_exprlist {ExprList*}
|
||||||
|
|
|
@ -626,14 +626,6 @@ void sqlite3Pragma(
|
||||||
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
|
if( sqlite3StrICmp(zLeft, "integrity_check")==0 ){
|
||||||
int i, j, addr;
|
int i, j, addr;
|
||||||
|
|
||||||
/* Code that initializes the integrity check program. Set the
|
|
||||||
** error count 0
|
|
||||||
*/
|
|
||||||
static const VdbeOpList initCode[] = {
|
|
||||||
{ OP_Integer, 0, 0, 0},
|
|
||||||
{ OP_MemStore, 0, 1, 0},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Code that appears at the end of the integrity check. If no error
|
/* Code that appears at the end of the integrity check. If no error
|
||||||
** messages have been generated, output OK. Otherwise output the
|
** messages have been generated, output OK. Otherwise output the
|
||||||
** error message
|
** error message
|
||||||
|
@ -650,7 +642,7 @@ void sqlite3Pragma(
|
||||||
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
|
||||||
sqlite3VdbeSetNumCols(v, 1);
|
sqlite3VdbeSetNumCols(v, 1);
|
||||||
sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC);
|
sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC);
|
||||||
sqlite3VdbeAddOpList(v, ArraySize(initCode), initCode);
|
sqlite3VdbeAddOp(v, OP_MemInt, 0, 0); /* Initialize error count to 0 */
|
||||||
|
|
||||||
/* Do an integrity check on each database file */
|
/* Do an integrity check on each database file */
|
||||||
for(i=0; i<db->nDb; i++){
|
for(i=0; i<db->nDb; i++){
|
||||||
|
@ -696,8 +688,7 @@ void sqlite3Pragma(
|
||||||
|
|
||||||
if( pTab->pIndex==0 ) continue;
|
if( pTab->pIndex==0 ) continue;
|
||||||
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
|
sqlite3OpenTableAndIndices(pParse, pTab, 1, OP_OpenRead);
|
||||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
sqlite3VdbeAddOp(v, OP_MemInt, 0, 1);
|
||||||
sqlite3VdbeAddOp(v, OP_MemStore, 1, 1);
|
|
||||||
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
|
loopTop = sqlite3VdbeAddOp(v, OP_Rewind, 1, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
|
sqlite3VdbeAddOp(v, OP_MemIncr, 1, 0);
|
||||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||||
|
@ -715,39 +706,38 @@ void sqlite3Pragma(
|
||||||
jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
|
jmp2 = sqlite3VdbeAddOp(v, OP_Found, j+2, 0);
|
||||||
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
|
addr = sqlite3VdbeAddOpList(v, ArraySize(idxErr), idxErr);
|
||||||
sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
|
sqlite3VdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
|
||||||
sqlite3VdbeChangeP2(v, jmp2, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, jmp2);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1);
|
sqlite3VdbeAddOp(v, OP_Next, 1, loopTop+1);
|
||||||
sqlite3VdbeChangeP2(v, loopTop, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, loopTop);
|
||||||
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
||||||
static const VdbeOpList cntIdx[] = {
|
static const VdbeOpList cntIdx[] = {
|
||||||
{ OP_Integer, 0, 0, 0},
|
{ OP_MemInt, 0, 2, 0},
|
||||||
{ OP_MemStore, 2, 1, 0},
|
{ OP_Rewind, 0, 0, 0}, /* 1 */
|
||||||
{ OP_Rewind, 0, 0, 0}, /* 2 */
|
|
||||||
{ OP_MemIncr, 2, 0, 0},
|
{ OP_MemIncr, 2, 0, 0},
|
||||||
{ OP_Next, 0, 0, 0}, /* 4 */
|
{ OP_Next, 0, 0, 0}, /* 3 */
|
||||||
{ OP_MemLoad, 1, 0, 0},
|
{ OP_MemLoad, 1, 0, 0},
|
||||||
{ OP_MemLoad, 2, 0, 0},
|
{ OP_MemLoad, 2, 0, 0},
|
||||||
{ OP_Eq, 0, 0, 0}, /* 7 */
|
{ OP_Eq, 0, 0, 0}, /* 6 */
|
||||||
{ OP_MemIncr, 0, 0, 0},
|
{ OP_MemIncr, 0, 0, 0},
|
||||||
{ OP_String8, 0, 0, "wrong # of entries in index "},
|
{ OP_String8, 0, 0, "wrong # of entries in index "},
|
||||||
{ OP_String8, 0, 0, 0}, /* 10 */
|
{ OP_String8, 0, 0, 0}, /* 9 */
|
||||||
{ OP_Concat, 0, 0, 0},
|
{ OP_Concat, 0, 0, 0},
|
||||||
{ OP_Callback, 1, 0, 0},
|
{ OP_Callback, 1, 0, 0},
|
||||||
};
|
};
|
||||||
if( pIdx->tnum==0 ) continue;
|
if( pIdx->tnum==0 ) continue;
|
||||||
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
|
addr = sqlite3VdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
|
||||||
sqlite3VdbeChangeP1(v, addr+2, j+2);
|
sqlite3VdbeChangeP1(v, addr+1, j+2);
|
||||||
sqlite3VdbeChangeP2(v, addr+2, addr+5);
|
sqlite3VdbeChangeP2(v, addr+1, addr+4);
|
||||||
sqlite3VdbeChangeP1(v, addr+4, j+2);
|
sqlite3VdbeChangeP1(v, addr+3, j+2);
|
||||||
sqlite3VdbeChangeP2(v, addr+4, addr+3);
|
sqlite3VdbeChangeP2(v, addr+3, addr+2);
|
||||||
sqlite3VdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx));
|
sqlite3VdbeJumpHere(v, addr+6);
|
||||||
sqlite3VdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC);
|
sqlite3VdbeChangeP3(v, addr+9, pIdx->zName, P3_STATIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
|
addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode);
|
||||||
sqlite3VdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
|
sqlite3VdbeJumpHere(v, addr+2);
|
||||||
}else
|
}else
|
||||||
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
#endif /* SQLITE_OMIT_INTEGRITY_CHECK */
|
||||||
|
|
||||||
|
@ -903,13 +893,13 @@ void sqlite3Pragma(
|
||||||
Btree *pBt;
|
Btree *pBt;
|
||||||
Pager *pPager;
|
Pager *pPager;
|
||||||
if( db->aDb[i].zName==0 ) continue;
|
if( db->aDb[i].zName==0 ) continue;
|
||||||
sqlite3VdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, P3_STATIC);
|
sqlite3VdbeOp3(v, OP_String8, 0, 0, db->aDb[i].zName, P3_STATIC);
|
||||||
pBt = db->aDb[i].pBt;
|
pBt = db->aDb[i].pBt;
|
||||||
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
|
if( pBt==0 || (pPager = sqlite3BtreePager(pBt))==0 ){
|
||||||
sqlite3VdbeOp3(v, OP_String, 0, 0, "closed", P3_STATIC);
|
sqlite3VdbeOp3(v, OP_String8, 0, 0, "closed", P3_STATIC);
|
||||||
}else{
|
}else{
|
||||||
int j = sqlite3pager_lockstate(pPager);
|
int j = sqlite3pager_lockstate(pPager);
|
||||||
sqlite3VdbeOp3(v, OP_String, 0, 0,
|
sqlite3VdbeOp3(v, OP_String8, 0, 0,
|
||||||
(j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
|
(j>=0 && j<=4) ? azLockName[j] : "unknown", P3_STATIC);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
|
sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
|
||||||
|
|
|
@ -458,6 +458,12 @@ int sqlite3_prepare(
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_EXPLAIN
|
#ifndef SQLITE_OMIT_EXPLAIN
|
||||||
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
|
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
|
||||||
|
if( sParse.explain==2 ){
|
||||||
|
sqlite3VdbeSetNumCols(sParse.pVdbe, 3);
|
||||||
|
sqlite3VdbeSetColName(sParse.pVdbe, 0, "order", P3_STATIC);
|
||||||
|
sqlite3VdbeSetColName(sParse.pVdbe, 1, "from", P3_STATIC);
|
||||||
|
sqlite3VdbeSetColName(sParse.pVdbe, 2, "detail", P3_STATIC);
|
||||||
|
}else{
|
||||||
sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
|
sqlite3VdbeSetNumCols(sParse.pVdbe, 5);
|
||||||
sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC);
|
sqlite3VdbeSetColName(sParse.pVdbe, 0, "addr", P3_STATIC);
|
||||||
sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC);
|
sqlite3VdbeSetColName(sParse.pVdbe, 1, "opcode", P3_STATIC);
|
||||||
|
@ -465,6 +471,7 @@ int sqlite3_prepare(
|
||||||
sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC);
|
sqlite3VdbeSetColName(sParse.pVdbe, 3, "p2", P3_STATIC);
|
||||||
sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC);
|
sqlite3VdbeSetColName(sParse.pVdbe, 4, "p3", P3_STATIC);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
prepare_out:
|
prepare_out:
|
||||||
|
|
|
@ -163,7 +163,15 @@ static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define etBUFSIZE 1000 /* Size of the output buffer */
|
/*
|
||||||
|
** On machines with a small stack size, you can redefine the
|
||||||
|
** SQLITE_PRINT_BUF_SIZE to be less than 350. But beware - for
|
||||||
|
** smaller values some %f conversions may go into an infinite loop.
|
||||||
|
*/
|
||||||
|
#ifndef SQLITE_PRINT_BUF_SIZE
|
||||||
|
# define SQLITE_PRINT_BUF_SIZE 350
|
||||||
|
#endif
|
||||||
|
#define etBUFSIZE SQLITE_PRINT_BUF_SIZE /* Size of the output buffer */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The root program. All variations call this core.
|
** The root program. All variations call this core.
|
||||||
|
@ -440,9 +448,9 @@ static int vxprintf(
|
||||||
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
|
/* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
|
||||||
exp = 0;
|
exp = 0;
|
||||||
if( realvalue>0.0 ){
|
if( realvalue>0.0 ){
|
||||||
while( realvalue>1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
|
while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
|
||||||
while( realvalue>1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
|
while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
|
||||||
while( realvalue>10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
|
while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }
|
||||||
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
|
while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; }
|
||||||
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
|
while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; }
|
||||||
if( exp>350 || exp<-350 ){
|
if( exp>350 || exp<-350 ){
|
||||||
|
@ -718,7 +726,11 @@ static void mout(void *arg, const char *zNewText, int nNewChar){
|
||||||
memcpy(pM->zText, pM->zBase, pM->nChar);
|
memcpy(pM->zText, pM->zBase, pM->nChar);
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
pM->zText = pM->xRealloc(pM->zText, pM->nAlloc);
|
char *zNew;
|
||||||
|
zNew = pM->xRealloc(pM->zText, pM->nAlloc);
|
||||||
|
if( zNew ){
|
||||||
|
pM->zText = zNew;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -756,7 +768,10 @@ static char *base_vprintf(
|
||||||
memcpy(sM.zText, sM.zBase, sM.nChar+1);
|
memcpy(sM.zText, sM.zBase, sM.nChar+1);
|
||||||
}
|
}
|
||||||
}else if( sM.nAlloc>sM.nChar+10 ){
|
}else if( sM.nAlloc>sM.nChar+10 ){
|
||||||
sM.zText = xRealloc(sM.zText, sM.nChar+1);
|
char *zNew = xRealloc(sM.zText, sM.nChar+1);
|
||||||
|
if( zNew ){
|
||||||
|
sM.zText = zNew;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sM.zText;
|
return sM.zText;
|
||||||
|
@ -774,7 +789,7 @@ static void *printf_realloc(void *old, int size){
|
||||||
** %-conversion extensions.
|
** %-conversion extensions.
|
||||||
*/
|
*/
|
||||||
char *sqlite3VMPrintf(const char *zFormat, va_list ap){
|
char *sqlite3VMPrintf(const char *zFormat, va_list ap){
|
||||||
char zBase[1000];
|
char zBase[SQLITE_PRINT_BUF_SIZE];
|
||||||
return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
|
return base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,7 +800,7 @@ char *sqlite3VMPrintf(const char *zFormat, va_list ap){
|
||||||
char *sqlite3MPrintf(const char *zFormat, ...){
|
char *sqlite3MPrintf(const char *zFormat, ...){
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char *z;
|
char *z;
|
||||||
char zBase[1000];
|
char zBase[SQLITE_PRINT_BUF_SIZE];
|
||||||
va_start(ap, zFormat);
|
va_start(ap, zFormat);
|
||||||
z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
|
z = base_vprintf(printf_realloc, 1, zBase, sizeof(zBase), zFormat, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -313,7 +313,7 @@ static void output_c_string(FILE *out, const char *z){
|
||||||
fputc('\\', out);
|
fputc('\\', out);
|
||||||
fputc('r', out);
|
fputc('r', out);
|
||||||
}else if( !isprint(c) ){
|
}else if( !isprint(c) ){
|
||||||
fprintf(out, "\\%03o", c);
|
fprintf(out, "\\%03o", c&0xff);
|
||||||
}else{
|
}else{
|
||||||
fputc(c, out);
|
fputc(c, out);
|
||||||
}
|
}
|
||||||
|
@ -656,10 +656,14 @@ static int dump_callback(void *pArg, int nArg, char **azArg, char **azCol){
|
||||||
zType = azArg[1];
|
zType = azArg[1];
|
||||||
zSql = azArg[2];
|
zSql = azArg[2];
|
||||||
|
|
||||||
if( strcmp(zTable,"sqlite_sequence")!=0 ){
|
if( strcmp(zTable, "sqlite_sequence")==0 ){
|
||||||
fprintf(p->out, "%s;\n", zSql);
|
|
||||||
}else{
|
|
||||||
fprintf(p->out, "DELETE FROM sqlite_sequence;\n");
|
fprintf(p->out, "DELETE FROM sqlite_sequence;\n");
|
||||||
|
}else if( strcmp(zTable, "sqlite_stat1")==0 ){
|
||||||
|
fprintf(p->out, "ANALYZE sqlite_master;\n");
|
||||||
|
}else if( strncmp(zTable, "sqlite_", 7)==0 ){
|
||||||
|
return 0;
|
||||||
|
}else{
|
||||||
|
fprintf(p->out, "%s;\n", zSql);
|
||||||
}
|
}
|
||||||
|
|
||||||
if( strcmp(zType, "table")==0 ){
|
if( strcmp(zType, "table")==0 ){
|
||||||
|
@ -1290,7 +1294,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||||
"SELECT sql FROM "
|
"SELECT sql FROM "
|
||||||
" (SELECT * FROM sqlite_master UNION ALL"
|
" (SELECT * FROM sqlite_master UNION ALL"
|
||||||
" SELECT * FROM sqlite_temp_master) "
|
" SELECT * FROM sqlite_temp_master) "
|
||||||
"WHERE type!='meta' AND sql NOTNULL "
|
"WHERE type!='meta' AND sql NOTNULL AND name NOT LIKE 'sqlite_%'"
|
||||||
"ORDER BY substr(type,2,1), name",
|
"ORDER BY substr(type,2,1), name",
|
||||||
callback, &data, &zErrMsg
|
callback, &data, &zErrMsg
|
||||||
);
|
);
|
||||||
|
@ -1334,7 +1338,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
|
||||||
if( nArg==1 ){
|
if( nArg==1 ){
|
||||||
rc = sqlite3_get_table(p->db,
|
rc = sqlite3_get_table(p->db,
|
||||||
"SELECT name FROM sqlite_master "
|
"SELECT name FROM sqlite_master "
|
||||||
"WHERE type IN ('table','view') "
|
"WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%'"
|
||||||
"UNION ALL "
|
"UNION ALL "
|
||||||
"SELECT name FROM sqlite_temp_master "
|
"SELECT name FROM sqlite_temp_master "
|
||||||
"WHERE type IN ('table','view') "
|
"WHERE type IN ('table','view') "
|
||||||
|
@ -1698,6 +1702,13 @@ int main(int argc, char **argv){
|
||||||
}
|
}
|
||||||
data.out = stdout;
|
data.out = stdout;
|
||||||
|
|
||||||
|
#ifdef SQLITE_OMIT_MEMORYDB
|
||||||
|
if( data.zDbFilename==0 ){
|
||||||
|
fprintf(stderr,"%s: no database filename specified\n", argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Go ahead and open the database file if it already exists. If the
|
/* Go ahead and open the database file if it already exists. If the
|
||||||
** file does not exist, delay opening it. This prevents empty database
|
** file does not exist, delay opening it. This prevents empty database
|
||||||
** files from being created if a user mistypes the database name argument
|
** files from being created if a user mistypes the database name argument
|
||||||
|
|
|
@ -373,8 +373,9 @@ void sqlite3_free_table(char **result);
|
||||||
**
|
**
|
||||||
** We can use this text in an SQL statement as follows:
|
** We can use this text in an SQL statement as follows:
|
||||||
**
|
**
|
||||||
** sqlite3_exec_printf(db, "INSERT INTO table VALUES('%q')",
|
** char *z = sqlite3_mprintf("INSERT INTO TABLES('%q')", zText);
|
||||||
** callback1, 0, 0, zText);
|
** sqlite3_exec(db, z, callback1, 0, 0);
|
||||||
|
** sqlite3_free(z);
|
||||||
**
|
**
|
||||||
** Because the %q format string is used, the '\'' character in zText
|
** Because the %q format string is used, the '\'' character in zText
|
||||||
** is escaped and the SQL generated is as follows:
|
** is escaped and the SQL generated is as follows:
|
||||||
|
@ -464,11 +465,18 @@ int sqlite3_set_authorizer(
|
||||||
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
|
#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Register a function that is called at every invocation of sqlite3_exec()
|
** Register a function for tracing SQL command evaluation. The function
|
||||||
** or sqlite3_prepare(). This function can be used (for example) to generate
|
** registered by sqlite3_trace() is invoked at the first sqlite3_step()
|
||||||
** a log file of all SQL executed against a database.
|
** for the evaluation of an SQL statement. The function registered by
|
||||||
|
** sqlite3_profile() runs at the end of each SQL statement and includes
|
||||||
|
** information on how long that statement ran.
|
||||||
|
**
|
||||||
|
** The sqlite3_profile() API is currently considered experimental and
|
||||||
|
** is subject to change.
|
||||||
*/
|
*/
|
||||||
void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
|
void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
|
||||||
|
void *sqlite3_profile(sqlite3*,
|
||||||
|
void(*xProfile)(void*,const char*,sqlite_uint64), void*);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This routine configures a callback function - the progress callback - that
|
** This routine configures a callback function - the progress callback - that
|
||||||
|
|
|
@ -16,6 +16,17 @@
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Many people are failing to set -DNDEBUG=1 when compiling SQLite.
|
||||||
|
** Setting NDEBUG makes the code smaller and run faster. So the following
|
||||||
|
** lines are added to automatically set NDEBUG unless the -DSQLITE_DEBUG=1
|
||||||
|
** option is set. Thus NDEBUG becomes an opt-in rather than an opt-out
|
||||||
|
** feature.
|
||||||
|
*/
|
||||||
|
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
|
||||||
|
# define NDEBUG 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** These #defines should enable >2GB file support on Posix if the
|
** These #defines should enable >2GB file support on Posix if the
|
||||||
** underlying operating system supports it. If the OS lacks
|
** underlying operating system supports it. If the OS lacks
|
||||||
|
@ -298,7 +309,7 @@ extern int sqlite3_iMallocReset; /* Set iMallocFail to this when it reaches 0 */
|
||||||
/*
|
/*
|
||||||
** Forward references to structures
|
** Forward references to structures
|
||||||
*/
|
*/
|
||||||
typedef struct AggExpr AggExpr;
|
typedef struct AggInfo AggInfo;
|
||||||
typedef struct AuthContext AuthContext;
|
typedef struct AuthContext AuthContext;
|
||||||
typedef struct CollSeq CollSeq;
|
typedef struct CollSeq CollSeq;
|
||||||
typedef struct Column Column;
|
typedef struct Column Column;
|
||||||
|
@ -422,6 +433,8 @@ struct sqlite3 {
|
||||||
int activeVdbeCnt; /* Number of vdbes currently executing */
|
int activeVdbeCnt; /* Number of vdbes currently executing */
|
||||||
void (*xTrace)(void*,const char*); /* Trace function */
|
void (*xTrace)(void*,const char*); /* Trace function */
|
||||||
void *pTraceArg; /* Argument to the trace function */
|
void *pTraceArg; /* Argument to the trace function */
|
||||||
|
void (*xProfile)(void*,const char*,u64); /* Profiling function */
|
||||||
|
void *pProfileArg; /* Argument to profile function */
|
||||||
void *pCommitArg; /* Argument to xCommitCallback() */
|
void *pCommitArg; /* Argument to xCommitCallback() */
|
||||||
int (*xCommitCallback)(void*);/* Invoked at every commit. */
|
int (*xCommitCallback)(void*);/* Invoked at every commit. */
|
||||||
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
|
void(*xCollNeeded)(void*,sqlite3*,int eTextRep,const char*);
|
||||||
|
@ -511,7 +524,8 @@ struct FuncDef {
|
||||||
/*
|
/*
|
||||||
** Possible values for FuncDef.flags
|
** Possible values for FuncDef.flags
|
||||||
*/
|
*/
|
||||||
#define SQLITE_FUNC_LIKEOPT 0x01 /* Candidate for the LIKE optimization */
|
#define SQLITE_FUNC_LIKE 0x01 /* Candidate for the LIKE optimization */
|
||||||
|
#define SQLITE_FUNC_CASE 0x02 /* Case-sensitive LIKE-type function */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** information about each column of an SQL table is held in an instance
|
** information about each column of an SQL table is held in an instance
|
||||||
|
@ -551,10 +565,19 @@ struct Column {
|
||||||
struct CollSeq {
|
struct CollSeq {
|
||||||
char *zName; /* Name of the collating sequence, UTF-8 encoded */
|
char *zName; /* Name of the collating sequence, UTF-8 encoded */
|
||||||
u8 enc; /* Text encoding handled by xCmp() */
|
u8 enc; /* Text encoding handled by xCmp() */
|
||||||
|
u8 type; /* One of the SQLITE_COLL_... values below */
|
||||||
void *pUser; /* First argument to xCmp() */
|
void *pUser; /* First argument to xCmp() */
|
||||||
int (*xCmp)(void*,int, const void*, int, const void*);
|
int (*xCmp)(void*,int, const void*, int, const void*);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Allowed values of CollSeq flags:
|
||||||
|
*/
|
||||||
|
#define SQLITE_COLL_BINARY 1 /* The default memcmp() collating sequence */
|
||||||
|
#define SQLITE_COLL_NOCASE 2 /* The built-in NOCASE collating sequence */
|
||||||
|
#define SQLITE_COLL_REVERSE 3 /* The built-in REVERSE collating sequence */
|
||||||
|
#define SQLITE_COLL_USER 0 /* Any other user-defined collating sequence */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A sort order can be either ASC or DESC.
|
** A sort order can be either ASC or DESC.
|
||||||
*/
|
*/
|
||||||
|
@ -776,6 +799,49 @@ struct Token {
|
||||||
unsigned n : 31; /* Number of characters in this token */
|
unsigned n : 31; /* Number of characters in this token */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** An instance of this structure contains information needed to generate
|
||||||
|
** code for a SELECT that contains aggregate functions.
|
||||||
|
**
|
||||||
|
** If Expr.op==TK_AGG_COLUMN or TK_AGG_FUNCTION then Expr.pAggInfo is a
|
||||||
|
** pointer to this structure. The Expr.iColumn field is the index in
|
||||||
|
** AggInfo.aCol[] or AggInfo.aFunc[] of information needed to generate
|
||||||
|
** code for that node.
|
||||||
|
**
|
||||||
|
** AggInfo.pGroupBy and AggInfo.aFunc.pExpr point to fields within the
|
||||||
|
** original Select structure that describes the SELECT statement. These
|
||||||
|
** fields do not need to be freed when deallocating the AggInfo structure.
|
||||||
|
*/
|
||||||
|
struct AggInfo {
|
||||||
|
u8 directMode; /* Direct rendering mode means take data directly
|
||||||
|
** from source tables rather than from accumulators */
|
||||||
|
u8 useSortingIdx; /* In direct mode, reference the sorting index rather
|
||||||
|
** than the source table */
|
||||||
|
int sortingIdx; /* Cursor number of the sorting index */
|
||||||
|
ExprList *pGroupBy; /* The group by clause */
|
||||||
|
int nSortingColumn; /* Number of columns in the sorting index */
|
||||||
|
struct AggInfo_col { /* For each column used in source tables */
|
||||||
|
int iTable; /* Cursor number of the source table */
|
||||||
|
int iColumn; /* Column number within the source table */
|
||||||
|
int iSorterColumn; /* Column number in the sorting index */
|
||||||
|
int iMem; /* Memory location that acts as accumulator */
|
||||||
|
Expr *pExpr; /* The original expression */
|
||||||
|
} *aCol;
|
||||||
|
int nColumn; /* Number of used entries in aCol[] */
|
||||||
|
int nColumnAlloc; /* Number of slots allocated for aCol[] */
|
||||||
|
int nAccumulator; /* Number of columns that show through to the output.
|
||||||
|
** Additional columns are used only as parameters to
|
||||||
|
** aggregate functions */
|
||||||
|
struct AggInfo_func { /* For each aggregate function */
|
||||||
|
Expr *pExpr; /* Expression encoding the function */
|
||||||
|
FuncDef *pFunc; /* The aggregate function implementation */
|
||||||
|
int iMem; /* Memory location that acts as accumulator */
|
||||||
|
int iDistinct; /* Virtual table used to enforce DISTINCT */
|
||||||
|
} *aFunc;
|
||||||
|
int nFunc; /* Number of entries in aFunc[] */
|
||||||
|
int nFuncAlloc; /* Number of slots allocated for aFunc[] */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Each node of an expression in the parse tree is an instance
|
** Each node of an expression in the parse tree is an instance
|
||||||
** of this structure.
|
** of this structure.
|
||||||
|
@ -835,9 +901,9 @@ struct Expr {
|
||||||
Token span; /* Complete text of the expression */
|
Token span; /* Complete text of the expression */
|
||||||
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
|
int iTable, iColumn; /* When op==TK_COLUMN, then this expr node means the
|
||||||
** iColumn-th field of the iTable-th table. */
|
** iColumn-th field of the iTable-th table. */
|
||||||
int iAgg; /* When op==TK_COLUMN and pParse->fillAgg==FALSE, pull
|
AggInfo *pAggInfo; /* Used by TK_AGG_COLUMN and TK_AGG_FUNCTION */
|
||||||
** result from the iAgg-th element of the aggregator */
|
int iAgg; /* Which entry in pAggInfo->aCol[] or ->aFunc[] */
|
||||||
int iAggCtx; /* The value to pass as P1 of OP_AggGet. */
|
int iRightJoinTable; /* If EP_FromJoin, the right table of the join */
|
||||||
Select *pSelect; /* When the expression is a sub-select. Also the
|
Select *pSelect; /* When the expression is a sub-select. Also the
|
||||||
** right side of "<expr> IN (<select>)" */
|
** right side of "<expr> IN (<select>)" */
|
||||||
Table *pTab; /* Table for OP_Column expressions. */
|
Table *pTab; /* Table for OP_Column expressions. */
|
||||||
|
@ -850,7 +916,7 @@ struct Expr {
|
||||||
#define EP_Agg 0x02 /* Contains one or more aggregate functions */
|
#define EP_Agg 0x02 /* Contains one or more aggregate functions */
|
||||||
#define EP_Resolved 0x04 /* IDs have been resolved to COLUMNs */
|
#define EP_Resolved 0x04 /* IDs have been resolved to COLUMNs */
|
||||||
#define EP_Error 0x08 /* Expression contains one or more errors */
|
#define EP_Error 0x08 /* Expression contains one or more errors */
|
||||||
#define EP_Not 0x10 /* Operator preceeded by NOT */
|
#define EP_Distinct 0x10 /* Aggregate function with DISTINCT keyword */
|
||||||
#define EP_VarSelect 0x20 /* pSelect is correlated, not constant */
|
#define EP_VarSelect 0x20 /* pSelect is correlated, not constant */
|
||||||
#define EP_Dequoted 0x40 /* True if the string has been dequoted */
|
#define EP_Dequoted 0x40 /* True if the string has been dequoted */
|
||||||
|
|
||||||
|
@ -874,6 +940,7 @@ struct Expr {
|
||||||
struct ExprList {
|
struct ExprList {
|
||||||
int nExpr; /* Number of expressions on the list */
|
int nExpr; /* Number of expressions on the list */
|
||||||
int nAlloc; /* Number of entries allocated below */
|
int nAlloc; /* Number of entries allocated below */
|
||||||
|
int iECursor; /* VDBE Cursor associated with this ExprList */
|
||||||
struct ExprList_item {
|
struct ExprList_item {
|
||||||
Expr *pExpr; /* The list of expressions */
|
Expr *pExpr; /* The list of expressions */
|
||||||
char *zName; /* Token associated with this expression */
|
char *zName; /* Token associated with this expression */
|
||||||
|
@ -899,12 +966,12 @@ struct ExprList {
|
||||||
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
|
** If "a" is the k-th column of table "t", then IdList.a[0].idx==k.
|
||||||
*/
|
*/
|
||||||
struct IdList {
|
struct IdList {
|
||||||
int nId; /* Number of identifiers on the list */
|
|
||||||
int nAlloc; /* Number of entries allocated for a[] below */
|
|
||||||
struct IdList_item {
|
struct IdList_item {
|
||||||
char *zName; /* Name of the identifier */
|
char *zName; /* Name of the identifier */
|
||||||
int idx; /* Index in some Table.aCol[] of a column named zName */
|
int idx; /* Index in some Table.aCol[] of a column named zName */
|
||||||
} *a;
|
} *a;
|
||||||
|
int nId; /* Number of identifiers on the list */
|
||||||
|
int nAlloc; /* Number of entries allocated for a[] below */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -944,11 +1011,12 @@ struct SrcList {
|
||||||
** Permitted values of the SrcList.a.jointype field
|
** Permitted values of the SrcList.a.jointype field
|
||||||
*/
|
*/
|
||||||
#define JT_INNER 0x0001 /* Any kind of inner or cross join */
|
#define JT_INNER 0x0001 /* Any kind of inner or cross join */
|
||||||
#define JT_NATURAL 0x0002 /* True for a "natural" join */
|
#define JT_CROSS 0x0002 /* Explicit use of the CROSS keyword */
|
||||||
#define JT_LEFT 0x0004 /* Left outer join */
|
#define JT_NATURAL 0x0004 /* True for a "natural" join */
|
||||||
#define JT_RIGHT 0x0008 /* Right outer join */
|
#define JT_LEFT 0x0008 /* Left outer join */
|
||||||
#define JT_OUTER 0x0010 /* The "OUTER" keyword is present */
|
#define JT_RIGHT 0x0010 /* Right outer join */
|
||||||
#define JT_ERROR 0x0020 /* unknown or unsupported join type */
|
#define JT_OUTER 0x0020 /* The "OUTER" keyword is present */
|
||||||
|
#define JT_ERROR 0x0040 /* unknown or unsupported join type */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** For each nested loop in a WHERE clause implementation, the WhereInfo
|
** For each nested loop in a WHERE clause implementation, the WhereInfo
|
||||||
|
@ -1018,8 +1086,9 @@ struct NameContext {
|
||||||
int nRef; /* Number of names resolved by this context */
|
int nRef; /* Number of names resolved by this context */
|
||||||
int nErr; /* Number of errors encountered while resolving names */
|
int nErr; /* Number of errors encountered while resolving names */
|
||||||
u8 allowAgg; /* Aggregate functions allowed here */
|
u8 allowAgg; /* Aggregate functions allowed here */
|
||||||
u8 hasAgg;
|
u8 hasAgg; /* True if aggregates are seen */
|
||||||
int nDepth; /* Depth of subquery recursion. 1 for no recursion */
|
int nDepth; /* Depth of subquery recursion. 1 for no recursion */
|
||||||
|
AggInfo *pAggInfo; /* Information about aggregates at this level */
|
||||||
NameContext *pNext; /* Next outer name context. NULL for outermost */
|
NameContext *pNext; /* Next outer name context. NULL for outermost */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1032,64 +1101,55 @@ struct NameContext {
|
||||||
** limit and nOffset to the value of the offset (or 0 if there is not
|
** limit and nOffset to the value of the offset (or 0 if there is not
|
||||||
** offset). But later on, nLimit and nOffset become the memory locations
|
** offset). But later on, nLimit and nOffset become the memory locations
|
||||||
** in the VDBE that record the limit and offset counters.
|
** in the VDBE that record the limit and offset counters.
|
||||||
|
**
|
||||||
|
** addrOpenVirt[] entries contain the address of OP_OpenVirtual opcodes.
|
||||||
|
** These addresses must be stored so that we can go back and fill in
|
||||||
|
** the P3_KEYINFO and P2 parameters later. Neither the KeyInfo nor
|
||||||
|
** the number of columns in P2 can be computed at the same time
|
||||||
|
** as the OP_OpenVirtual instruction is coded because not
|
||||||
|
** enough information about the compound query is known at that point.
|
||||||
|
** The KeyInfo for addrOpenVirt[0] and [1] contains collating sequences
|
||||||
|
** for the result set. The KeyInfo for addrOpenVirt[2] contains collating
|
||||||
|
** sequences for the ORDER BY clause.
|
||||||
*/
|
*/
|
||||||
struct Select {
|
struct Select {
|
||||||
ExprList *pEList; /* The fields of the result */
|
ExprList *pEList; /* The fields of the result */
|
||||||
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */
|
||||||
u8 isDistinct; /* True if the DISTINCT keyword is present */
|
u8 isDistinct; /* True if the DISTINCT keyword is present */
|
||||||
|
u8 isResolved; /* True once sqlite3SelectResolve() has run. */
|
||||||
|
u8 isAgg; /* True if this is an aggregate query */
|
||||||
|
u8 usesVirt; /* True if uses an OpenVirtual opcode */
|
||||||
|
u8 disallowOrderBy; /* Do not allow an ORDER BY to be attached if TRUE */
|
||||||
SrcList *pSrc; /* The FROM clause */
|
SrcList *pSrc; /* The FROM clause */
|
||||||
Expr *pWhere; /* The WHERE clause */
|
Expr *pWhere; /* The WHERE clause */
|
||||||
ExprList *pGroupBy; /* The GROUP BY clause */
|
ExprList *pGroupBy; /* The GROUP BY clause */
|
||||||
Expr *pHaving; /* The HAVING clause */
|
Expr *pHaving; /* The HAVING clause */
|
||||||
ExprList *pOrderBy; /* The ORDER BY clause */
|
ExprList *pOrderBy; /* The ORDER BY clause */
|
||||||
Select *pPrior; /* Prior select in a compound select statement */
|
Select *pPrior; /* Prior select in a compound select statement */
|
||||||
|
Select *pRightmost; /* Right-most select in a compound select statement */
|
||||||
Expr *pLimit; /* LIMIT expression. NULL means not used. */
|
Expr *pLimit; /* LIMIT expression. NULL means not used. */
|
||||||
Expr *pOffset; /* OFFSET expression. NULL means not used. */
|
Expr *pOffset; /* OFFSET expression. NULL means not used. */
|
||||||
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */
|
||||||
IdList **ppOpenVirtual;/* OP_OpenVirtual addresses used by multi-selects */
|
int addrOpenVirt[3]; /* OP_OpenVirtual opcodes related to this select */
|
||||||
u8 isResolved; /* True once sqlite3SelectResolve() has run. */
|
|
||||||
u8 isAgg; /* True if this is an aggregate query */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** The results of a select can be distributed in several ways.
|
** The results of a select can be distributed in several ways.
|
||||||
*/
|
*/
|
||||||
#define SRT_Callback 1 /* Invoke a callback with each row of result */
|
#define SRT_Union 1 /* Store result as keys in an index */
|
||||||
#define SRT_Mem 2 /* Store result in a memory cell */
|
#define SRT_Except 2 /* Remove result from a UNION index */
|
||||||
#define SRT_Set 3 /* Store result as unique keys in a table */
|
#define SRT_Discard 3 /* Do not save the results anywhere */
|
||||||
#define SRT_Union 5 /* Store result as keys in a table */
|
|
||||||
#define SRT_Except 6 /* Remove result from a UNION table */
|
|
||||||
#define SRT_Table 7 /* Store result as data with a unique key */
|
|
||||||
#define SRT_TempTable 8 /* Store result in a trasient table */
|
|
||||||
#define SRT_Discard 9 /* Do not save the results anywhere */
|
|
||||||
#define SRT_Sorter 10 /* Store results in the sorter */
|
|
||||||
#define SRT_Subroutine 11 /* Call a subroutine to handle results */
|
|
||||||
#define SRT_Exists 12 /* Put 0 or 1 in a memory cell */
|
|
||||||
|
|
||||||
/*
|
/* The ORDER BY clause is ignored for all of the above */
|
||||||
** When a SELECT uses aggregate functions (like "count(*)" or "avg(f1)")
|
#define IgnorableOrderby(X) (X<=SRT_Discard)
|
||||||
** we have to do some additional analysis of expressions. An instance
|
|
||||||
** of the following structure holds information about a single subexpression
|
#define SRT_Callback 4 /* Invoke a callback with each row of result */
|
||||||
** somewhere in the SELECT statement. An array of these structures holds
|
#define SRT_Mem 5 /* Store result in a memory cell */
|
||||||
** all the information we need to generate code for aggregate
|
#define SRT_Set 6 /* Store non-null results as keys in an index */
|
||||||
** expressions.
|
#define SRT_Table 7 /* Store result as data with an automatic rowid */
|
||||||
**
|
#define SRT_VirtualTab 8 /* Create virtual table and store like SRT_Table */
|
||||||
** Note that when analyzing a SELECT containing aggregates, both
|
#define SRT_Subroutine 9 /* Call a subroutine to handle results */
|
||||||
** non-aggregate field variables and aggregate functions are stored
|
#define SRT_Exists 10 /* Put 0 or 1 in a memory cell */
|
||||||
** in the AggExpr array of the Parser structure.
|
|
||||||
**
|
|
||||||
** The pExpr field points to an expression that is part of either the
|
|
||||||
** field list, the GROUP BY clause, the HAVING clause or the ORDER BY
|
|
||||||
** clause. The expression will be freed when those clauses are cleaned
|
|
||||||
** up. Do not try to delete the expression attached to AggExpr.pExpr.
|
|
||||||
**
|
|
||||||
** If AggExpr.pExpr==0, that means the expression is "count(*)".
|
|
||||||
*/
|
|
||||||
struct AggExpr {
|
|
||||||
int isAgg; /* if TRUE contains an aggregate function */
|
|
||||||
Expr *pExpr; /* The expression */
|
|
||||||
FuncDef *pFunc; /* Information about the aggregate function */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** An SQL parser context. A copy of this structure is passed through
|
** An SQL parser context. A copy of this structure is passed through
|
||||||
|
@ -1110,7 +1170,6 @@ struct Parse {
|
||||||
u8 nameClash; /* A permanent table name clashes with temp table name */
|
u8 nameClash; /* A permanent table name clashes with temp table name */
|
||||||
u8 checkSchema; /* Causes schema cookie check after an error */
|
u8 checkSchema; /* Causes schema cookie check after an error */
|
||||||
u8 nested; /* Number of nested calls to the parser/code generator */
|
u8 nested; /* Number of nested calls to the parser/code generator */
|
||||||
u8 fillAgg; /* If true, ignore the Expr.iAgg field. Normally false */
|
|
||||||
int nErr; /* Number of errors seen */
|
int nErr; /* Number of errors seen */
|
||||||
int nTab; /* Number of previously allocated VDBE cursors */
|
int nTab; /* Number of previously allocated VDBE cursors */
|
||||||
int nMem; /* Number of memory cells used so far */
|
int nMem; /* Number of memory cells used so far */
|
||||||
|
@ -1137,9 +1196,6 @@ struct Parse {
|
||||||
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
|
Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */
|
||||||
TriggerStack *trigStack; /* Trigger actions being coded */
|
TriggerStack *trigStack; /* Trigger actions being coded */
|
||||||
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
|
const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */
|
||||||
int nAgg; /* Number of aggregate expressions */
|
|
||||||
AggExpr *aAgg; /* An array of aggregate expressions */
|
|
||||||
int nMaxDepth; /* Maximum depth of subquery recursion */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1319,6 +1375,19 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
extern int sqlite3_always_code_trigger_setup;
|
extern int sqlite3_always_code_trigger_setup;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The SQLITE_CORRUPT_BKPT macro can be either a constant (for production
|
||||||
|
** builds) or a function call (for debugging). If it is a function call,
|
||||||
|
** it allows the operator to set a breakpoint at the spot where database
|
||||||
|
** corruption is first detected.
|
||||||
|
*/
|
||||||
|
#ifdef SQLITE_DEBUG
|
||||||
|
extern int sqlite3Corrupt(void);
|
||||||
|
# define SQLITE_CORRUPT_BKPT sqlite3Corrupt()
|
||||||
|
#else
|
||||||
|
# define SQLITE_CORRUPT_BKPT SQLITE_CORRUPT
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Internal function prototypes
|
** Internal function prototypes
|
||||||
*/
|
*/
|
||||||
|
@ -1346,6 +1415,7 @@ void sqlite3RealToSortable(double r, char *);
|
||||||
# define sqlite3CheckMemory(a,b)
|
# define sqlite3CheckMemory(a,b)
|
||||||
# define sqlite3MallocX sqlite3Malloc
|
# define sqlite3MallocX sqlite3Malloc
|
||||||
#endif
|
#endif
|
||||||
|
void sqlite3ReallocOrFree(void**,int);
|
||||||
void sqlite3FreeX(void*);
|
void sqlite3FreeX(void*);
|
||||||
void *sqlite3MallocX(int);
|
void *sqlite3MallocX(int);
|
||||||
char *sqlite3MPrintf(const char*, ...);
|
char *sqlite3MPrintf(const char*, ...);
|
||||||
|
@ -1396,6 +1466,7 @@ void sqlite3EndTable(Parse*,Token*,Token*,Select*);
|
||||||
void sqlite3DropTable(Parse*, SrcList*, int);
|
void sqlite3DropTable(Parse*, SrcList*, int);
|
||||||
void sqlite3DeleteTable(sqlite3*, Table*);
|
void sqlite3DeleteTable(sqlite3*, Table*);
|
||||||
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
|
void sqlite3Insert(Parse*, SrcList*, ExprList*, Select*, IdList*, int);
|
||||||
|
int sqlite3ArrayAllocate(void**,int,int);
|
||||||
IdList *sqlite3IdListAppend(IdList*, Token*);
|
IdList *sqlite3IdListAppend(IdList*, Token*);
|
||||||
int sqlite3IdListIndex(IdList*,const char*);
|
int sqlite3IdListIndex(IdList*,const char*);
|
||||||
SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*);
|
SrcList *sqlite3SrcListAppend(SrcList*, Token*, Token*);
|
||||||
|
@ -1440,6 +1511,7 @@ int sqlite3ExprCompare(Expr*, Expr*);
|
||||||
int sqliteFuncId(Token*);
|
int sqliteFuncId(Token*);
|
||||||
int sqlite3ExprResolveNames(NameContext *, Expr *);
|
int sqlite3ExprResolveNames(NameContext *, Expr *);
|
||||||
int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
int sqlite3ExprAnalyzeAggregates(NameContext*, Expr*);
|
||||||
|
int sqlite3ExprAnalyzeAggList(NameContext*,ExprList*);
|
||||||
Vdbe *sqlite3GetVdbe(Parse*);
|
Vdbe *sqlite3GetVdbe(Parse*);
|
||||||
void sqlite3Randomness(int, void*);
|
void sqlite3Randomness(int, void*);
|
||||||
void sqlite3RollbackAll(sqlite3*);
|
void sqlite3RollbackAll(sqlite3*);
|
||||||
|
@ -1557,7 +1629,7 @@ const void *sqlite3ValueText(sqlite3_value*, u8);
|
||||||
int sqlite3ValueBytes(sqlite3_value*, u8);
|
int sqlite3ValueBytes(sqlite3_value*, u8);
|
||||||
void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
|
void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*));
|
||||||
void sqlite3ValueFree(sqlite3_value*);
|
void sqlite3ValueFree(sqlite3_value*);
|
||||||
sqlite3_value *sqlite3ValueNew();
|
sqlite3_value *sqlite3ValueNew(void);
|
||||||
sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
|
sqlite3_value *sqlite3GetTransientValue(sqlite3*db);
|
||||||
int sqlite3ValueFromExpr(Expr *, u8, u8, sqlite3_value **);
|
int sqlite3ValueFromExpr(Expr *, u8, u8, sqlite3_value **);
|
||||||
void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
|
void sqlite3ValueApplyAffinity(sqlite3_value *, u8, u8);
|
||||||
|
@ -1583,7 +1655,7 @@ int sqlite3FindDb(sqlite3*, Token*);
|
||||||
void sqlite3AnalysisLoad(sqlite3*,int iDB);
|
void sqlite3AnalysisLoad(sqlite3*,int iDB);
|
||||||
void sqlite3DefaultRowEst(Index*);
|
void sqlite3DefaultRowEst(Index*);
|
||||||
void sqlite3RegisterLikeFunctions(sqlite3*, int);
|
void sqlite3RegisterLikeFunctions(sqlite3*, int);
|
||||||
int sqlite3IsLikeFunction(sqlite3*,Expr*,char*);
|
int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*);
|
||||||
|
|
||||||
#ifdef SQLITE_SSE
|
#ifdef SQLITE_SSE
|
||||||
#include "sseInt.h"
|
#include "sseInt.h"
|
||||||
|
|
|
@ -84,6 +84,7 @@ struct SqliteDb {
|
||||||
char *zBusy; /* The busy callback routine */
|
char *zBusy; /* The busy callback routine */
|
||||||
char *zCommit; /* The commit hook callback routine */
|
char *zCommit; /* The commit hook callback routine */
|
||||||
char *zTrace; /* The trace callback routine */
|
char *zTrace; /* The trace callback routine */
|
||||||
|
char *zProfile; /* The profile callback routine */
|
||||||
char *zProgress; /* The progress callback routine */
|
char *zProgress; /* The progress callback routine */
|
||||||
char *zAuth; /* The authorization callback routine */
|
char *zAuth; /* The authorization callback routine */
|
||||||
char *zNull; /* Text to substitute for an SQL NULL value */
|
char *zNull; /* Text to substitute for an SQL NULL value */
|
||||||
|
@ -190,6 +191,9 @@ static void DbDeleteCmd(void *db){
|
||||||
if( pDb->zTrace ){
|
if( pDb->zTrace ){
|
||||||
Tcl_Free(pDb->zTrace);
|
Tcl_Free(pDb->zTrace);
|
||||||
}
|
}
|
||||||
|
if( pDb->zProfile ){
|
||||||
|
Tcl_Free(pDb->zProfile);
|
||||||
|
}
|
||||||
if( pDb->zAuth ){
|
if( pDb->zAuth ){
|
||||||
Tcl_Free(pDb->zAuth);
|
Tcl_Free(pDb->zAuth);
|
||||||
}
|
}
|
||||||
|
@ -247,6 +251,25 @@ static void DbTraceHandler(void *cd, const char *zSql){
|
||||||
Tcl_ResetResult(pDb->interp);
|
Tcl_ResetResult(pDb->interp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** This routine is called by the SQLite profile handler after a statement
|
||||||
|
** SQL has executed. The TCL script in pDb->zProfile is evaluated.
|
||||||
|
*/
|
||||||
|
static void DbProfileHandler(void *cd, const char *zSql, sqlite_uint64 tm){
|
||||||
|
SqliteDb *pDb = (SqliteDb*)cd;
|
||||||
|
Tcl_DString str;
|
||||||
|
char zTm[100];
|
||||||
|
|
||||||
|
sqlite3_snprintf(sizeof(zTm)-1, zTm, "%lld", tm);
|
||||||
|
Tcl_DStringInit(&str);
|
||||||
|
Tcl_DStringAppend(&str, pDb->zProfile, -1);
|
||||||
|
Tcl_DStringAppendElement(&str, zSql);
|
||||||
|
Tcl_DStringAppendElement(&str, zTm);
|
||||||
|
Tcl_Eval(pDb->interp, Tcl_DStringValue(&str));
|
||||||
|
Tcl_DStringFree(&str);
|
||||||
|
Tcl_ResetResult(pDb->interp);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This routine is called when a transaction is committed. The
|
** This routine is called when a transaction is committed. The
|
||||||
** TCL script in pDb->zCommit is executed. If it returns non-zero or
|
** TCL script in pDb->zCommit is executed. If it returns non-zero or
|
||||||
|
@ -589,9 +612,10 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||||
"collation_needed", "commit_hook", "complete",
|
"collation_needed", "commit_hook", "complete",
|
||||||
"copy", "errorcode", "eval",
|
"copy", "errorcode", "eval",
|
||||||
"function", "last_insert_rowid", "nullvalue",
|
"function", "last_insert_rowid", "nullvalue",
|
||||||
"onecolumn", "progress", "rekey",
|
"onecolumn", "profile", "progress",
|
||||||
"timeout", "total_changes", "trace",
|
"rekey", "timeout", "total_changes",
|
||||||
"transaction", "version", 0
|
"trace", "transaction", "version",
|
||||||
|
0
|
||||||
};
|
};
|
||||||
enum DB_enum {
|
enum DB_enum {
|
||||||
DB_AUTHORIZER, DB_BUSY, DB_CACHE,
|
DB_AUTHORIZER, DB_BUSY, DB_CACHE,
|
||||||
|
@ -599,9 +623,9 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||||
DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE,
|
DB_COLLATION_NEEDED, DB_COMMIT_HOOK, DB_COMPLETE,
|
||||||
DB_COPY, DB_ERRORCODE, DB_EVAL,
|
DB_COPY, DB_ERRORCODE, DB_EVAL,
|
||||||
DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_NULLVALUE,
|
DB_FUNCTION, DB_LAST_INSERT_ROWID,DB_NULLVALUE,
|
||||||
DB_ONECOLUMN, DB_PROGRESS, DB_REKEY,
|
DB_ONECOLUMN, DB_PROFILE, DB_PROGRESS,
|
||||||
DB_TIMEOUT, DB_TOTAL_CHANGES, DB_TRACE,
|
DB_REKEY, DB_TIMEOUT, DB_TOTAL_CHANGES,
|
||||||
DB_TRANSACTION, DB_VERSION,
|
DB_TRACE, DB_TRANSACTION, DB_VERSION
|
||||||
};
|
};
|
||||||
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
|
/* don't leave trailing commas on DB_enum, it confuses the AIX xlc compiler */
|
||||||
|
|
||||||
|
@ -780,44 +804,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* $db commit_hook ?CALLBACK?
|
|
||||||
**
|
|
||||||
** Invoke the given callback just before committing every SQL transaction.
|
|
||||||
** If the callback throws an exception or returns non-zero, then the
|
|
||||||
** transaction is aborted. If CALLBACK is an empty string, the callback
|
|
||||||
** is disabled.
|
|
||||||
*/
|
|
||||||
case DB_COMMIT_HOOK: {
|
|
||||||
if( objc>3 ){
|
|
||||||
Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
|
|
||||||
return TCL_ERROR;
|
|
||||||
}else if( objc==2 ){
|
|
||||||
if( pDb->zCommit ){
|
|
||||||
Tcl_AppendResult(interp, pDb->zCommit, 0);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
char *zCommit;
|
|
||||||
int len;
|
|
||||||
if( pDb->zCommit ){
|
|
||||||
Tcl_Free(pDb->zCommit);
|
|
||||||
}
|
|
||||||
zCommit = Tcl_GetStringFromObj(objv[2], &len);
|
|
||||||
if( zCommit && len>0 ){
|
|
||||||
pDb->zCommit = Tcl_Alloc( len + 1 );
|
|
||||||
strcpy(pDb->zCommit, zCommit);
|
|
||||||
}else{
|
|
||||||
pDb->zCommit = 0;
|
|
||||||
}
|
|
||||||
if( pDb->zCommit ){
|
|
||||||
pDb->interp = interp;
|
|
||||||
sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb);
|
|
||||||
}else{
|
|
||||||
sqlite3_commit_hook(pDb->db, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** $db collate NAME SCRIPT
|
** $db collate NAME SCRIPT
|
||||||
**
|
**
|
||||||
|
@ -870,6 +856,44 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* $db commit_hook ?CALLBACK?
|
||||||
|
**
|
||||||
|
** Invoke the given callback just before committing every SQL transaction.
|
||||||
|
** If the callback throws an exception or returns non-zero, then the
|
||||||
|
** transaction is aborted. If CALLBACK is an empty string, the callback
|
||||||
|
** is disabled.
|
||||||
|
*/
|
||||||
|
case DB_COMMIT_HOOK: {
|
||||||
|
if( objc>3 ){
|
||||||
|
Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
|
||||||
|
return TCL_ERROR;
|
||||||
|
}else if( objc==2 ){
|
||||||
|
if( pDb->zCommit ){
|
||||||
|
Tcl_AppendResult(interp, pDb->zCommit, 0);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
char *zCommit;
|
||||||
|
int len;
|
||||||
|
if( pDb->zCommit ){
|
||||||
|
Tcl_Free(pDb->zCommit);
|
||||||
|
}
|
||||||
|
zCommit = Tcl_GetStringFromObj(objv[2], &len);
|
||||||
|
if( zCommit && len>0 ){
|
||||||
|
pDb->zCommit = Tcl_Alloc( len + 1 );
|
||||||
|
strcpy(pDb->zCommit, zCommit);
|
||||||
|
}else{
|
||||||
|
pDb->zCommit = 0;
|
||||||
|
}
|
||||||
|
if( pDb->zCommit ){
|
||||||
|
pDb->interp = interp;
|
||||||
|
sqlite3_commit_hook(pDb->db, DbCommitHandler, pDb);
|
||||||
|
}else{
|
||||||
|
sqlite3_commit_hook(pDb->db, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* $db complete SQL
|
/* $db complete SQL
|
||||||
**
|
**
|
||||||
** Return TRUE if SQL is a complete SQL statement. Return FALSE if
|
** Return TRUE if SQL is a complete SQL statement. Return FALSE if
|
||||||
|
@ -891,6 +915,192 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
|
||||||
|
**
|
||||||
|
** Copy data into table from filename, optionally using SEPARATOR
|
||||||
|
** as column separators. If a column contains a null string, or the
|
||||||
|
** value of NULLINDICATOR, a NULL is inserted for the column.
|
||||||
|
** conflict-algorithm is one of the sqlite conflict algorithms:
|
||||||
|
** rollback, abort, fail, ignore, replace
|
||||||
|
** On success, return the number of lines processed, not necessarily same
|
||||||
|
** as 'db changes' due to conflict-algorithm selected.
|
||||||
|
**
|
||||||
|
** This code is basically an implementation/enhancement of
|
||||||
|
** the sqlite3 shell.c ".import" command.
|
||||||
|
**
|
||||||
|
** This command usage is equivalent to the sqlite2.x COPY statement,
|
||||||
|
** which imports file data into a table using the PostgreSQL COPY file format:
|
||||||
|
** $db copy $conflit_algo $table_name $filename \t \\N
|
||||||
|
*/
|
||||||
|
case DB_COPY: {
|
||||||
|
char *zTable; /* Insert data into this table */
|
||||||
|
char *zFile; /* The file from which to extract data */
|
||||||
|
char *zConflict; /* The conflict algorithm to use */
|
||||||
|
sqlite3_stmt *pStmt; /* A statement */
|
||||||
|
int rc; /* Result code */
|
||||||
|
int nCol; /* Number of columns in the table */
|
||||||
|
int nByte; /* Number of bytes in an SQL string */
|
||||||
|
int i, j; /* Loop counters */
|
||||||
|
int nSep; /* Number of bytes in zSep[] */
|
||||||
|
int nNull; /* Number of bytes in zNull[] */
|
||||||
|
char *zSql; /* An SQL statement */
|
||||||
|
char *zLine; /* A single line of input from the file */
|
||||||
|
char **azCol; /* zLine[] broken up into columns */
|
||||||
|
char *zCommit; /* How to commit changes */
|
||||||
|
FILE *in; /* The input file */
|
||||||
|
int lineno = 0; /* Line number of input file */
|
||||||
|
char zLineNum[80]; /* Line number print buffer */
|
||||||
|
Tcl_Obj *pResult; /* interp result */
|
||||||
|
|
||||||
|
char *zSep;
|
||||||
|
char *zNull;
|
||||||
|
if( objc<5 || objc>7 ){
|
||||||
|
Tcl_WrongNumArgs(interp, 2, objv,
|
||||||
|
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if( objc>=6 ){
|
||||||
|
zSep = Tcl_GetStringFromObj(objv[5], 0);
|
||||||
|
}else{
|
||||||
|
zSep = "\t";
|
||||||
|
}
|
||||||
|
if( objc>=7 ){
|
||||||
|
zNull = Tcl_GetStringFromObj(objv[6], 0);
|
||||||
|
}else{
|
||||||
|
zNull = "";
|
||||||
|
}
|
||||||
|
zConflict = Tcl_GetStringFromObj(objv[2], 0);
|
||||||
|
zTable = Tcl_GetStringFromObj(objv[3], 0);
|
||||||
|
zFile = Tcl_GetStringFromObj(objv[4], 0);
|
||||||
|
nSep = strlen(zSep);
|
||||||
|
nNull = strlen(zNull);
|
||||||
|
if( nSep==0 ){
|
||||||
|
Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if(sqlite3StrICmp(zConflict, "rollback") != 0 &&
|
||||||
|
sqlite3StrICmp(zConflict, "abort" ) != 0 &&
|
||||||
|
sqlite3StrICmp(zConflict, "fail" ) != 0 &&
|
||||||
|
sqlite3StrICmp(zConflict, "ignore" ) != 0 &&
|
||||||
|
sqlite3StrICmp(zConflict, "replace" ) != 0 ) {
|
||||||
|
Tcl_AppendResult(interp, "Error: \"", zConflict,
|
||||||
|
"\", conflict-algorithm must be one of: rollback, "
|
||||||
|
"abort, fail, ignore, or replace", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
|
||||||
|
if( zSql==0 ){
|
||||||
|
Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
nByte = strlen(zSql);
|
||||||
|
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
|
||||||
|
sqlite3_free(zSql);
|
||||||
|
if( rc ){
|
||||||
|
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||||
|
nCol = 0;
|
||||||
|
}else{
|
||||||
|
nCol = sqlite3_column_count(pStmt);
|
||||||
|
}
|
||||||
|
sqlite3_finalize(pStmt);
|
||||||
|
if( nCol==0 ) {
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
zSql = malloc( nByte + 50 + nCol*2 );
|
||||||
|
if( zSql==0 ) {
|
||||||
|
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
|
||||||
|
zConflict, zTable);
|
||||||
|
j = strlen(zSql);
|
||||||
|
for(i=1; i<nCol; i++){
|
||||||
|
zSql[j++] = ',';
|
||||||
|
zSql[j++] = '?';
|
||||||
|
}
|
||||||
|
zSql[j++] = ')';
|
||||||
|
zSql[j] = 0;
|
||||||
|
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
|
||||||
|
free(zSql);
|
||||||
|
if( rc ){
|
||||||
|
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||||
|
sqlite3_finalize(pStmt);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
in = fopen(zFile, "rb");
|
||||||
|
if( in==0 ){
|
||||||
|
Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL);
|
||||||
|
sqlite3_finalize(pStmt);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
|
||||||
|
if( azCol==0 ) {
|
||||||
|
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
|
||||||
|
zCommit = "COMMIT";
|
||||||
|
while( (zLine = local_getline(0, in))!=0 ){
|
||||||
|
char *z;
|
||||||
|
i = 0;
|
||||||
|
lineno++;
|
||||||
|
azCol[0] = zLine;
|
||||||
|
for(i=0, z=zLine; *z; z++){
|
||||||
|
if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
|
||||||
|
*z = 0;
|
||||||
|
i++;
|
||||||
|
if( i<nCol ){
|
||||||
|
azCol[i] = &z[nSep];
|
||||||
|
z += nSep-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( i+1!=nCol ){
|
||||||
|
char *zErr;
|
||||||
|
zErr = malloc(200 + strlen(zFile));
|
||||||
|
sprintf(zErr,"Error: %s line %d: expected %d columns of data but found %d",
|
||||||
|
zFile, lineno, nCol, i+1);
|
||||||
|
Tcl_AppendResult(interp, zErr, 0);
|
||||||
|
free(zErr);
|
||||||
|
zCommit = "ROLLBACK";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for(i=0; i<nCol; i++){
|
||||||
|
/* check for null data, if so, bind as null */
|
||||||
|
if ((nNull>0 && strcmp(azCol[i], zNull)==0) || strlen(azCol[i])==0) {
|
||||||
|
sqlite3_bind_null(pStmt, i+1);
|
||||||
|
}else{
|
||||||
|
sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlite3_step(pStmt);
|
||||||
|
rc = sqlite3_reset(pStmt);
|
||||||
|
free(zLine);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||||
|
zCommit = "ROLLBACK";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(azCol);
|
||||||
|
fclose(in);
|
||||||
|
sqlite3_finalize(pStmt);
|
||||||
|
sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
|
||||||
|
|
||||||
|
if( zCommit[0] == 'C' ){
|
||||||
|
/* success, set result as number of lines processed */
|
||||||
|
pResult = Tcl_GetObjResult(interp);
|
||||||
|
Tcl_SetIntObj(pResult, lineno);
|
||||||
|
rc = TCL_OK;
|
||||||
|
}else{
|
||||||
|
/* failure, append lineno where failed */
|
||||||
|
sprintf(zLineNum,"%d",lineno);
|
||||||
|
Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0);
|
||||||
|
rc = TCL_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** $db errorcode
|
** $db errorcode
|
||||||
**
|
**
|
||||||
|
@ -1301,6 +1511,37 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** $db nullvalue ?STRING?
|
||||||
|
**
|
||||||
|
** Change text used when a NULL comes back from the database. If ?STRING?
|
||||||
|
** is not present, then the current string used for NULL is returned.
|
||||||
|
** If STRING is present, then STRING is returned.
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
case DB_NULLVALUE: {
|
||||||
|
if( objc!=2 && objc!=3 ){
|
||||||
|
Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE");
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if( objc==3 ){
|
||||||
|
int len;
|
||||||
|
char *zNull = Tcl_GetStringFromObj(objv[2], &len);
|
||||||
|
if( pDb->zNull ){
|
||||||
|
Tcl_Free(pDb->zNull);
|
||||||
|
}
|
||||||
|
if( zNull && len>0 ){
|
||||||
|
pDb->zNull = Tcl_Alloc( len + 1 );
|
||||||
|
strncpy(pDb->zNull, zNull, len);
|
||||||
|
pDb->zNull[len] = '\0';
|
||||||
|
}else{
|
||||||
|
pDb->zNull = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** $db last_insert_rowid
|
** $db last_insert_rowid
|
||||||
**
|
**
|
||||||
|
@ -1365,6 +1606,45 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* $db profile ?CALLBACK?
|
||||||
|
**
|
||||||
|
** Make arrangements to invoke the CALLBACK routine after each SQL statement
|
||||||
|
** that has run. The text of the SQL and the amount of elapse time are
|
||||||
|
** appended to CALLBACK before the script is run.
|
||||||
|
*/
|
||||||
|
case DB_PROFILE: {
|
||||||
|
if( objc>3 ){
|
||||||
|
Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?");
|
||||||
|
return TCL_ERROR;
|
||||||
|
}else if( objc==2 ){
|
||||||
|
if( pDb->zProfile ){
|
||||||
|
Tcl_AppendResult(interp, pDb->zProfile, 0);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
char *zProfile;
|
||||||
|
int len;
|
||||||
|
if( pDb->zProfile ){
|
||||||
|
Tcl_Free(pDb->zProfile);
|
||||||
|
}
|
||||||
|
zProfile = Tcl_GetStringFromObj(objv[2], &len);
|
||||||
|
if( zProfile && len>0 ){
|
||||||
|
pDb->zProfile = Tcl_Alloc( len + 1 );
|
||||||
|
strcpy(pDb->zProfile, zProfile);
|
||||||
|
}else{
|
||||||
|
pDb->zProfile = 0;
|
||||||
|
}
|
||||||
|
#ifndef SQLITE_OMIT_TRACE
|
||||||
|
if( pDb->zProfile ){
|
||||||
|
pDb->interp = interp;
|
||||||
|
sqlite3_profile(pDb->db, DbProfileHandler, pDb);
|
||||||
|
}else{
|
||||||
|
sqlite3_profile(pDb->db, 0, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** $db rekey KEY
|
** $db rekey KEY
|
||||||
**
|
**
|
||||||
|
@ -1404,37 +1684,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** $db nullvalue ?STRING?
|
|
||||||
**
|
|
||||||
** Change text used when a NULL comes back from the database. If ?STRING?
|
|
||||||
** is not present, then the current string used for NULL is returned.
|
|
||||||
** If STRING is present, then STRING is returned.
|
|
||||||
**
|
|
||||||
*/
|
|
||||||
case DB_NULLVALUE: {
|
|
||||||
if( objc!=2 && objc!=3 ){
|
|
||||||
Tcl_WrongNumArgs(interp, 2, objv, "NULLVALUE");
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
if( objc==3 ){
|
|
||||||
int len;
|
|
||||||
char *zNull = Tcl_GetStringFromObj(objv[2], &len);
|
|
||||||
if( pDb->zNull ){
|
|
||||||
Tcl_Free(pDb->zNull);
|
|
||||||
}
|
|
||||||
if( zNull && len>0 ){
|
|
||||||
pDb->zNull = Tcl_Alloc( len + 1 );
|
|
||||||
strncpy(pDb->zNull, zNull, len);
|
|
||||||
pDb->zNull[len] = '\0';
|
|
||||||
}else{
|
|
||||||
pDb->zNull = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Tcl_SetObjResult(interp, dbTextToObj(pDb->zNull));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** $db total_changes
|
** $db total_changes
|
||||||
**
|
**
|
||||||
|
@ -1479,12 +1728,14 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||||
}else{
|
}else{
|
||||||
pDb->zTrace = 0;
|
pDb->zTrace = 0;
|
||||||
}
|
}
|
||||||
|
#ifndef SQLITE_OMIT_TRACE
|
||||||
if( pDb->zTrace ){
|
if( pDb->zTrace ){
|
||||||
pDb->interp = interp;
|
pDb->interp = interp;
|
||||||
sqlite3_trace(pDb->db, DbTraceHandler, pDb);
|
sqlite3_trace(pDb->db, DbTraceHandler, pDb);
|
||||||
}else{
|
}else{
|
||||||
sqlite3_trace(pDb->db, 0, 0);
|
sqlite3_trace(pDb->db, 0, 0);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1546,192 +1797,6 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* $db copy conflict-algorithm table filename ?SEPARATOR? ?NULLINDICATOR?
|
|
||||||
**
|
|
||||||
** Copy data into table from filename, optionally using SEPARATOR
|
|
||||||
** as column separators. If a column contains a null string, or the
|
|
||||||
** value of NULLINDICATOR, a NULL is inserted for the column.
|
|
||||||
** conflict-algorithm is one of the sqlite conflict algorithms:
|
|
||||||
** rollback, abort, fail, ignore, replace
|
|
||||||
** On success, return the number of lines processed, not necessarily same
|
|
||||||
** as 'db changes' due to conflict-algorithm selected.
|
|
||||||
**
|
|
||||||
** This code is basically an implementation/enhancement of
|
|
||||||
** the sqlite3 shell.c ".import" command.
|
|
||||||
**
|
|
||||||
** This command usage is equivalent to the sqlite2.x COPY statement,
|
|
||||||
** which imports file data into a table using the PostgreSQL COPY file format:
|
|
||||||
** $db copy $conflit_algo $table_name $filename \t \\N
|
|
||||||
*/
|
|
||||||
case DB_COPY: {
|
|
||||||
char *zTable; /* Insert data into this table */
|
|
||||||
char *zFile; /* The file from which to extract data */
|
|
||||||
char *zConflict; /* The conflict algorithm to use */
|
|
||||||
sqlite3_stmt *pStmt; /* A statement */
|
|
||||||
int rc; /* Result code */
|
|
||||||
int nCol; /* Number of columns in the table */
|
|
||||||
int nByte; /* Number of bytes in an SQL string */
|
|
||||||
int i, j; /* Loop counters */
|
|
||||||
int nSep; /* Number of bytes in zSep[] */
|
|
||||||
int nNull; /* Number of bytes in zNull[] */
|
|
||||||
char *zSql; /* An SQL statement */
|
|
||||||
char *zLine; /* A single line of input from the file */
|
|
||||||
char **azCol; /* zLine[] broken up into columns */
|
|
||||||
char *zCommit; /* How to commit changes */
|
|
||||||
FILE *in; /* The input file */
|
|
||||||
int lineno = 0; /* Line number of input file */
|
|
||||||
char zLineNum[80]; /* Line number print buffer */
|
|
||||||
Tcl_Obj *pResult; /* interp result */
|
|
||||||
|
|
||||||
char *zSep;
|
|
||||||
char *zNull;
|
|
||||||
if( objc<5 || objc>7 ){
|
|
||||||
Tcl_WrongNumArgs(interp, 2, objv,
|
|
||||||
"CONFLICT-ALGORITHM TABLE FILENAME ?SEPARATOR? ?NULLINDICATOR?");
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
if( objc>=6 ){
|
|
||||||
zSep = Tcl_GetStringFromObj(objv[5], 0);
|
|
||||||
}else{
|
|
||||||
zSep = "\t";
|
|
||||||
}
|
|
||||||
if( objc>=7 ){
|
|
||||||
zNull = Tcl_GetStringFromObj(objv[6], 0);
|
|
||||||
}else{
|
|
||||||
zNull = "";
|
|
||||||
}
|
|
||||||
zConflict = Tcl_GetStringFromObj(objv[2], 0);
|
|
||||||
zTable = Tcl_GetStringFromObj(objv[3], 0);
|
|
||||||
zFile = Tcl_GetStringFromObj(objv[4], 0);
|
|
||||||
nSep = strlen(zSep);
|
|
||||||
nNull = strlen(zNull);
|
|
||||||
if( nSep==0 ){
|
|
||||||
Tcl_AppendResult(interp, "Error: non-null separator required for copy", 0);
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
if(sqlite3StrICmp(zConflict, "rollback") != 0 &&
|
|
||||||
sqlite3StrICmp(zConflict, "abort" ) != 0 &&
|
|
||||||
sqlite3StrICmp(zConflict, "fail" ) != 0 &&
|
|
||||||
sqlite3StrICmp(zConflict, "ignore" ) != 0 &&
|
|
||||||
sqlite3StrICmp(zConflict, "replace" ) != 0 ) {
|
|
||||||
Tcl_AppendResult(interp, "Error: \"", zConflict,
|
|
||||||
"\", conflict-algorithm must be one of: rollback, "
|
|
||||||
"abort, fail, ignore, or replace", 0);
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
zSql = sqlite3_mprintf("SELECT * FROM '%q'", zTable);
|
|
||||||
if( zSql==0 ){
|
|
||||||
Tcl_AppendResult(interp, "Error: no such table: ", zTable, 0);
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
nByte = strlen(zSql);
|
|
||||||
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
|
|
||||||
sqlite3_free(zSql);
|
|
||||||
if( rc ){
|
|
||||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
|
||||||
nCol = 0;
|
|
||||||
}else{
|
|
||||||
nCol = sqlite3_column_count(pStmt);
|
|
||||||
}
|
|
||||||
sqlite3_finalize(pStmt);
|
|
||||||
if( nCol==0 ) {
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
zSql = malloc( nByte + 50 + nCol*2 );
|
|
||||||
if( zSql==0 ) {
|
|
||||||
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
sqlite3_snprintf(nByte+50, zSql, "INSERT OR %q INTO '%q' VALUES(?",
|
|
||||||
zConflict, zTable);
|
|
||||||
j = strlen(zSql);
|
|
||||||
for(i=1; i<nCol; i++){
|
|
||||||
zSql[j++] = ',';
|
|
||||||
zSql[j++] = '?';
|
|
||||||
}
|
|
||||||
zSql[j++] = ')';
|
|
||||||
zSql[j] = 0;
|
|
||||||
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
|
|
||||||
free(zSql);
|
|
||||||
if( rc ){
|
|
||||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
|
||||||
sqlite3_finalize(pStmt);
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
in = fopen(zFile, "rb");
|
|
||||||
if( in==0 ){
|
|
||||||
Tcl_AppendResult(interp, "Error: cannot open file: ", zFile, NULL);
|
|
||||||
sqlite3_finalize(pStmt);
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
azCol = malloc( sizeof(azCol[0])*(nCol+1) );
|
|
||||||
if( azCol==0 ) {
|
|
||||||
Tcl_AppendResult(interp, "Error: can't malloc()", 0);
|
|
||||||
return TCL_ERROR;
|
|
||||||
}
|
|
||||||
sqlite3_exec(pDb->db, "BEGIN", 0, 0, 0);
|
|
||||||
zCommit = "COMMIT";
|
|
||||||
while( (zLine = local_getline(0, in))!=0 ){
|
|
||||||
char *z;
|
|
||||||
i = 0;
|
|
||||||
lineno++;
|
|
||||||
azCol[0] = zLine;
|
|
||||||
for(i=0, z=zLine; *z; z++){
|
|
||||||
if( *z==zSep[0] && strncmp(z, zSep, nSep)==0 ){
|
|
||||||
*z = 0;
|
|
||||||
i++;
|
|
||||||
if( i<nCol ){
|
|
||||||
azCol[i] = &z[nSep];
|
|
||||||
z += nSep-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( i+1!=nCol ){
|
|
||||||
char *zErr;
|
|
||||||
zErr = malloc(200 + strlen(zFile));
|
|
||||||
sprintf(zErr,"Error: %s line %d: expected %d columns of data but found %d",
|
|
||||||
zFile, lineno, nCol, i+1);
|
|
||||||
Tcl_AppendResult(interp, zErr, 0);
|
|
||||||
free(zErr);
|
|
||||||
zCommit = "ROLLBACK";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for(i=0; i<nCol; i++){
|
|
||||||
/* check for null data, if so, bind as null */
|
|
||||||
if ((nNull>0 && strcmp(azCol[i], zNull)==0) || strlen(azCol[i])==0) {
|
|
||||||
sqlite3_bind_null(pStmt, i+1);
|
|
||||||
}else{
|
|
||||||
sqlite3_bind_text(pStmt, i+1, azCol[i], -1, SQLITE_STATIC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sqlite3_step(pStmt);
|
|
||||||
rc = sqlite3_reset(pStmt);
|
|
||||||
free(zLine);
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
Tcl_AppendResult(interp,"Error: ", sqlite3_errmsg(pDb->db), 0);
|
|
||||||
zCommit = "ROLLBACK";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(azCol);
|
|
||||||
fclose(in);
|
|
||||||
sqlite3_finalize(pStmt);
|
|
||||||
sqlite3_exec(pDb->db, zCommit, 0, 0, 0);
|
|
||||||
|
|
||||||
if( zCommit[0] == 'C' ){
|
|
||||||
/* success, set result as number of lines processed */
|
|
||||||
pResult = Tcl_GetObjResult(interp);
|
|
||||||
Tcl_SetIntObj(pResult, lineno);
|
|
||||||
rc = TCL_OK;
|
|
||||||
}else{
|
|
||||||
/* failure, append lineno where failed */
|
|
||||||
sprintf(zLineNum,"%d",lineno);
|
|
||||||
Tcl_AppendResult(interp,", failed while processing line: ",zLineNum,0);
|
|
||||||
rc = TCL_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* $db version
|
/* $db version
|
||||||
**
|
**
|
||||||
** Return the version string for this database.
|
** Return the version string for this database.
|
||||||
|
|
|
@ -661,7 +661,7 @@ static int sqlite3_mprintf_str(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Usage: sqlite3_mprintf_str FORMAT INTEGER INTEGER DOUBLE
|
** Usage: sqlite3_mprintf_double FORMAT INTEGER INTEGER DOUBLE
|
||||||
**
|
**
|
||||||
** Call mprintf with two integer arguments and one double argument
|
** Call mprintf with two integer arguments and one double argument
|
||||||
*/
|
*/
|
||||||
|
@ -676,7 +676,7 @@ static int sqlite3_mprintf_double(
|
||||||
char *z;
|
char *z;
|
||||||
if( argc!=5 ){
|
if( argc!=5 ){
|
||||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||||
" FORMAT INT INT STRING\"", 0);
|
" FORMAT INT INT DOUBLE\"", 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
for(i=2; i<4; i++){
|
for(i=2; i<4; i++){
|
||||||
|
@ -690,7 +690,7 @@ static int sqlite3_mprintf_double(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Usage: sqlite3_mprintf_str FORMAT DOUBLE DOUBLE
|
** Usage: sqlite3_mprintf_scaled FORMAT DOUBLE DOUBLE
|
||||||
**
|
**
|
||||||
** Call mprintf with a single double argument which is the product of the
|
** Call mprintf with a single double argument which is the product of the
|
||||||
** two arguments given above. This is used to generate overflow and underflow
|
** two arguments given above. This is used to generate overflow and underflow
|
||||||
|
@ -744,6 +744,40 @@ static int sqlite3_mprintf_stronly(
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Usage: sqlite3_mprintf_hexdouble FORMAT HEX
|
||||||
|
**
|
||||||
|
** Call mprintf with a single double argument which is derived from the
|
||||||
|
** hexadecimal encoding of an IEEE double.
|
||||||
|
*/
|
||||||
|
static int sqlite3_mprintf_hexdouble(
|
||||||
|
void *NotUsed,
|
||||||
|
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||||
|
int argc, /* Number of arguments */
|
||||||
|
char **argv /* Text of each argument */
|
||||||
|
){
|
||||||
|
char *z;
|
||||||
|
double r;
|
||||||
|
unsigned x1, x2;
|
||||||
|
long long unsigned d;
|
||||||
|
if( argc!=3 ){
|
||||||
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||||
|
" FORMAT STRING\"", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
if( sscanf(argv[2], "%08x%08x", &x2, &x1)!=2 ){
|
||||||
|
Tcl_AppendResult(interp, "2nd argument should be 16-characters of hex", 0);
|
||||||
|
return TCL_ERROR;
|
||||||
|
}
|
||||||
|
d = x2;
|
||||||
|
d = (d<<32) + x1;
|
||||||
|
memcpy(&r, &d, sizeof(r));
|
||||||
|
z = sqlite3_mprintf(argv[1], r);
|
||||||
|
Tcl_AppendResult(interp, z, 0);
|
||||||
|
sqlite3_free(z);
|
||||||
|
return TCL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Usage: sqlite_malloc_fail N ?REPEAT-INTERVAL?
|
** Usage: sqlite_malloc_fail N ?REPEAT-INTERVAL?
|
||||||
**
|
**
|
||||||
|
@ -1107,6 +1141,7 @@ static int test_collate_func(
|
||||||
Tcl_Interp *i = pTestCollateInterp;
|
Tcl_Interp *i = pTestCollateInterp;
|
||||||
int encin = (int)pCtx;
|
int encin = (int)pCtx;
|
||||||
int res;
|
int res;
|
||||||
|
int n;
|
||||||
|
|
||||||
sqlite3_value *pVal;
|
sqlite3_value *pVal;
|
||||||
Tcl_Obj *pX;
|
Tcl_Obj *pX;
|
||||||
|
@ -1130,9 +1165,11 @@ static int test_collate_func(
|
||||||
|
|
||||||
pVal = sqlite3ValueNew();
|
pVal = sqlite3ValueNew();
|
||||||
sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC);
|
sqlite3ValueSetStr(pVal, nA, zA, encin, SQLITE_STATIC);
|
||||||
Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),-1));
|
n = sqlite3_value_bytes(pVal);
|
||||||
|
Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),n));
|
||||||
sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC);
|
sqlite3ValueSetStr(pVal, nB, zB, encin, SQLITE_STATIC);
|
||||||
Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),-1));
|
n = sqlite3_value_bytes(pVal);
|
||||||
|
Tcl_ListObjAppendElement(i,pX,Tcl_NewStringObj(sqlite3_value_text(pVal),n));
|
||||||
sqlite3ValueFree(pVal);
|
sqlite3ValueFree(pVal);
|
||||||
|
|
||||||
Tcl_EvalObjEx(i, pX, 0);
|
Tcl_EvalObjEx(i, pX, 0);
|
||||||
|
@ -2620,27 +2657,51 @@ static int test_interrupt(
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u8 *sqlite3_stack_baseline = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Usage: sqlite3_sleep ms
|
** Fill the stack with a known bitpattern.
|
||||||
**
|
|
||||||
** Sleep for the specified number of ms.
|
|
||||||
*/
|
*/
|
||||||
#if 0
|
static void prepStack(void){
|
||||||
static int test_sleep(
|
int i;
|
||||||
|
u32 bigBuf[65536];
|
||||||
|
for(i=0; i<sizeof(bigBuf); i++) bigBuf[i] = 0xdeadbeef;
|
||||||
|
sqlite3_stack_baseline = (u8*)&bigBuf[65536];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Get the current stack depth. Used for debugging only.
|
||||||
|
*/
|
||||||
|
u64 sqlite3StackDepth(void){
|
||||||
|
u8 x;
|
||||||
|
return (u64)(sqlite3_stack_baseline - &x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Usage: sqlite3_stack_used DB SQL
|
||||||
|
**
|
||||||
|
** Try to measure the amount of stack space used by a call to sqlite3_exec
|
||||||
|
*/
|
||||||
|
static int test_stack_used(
|
||||||
void * clientData,
|
void * clientData,
|
||||||
Tcl_Interp *interp,
|
Tcl_Interp *interp,
|
||||||
int argc,
|
int argc,
|
||||||
char **argv
|
char **argv
|
||||||
){
|
){
|
||||||
sqlite3 *db;
|
sqlite3 *db;
|
||||||
if( argc!=2 ){
|
int i;
|
||||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ms", 0);
|
if( argc!=3 ){
|
||||||
|
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||||
|
" DB SQL", 0);
|
||||||
return TCL_ERROR;
|
return TCL_ERROR;
|
||||||
}
|
}
|
||||||
Tcl_SetObjResult(interp, Tcl_NewIntObj(sqlite3_sleep(atoi(argv[1]))));
|
if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
|
||||||
|
prepStack();
|
||||||
|
sqlite3_exec(db, argv[2], 0, 0, 0);
|
||||||
|
for(i=65535; i>=0 && ((u32*)sqlite3_stack_baseline)[-i]==0xdeadbeef; i--){}
|
||||||
|
Tcl_SetObjResult(interp, Tcl_NewIntObj(i*4));
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Usage: sqlite_delete_function DB function-name
|
** Usage: sqlite_delete_function DB function-name
|
||||||
|
@ -2954,6 +3015,12 @@ static void set_options(Tcl_Interp *interp){
|
||||||
Tcl_SetVar2(interp, "sqlite_options", "threadsafe", "0", TCL_GLOBAL_ONLY);
|
Tcl_SetVar2(interp, "sqlite_options", "threadsafe", "0", TCL_GLOBAL_ONLY);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SQLITE_OMIT_TRACE
|
||||||
|
Tcl_SetVar2(interp, "sqlite_options", "trace", "0", TCL_GLOBAL_ONLY);
|
||||||
|
#else
|
||||||
|
Tcl_SetVar2(interp, "sqlite_options", "trace", "1", TCL_GLOBAL_ONLY);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SQLITE_OMIT_TRIGGER
|
#ifdef SQLITE_OMIT_TRIGGER
|
||||||
Tcl_SetVar2(interp, "sqlite_options", "trigger", "0", TCL_GLOBAL_ONLY);
|
Tcl_SetVar2(interp, "sqlite_options", "trigger", "0", TCL_GLOBAL_ONLY);
|
||||||
#else
|
#else
|
||||||
|
@ -3004,6 +3071,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||||
{ "sqlite3_mprintf_stronly", (Tcl_CmdProc*)sqlite3_mprintf_stronly},
|
{ "sqlite3_mprintf_stronly", (Tcl_CmdProc*)sqlite3_mprintf_stronly},
|
||||||
{ "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double },
|
{ "sqlite3_mprintf_double", (Tcl_CmdProc*)sqlite3_mprintf_double },
|
||||||
{ "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled },
|
{ "sqlite3_mprintf_scaled", (Tcl_CmdProc*)sqlite3_mprintf_scaled },
|
||||||
|
{ "sqlite3_mprintf_hexdouble", (Tcl_CmdProc*)sqlite3_mprintf_hexdouble},
|
||||||
{ "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z },
|
{ "sqlite3_mprintf_z_test", (Tcl_CmdProc*)test_mprintf_z },
|
||||||
{ "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
|
{ "sqlite3_last_insert_rowid", (Tcl_CmdProc*)test_last_rowid },
|
||||||
{ "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf },
|
{ "sqlite3_exec_printf", (Tcl_CmdProc*)test_exec_printf },
|
||||||
|
@ -3029,6 +3097,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||||
{ "sqlite_delete_function", (Tcl_CmdProc*)delete_function },
|
{ "sqlite_delete_function", (Tcl_CmdProc*)delete_function },
|
||||||
{ "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation },
|
{ "sqlite_delete_collation", (Tcl_CmdProc*)delete_collation },
|
||||||
{ "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit },
|
{ "sqlite3_get_autocommit", (Tcl_CmdProc*)get_autocommit },
|
||||||
|
{ "sqlite3_stack_used", (Tcl_CmdProc*)test_stack_used },
|
||||||
};
|
};
|
||||||
static struct {
|
static struct {
|
||||||
char *zName;
|
char *zName;
|
||||||
|
@ -3111,12 +3180,17 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||||
extern int sqlite3_opentemp_count;
|
extern int sqlite3_opentemp_count;
|
||||||
extern int sqlite3_memUsed;
|
extern int sqlite3_memUsed;
|
||||||
extern int sqlite3_memMax;
|
extern int sqlite3_memMax;
|
||||||
extern char sqlite3_query_plan[];
|
|
||||||
extern int sqlite3_like_count;
|
extern int sqlite3_like_count;
|
||||||
|
#if OS_WIN
|
||||||
|
extern int sqlite3_os_type;
|
||||||
|
#endif
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
extern int sqlite3_vdbe_addop_trace;
|
extern int sqlite3_vdbe_addop_trace;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef SQLITE_TEST
|
||||||
|
extern char sqlite3_query_plan[];
|
||||||
static char *query_plan = sqlite3_query_plan;
|
static char *query_plan = sqlite3_query_plan;
|
||||||
|
#endif
|
||||||
|
|
||||||
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
|
||||||
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
|
Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
|
||||||
|
@ -3139,11 +3213,19 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||||
(char*)&sqlite3_current_time, TCL_LINK_INT);
|
(char*)&sqlite3_current_time, TCL_LINK_INT);
|
||||||
Tcl_LinkVar(interp, "sqlite_os_trace",
|
Tcl_LinkVar(interp, "sqlite_os_trace",
|
||||||
(char*)&sqlite3_os_trace, TCL_LINK_INT);
|
(char*)&sqlite3_os_trace, TCL_LINK_INT);
|
||||||
Tcl_LinkVar(interp, "sqlite_where_trace",
|
#if OS_WIN
|
||||||
(char*)&sqlite3_where_trace, TCL_LINK_INT);
|
Tcl_LinkVar(interp, "sqlite_os_type",
|
||||||
|
(char*)&sqlite3_os_type, TCL_LINK_INT);
|
||||||
|
#endif
|
||||||
|
#ifdef SQLITE_TEST
|
||||||
|
Tcl_LinkVar(interp, "sqlite_query_plan",
|
||||||
|
(char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
|
||||||
|
#endif
|
||||||
#ifdef SQLITE_DEBUG
|
#ifdef SQLITE_DEBUG
|
||||||
Tcl_LinkVar(interp, "sqlite_addop_trace",
|
Tcl_LinkVar(interp, "sqlite_addop_trace",
|
||||||
(char*)&sqlite3_vdbe_addop_trace, TCL_LINK_INT);
|
(char*)&sqlite3_vdbe_addop_trace, TCL_LINK_INT);
|
||||||
|
Tcl_LinkVar(interp, "sqlite_where_trace",
|
||||||
|
(char*)&sqlite3_where_trace, TCL_LINK_INT);
|
||||||
#endif
|
#endif
|
||||||
#ifdef SQLITE_MEMDEBUG
|
#ifdef SQLITE_MEMDEBUG
|
||||||
Tcl_LinkVar(interp, "sqlite_memused",
|
Tcl_LinkVar(interp, "sqlite_memused",
|
||||||
|
@ -3151,8 +3233,6 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
|
||||||
Tcl_LinkVar(interp, "sqlite_memmax",
|
Tcl_LinkVar(interp, "sqlite_memmax",
|
||||||
(char*)&sqlite3_memMax, TCL_LINK_INT | TCL_LINK_READ_ONLY);
|
(char*)&sqlite3_memMax, TCL_LINK_INT | TCL_LINK_READ_ONLY);
|
||||||
#endif
|
#endif
|
||||||
Tcl_LinkVar(interp, "sqlite_query_plan",
|
|
||||||
(char*)&query_plan, TCL_LINK_STRING|TCL_LINK_READ_ONLY);
|
|
||||||
#ifndef SQLITE_OMIT_DISKIO
|
#ifndef SQLITE_OMIT_DISKIO
|
||||||
Tcl_LinkVar(interp, "sqlite_opentemp_count",
|
Tcl_LinkVar(interp, "sqlite_opentemp_count",
|
||||||
(char*)&sqlite3_opentemp_count, TCL_LINK_INT);
|
(char*)&sqlite3_opentemp_count, TCL_LINK_INT);
|
||||||
|
|
|
@ -561,6 +561,7 @@ static int fake_big_file(
|
||||||
int Sqlitetest2_Init(Tcl_Interp *interp){
|
int Sqlitetest2_Init(Tcl_Interp *interp){
|
||||||
extern int sqlite3_io_error_pending;
|
extern int sqlite3_io_error_pending;
|
||||||
extern int sqlite3_diskfull_pending;
|
extern int sqlite3_diskfull_pending;
|
||||||
|
extern int sqlite3_diskfull;
|
||||||
static struct {
|
static struct {
|
||||||
char *zName;
|
char *zName;
|
||||||
Tcl_CmdProc *xProc;
|
Tcl_CmdProc *xProc;
|
||||||
|
@ -593,6 +594,10 @@ int Sqlitetest2_Init(Tcl_Interp *interp){
|
||||||
(char*)&sqlite3_io_error_pending, TCL_LINK_INT);
|
(char*)&sqlite3_io_error_pending, TCL_LINK_INT);
|
||||||
Tcl_LinkVar(interp, "sqlite_diskfull_pending",
|
Tcl_LinkVar(interp, "sqlite_diskfull_pending",
|
||||||
(char*)&sqlite3_diskfull_pending, TCL_LINK_INT);
|
(char*)&sqlite3_diskfull_pending, TCL_LINK_INT);
|
||||||
|
Tcl_LinkVar(interp, "sqlite_diskfull",
|
||||||
|
(char*)&sqlite3_diskfull, TCL_LINK_INT);
|
||||||
|
Tcl_LinkVar(interp, "sqlite_pending_byte",
|
||||||
|
(char*)&sqlite3_pending_byte, TCL_LINK_INT);
|
||||||
Tcl_LinkVar(interp, "pager_pagesize",
|
Tcl_LinkVar(interp, "pager_pagesize",
|
||||||
(char*)&test_pagesize, TCL_LINK_INT);
|
(char*)&test_pagesize, TCL_LINK_INT);
|
||||||
return TCL_OK;
|
return TCL_OK;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
|
#include "vdbe.h"
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_TRIGGER
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -259,13 +259,13 @@ void sqlite3Update(
|
||||||
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
if( pParse->nested==0 ) sqlite3VdbeCountChanges(v);
|
||||||
sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
|
sqlite3BeginWriteOperation(pParse, 1, pTab->iDb);
|
||||||
|
|
||||||
/* If we are trying to update a view, construct that view into
|
/* If we are trying to update a view, realize that view into
|
||||||
** a temporary table.
|
** a ephemeral table.
|
||||||
*/
|
*/
|
||||||
if( isView ){
|
if( isView ){
|
||||||
Select *pView;
|
Select *pView;
|
||||||
pView = sqlite3SelectDup(pTab->pSelect);
|
pView = sqlite3SelectDup(pTab->pSelect);
|
||||||
sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0);
|
sqlite3Select(pParse, pView, SRT_VirtualTab, iCur, 0, 0, 0, 0);
|
||||||
sqlite3SelectDelete(pView);
|
sqlite3SelectDelete(pView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,7 +469,7 @@ void sqlite3Update(
|
||||||
** all record selected by the WHERE clause have been updated.
|
** all record selected by the WHERE clause have been updated.
|
||||||
*/
|
*/
|
||||||
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
|
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
|
||||||
sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
|
|
||||||
/* Close all tables if there were no FOR EACH ROW triggers */
|
/* Close all tables if there were no FOR EACH ROW triggers */
|
||||||
if( !triggers_exist ){
|
if( !triggers_exist ){
|
||||||
|
|
|
@ -366,6 +366,19 @@ char *sqlite3StrNDup(const char *z, int n){
|
||||||
}
|
}
|
||||||
#endif /* !defined(SQLITE_MEMDEBUG) */
|
#endif /* !defined(SQLITE_MEMDEBUG) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Reallocate a buffer to a different size. This is similar to
|
||||||
|
** sqliteRealloc() except that if the allocation fails the buffer
|
||||||
|
** is freed.
|
||||||
|
*/
|
||||||
|
void sqlite3ReallocOrFree(void **ppBuf, int newSize){
|
||||||
|
void *pNew = sqliteRealloc(*ppBuf, newSize);
|
||||||
|
if( pNew==0 ){
|
||||||
|
sqliteFree(*ppBuf);
|
||||||
|
}
|
||||||
|
*ppBuf = pNew;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Create a string from the 2nd and subsequent arguments (up to the
|
** Create a string from the 2nd and subsequent arguments (up to the
|
||||||
** first NULL argument), store the string in memory obtained from
|
** first NULL argument), store the string in memory obtained from
|
||||||
|
|
|
@ -160,38 +160,6 @@ static void _storeTypeInfo(Mem *pMem){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** Insert a new aggregate element and make it the element that
|
|
||||||
** has focus.
|
|
||||||
**
|
|
||||||
** Return 0 on success and 1 if memory is exhausted.
|
|
||||||
*/
|
|
||||||
static int AggInsert(Agg *p, char *zKey, int nKey){
|
|
||||||
AggElem *pElem;
|
|
||||||
int i;
|
|
||||||
int rc;
|
|
||||||
pElem = sqliteMalloc( sizeof(AggElem) + nKey +
|
|
||||||
(p->nMem-1)*sizeof(pElem->aMem[0]) );
|
|
||||||
if( pElem==0 ) return SQLITE_NOMEM;
|
|
||||||
pElem->zKey = (char*)&pElem->aMem[p->nMem];
|
|
||||||
memcpy(pElem->zKey, zKey, nKey);
|
|
||||||
pElem->nKey = nKey;
|
|
||||||
|
|
||||||
if( p->pCsr ){
|
|
||||||
rc = sqlite3BtreeInsert(p->pCsr, zKey, nKey, &pElem, sizeof(AggElem*));
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
sqliteFree(pElem);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i=0; i<p->nMem; i++){
|
|
||||||
pElem->aMem[i].flags = MEM_Null;
|
|
||||||
}
|
|
||||||
p->pCurrent = pElem;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Pop the stack N times.
|
** Pop the stack N times.
|
||||||
*/
|
*/
|
||||||
|
@ -205,39 +173,6 @@ static void popStack(Mem **ppTos, int N){
|
||||||
*ppTos = pTos;
|
*ppTos = pTos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
** The parameters are pointers to the head of two sorted lists
|
|
||||||
** of Sorter structures. Merge these two lists together and return
|
|
||||||
** a single sorted list. This routine forms the core of the merge-sort
|
|
||||||
** algorithm.
|
|
||||||
**
|
|
||||||
** In the case of a tie, left sorts in front of right.
|
|
||||||
*/
|
|
||||||
static Sorter *Merge(Sorter *pLeft, Sorter *pRight, KeyInfo *pKeyInfo){
|
|
||||||
Sorter sHead;
|
|
||||||
Sorter *pTail;
|
|
||||||
pTail = &sHead;
|
|
||||||
pTail->pNext = 0;
|
|
||||||
while( pLeft && pRight ){
|
|
||||||
int c = sqlite3VdbeRecordCompare(pKeyInfo, pLeft->nKey, pLeft->zKey,
|
|
||||||
pRight->nKey, pRight->zKey);
|
|
||||||
if( c<=0 ){
|
|
||||||
pTail->pNext = pLeft;
|
|
||||||
pLeft = pLeft->pNext;
|
|
||||||
}else{
|
|
||||||
pTail->pNext = pRight;
|
|
||||||
pRight = pRight->pNext;
|
|
||||||
}
|
|
||||||
pTail = pTail->pNext;
|
|
||||||
}
|
|
||||||
if( pLeft ){
|
|
||||||
pTail->pNext = pLeft;
|
|
||||||
}else if( pRight ){
|
|
||||||
pTail->pNext = pRight;
|
|
||||||
}
|
|
||||||
return sHead.pNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Allocate cursor number iCur. Return a pointer to it. Return NULL
|
** Allocate cursor number iCur. Return a pointer to it. Return NULL
|
||||||
** if we run out of memory.
|
** if we run out of memory.
|
||||||
|
@ -635,7 +570,7 @@ case OP_Return: { /* no-push */
|
||||||
|
|
||||||
/* Opcode: Halt P1 P2 P3
|
/* Opcode: Halt P1 P2 P3
|
||||||
**
|
**
|
||||||
** Exit immediately. All open cursors, Lists, Sorts, etc are closed
|
** Exit immediately. All open cursors, Fifos, etc are closed
|
||||||
** automatically.
|
** automatically.
|
||||||
**
|
**
|
||||||
** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(),
|
** P1 is the result code returned by sqlite3_exec(), sqlite3_reset(),
|
||||||
|
@ -773,6 +708,7 @@ case OP_String: {
|
||||||
case OP_Null: {
|
case OP_Null: {
|
||||||
pTos++;
|
pTos++;
|
||||||
pTos->flags = MEM_Null;
|
pTos->flags = MEM_Null;
|
||||||
|
pTos->n = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1164,26 +1100,25 @@ case OP_CollSeq: { /* no-push */
|
||||||
/* Opcode: Function P1 P2 P3
|
/* Opcode: Function P1 P2 P3
|
||||||
**
|
**
|
||||||
** Invoke a user function (P3 is a pointer to a Function structure that
|
** Invoke a user function (P3 is a pointer to a Function structure that
|
||||||
** defines the function) with P1 arguments taken from the stack. Pop all
|
** defines the function) with P2 arguments taken from the stack. Pop all
|
||||||
** arguments from the stack and push back the result.
|
** arguments from the stack and push back the result.
|
||||||
**
|
**
|
||||||
** P2 is a 32-bit bitmask indicating whether or not each argument to the
|
** P1 is a 32-bit bitmask indicating whether or not each argument to the
|
||||||
** function was determined to be constant at compile time. If the first
|
** function was determined to be constant at compile time. If the first
|
||||||
** argument was constant then bit 0 of P2 is set. This is used to determine
|
** argument was constant then bit 0 of P1 is set. This is used to determine
|
||||||
** whether meta data associated with a user function argument using the
|
** whether meta data associated with a user function argument using the
|
||||||
** sqlite3_set_auxdata() API may be safely retained until the next
|
** sqlite3_set_auxdata() API may be safely retained until the next
|
||||||
** invocation of this opcode.
|
** invocation of this opcode.
|
||||||
**
|
**
|
||||||
** See also: AggFunc
|
** See also: AggStep and AggFinal
|
||||||
*/
|
*/
|
||||||
case OP_Function: {
|
case OP_Function: {
|
||||||
int i;
|
int i;
|
||||||
Mem *pArg;
|
Mem *pArg;
|
||||||
sqlite3_context ctx;
|
sqlite3_context ctx;
|
||||||
sqlite3_value **apVal;
|
sqlite3_value **apVal;
|
||||||
int n = pOp->p1;
|
int n = pOp->p2;
|
||||||
|
|
||||||
n = pOp->p1;
|
|
||||||
apVal = p->apArg;
|
apVal = p->apArg;
|
||||||
assert( apVal || n==0 );
|
assert( apVal || n==0 );
|
||||||
|
|
||||||
|
@ -1222,7 +1157,7 @@ case OP_Function: {
|
||||||
** immediately call the destructor for any non-static values.
|
** immediately call the destructor for any non-static values.
|
||||||
*/
|
*/
|
||||||
if( ctx.pVdbeFunc ){
|
if( ctx.pVdbeFunc ){
|
||||||
sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p2);
|
sqlite3VdbeDeleteAuxData(ctx.pVdbeFunc, pOp->p1);
|
||||||
pOp->p3 = (char *)ctx.pVdbeFunc;
|
pOp->p3 = (char *)ctx.pVdbeFunc;
|
||||||
pOp->p3type = P3_VDBEFUNC;
|
pOp->p3type = P3_VDBEFUNC;
|
||||||
}
|
}
|
||||||
|
@ -1476,9 +1411,16 @@ case OP_ToBlob: { /* no-push */
|
||||||
** jump to instruction P2. Otherwise, continue to the next instruction.
|
** jump to instruction P2. Otherwise, continue to the next instruction.
|
||||||
**
|
**
|
||||||
** If the 0x100 bit of P1 is true and either operand is NULL then take the
|
** If the 0x100 bit of P1 is true and either operand is NULL then take the
|
||||||
** jump. If the 0x100 bit of P1 is false then fall thru if either operand
|
** jump. If the 0x100 bit of P1 is clear then fall thru if either operand
|
||||||
** is NULL.
|
** is NULL.
|
||||||
**
|
**
|
||||||
|
** If the 0x200 bit of P1 is set and either operand is NULL then
|
||||||
|
** both operands are converted to integers prior to comparison.
|
||||||
|
** NULL operands are converted to zero and non-NULL operands are
|
||||||
|
** converted to 1. Thus, for example, with 0x200 set, NULL==NULL is true
|
||||||
|
** whereas it would normally be NULL. Similarly, NULL==123 is false when
|
||||||
|
** 0x200 is set but is NULL when the 0x200 bit of P1 is clear.
|
||||||
|
**
|
||||||
** The least significant byte of P1 (mask 0xff) must be an affinity character -
|
** The least significant byte of P1 (mask 0xff) must be an affinity character -
|
||||||
** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values
|
** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values
|
||||||
** according to the affinity before the comparison is made. If the byte is
|
** according to the affinity before the comparison is made. If the byte is
|
||||||
|
@ -1546,15 +1488,37 @@ case OP_Ge: { /* same as TK_GE, no-push */
|
||||||
** the stack.
|
** the stack.
|
||||||
*/
|
*/
|
||||||
if( flags&MEM_Null ){
|
if( flags&MEM_Null ){
|
||||||
|
if( (pOp->p1 & 0x200)!=0 ){
|
||||||
|
/* The 0x200 bit of P1 means, roughly "do not treat NULL as the
|
||||||
|
** magic SQL value it normally is - treat it as if it were another
|
||||||
|
** integer".
|
||||||
|
**
|
||||||
|
** With 0x200 set, if either operand is NULL then both operands
|
||||||
|
** are converted to integers prior to being passed down into the
|
||||||
|
** normal comparison logic below. NULL operands are converted to
|
||||||
|
** zero and non-NULL operands are converted to 1. Thus, for example,
|
||||||
|
** with 0x200 set, NULL==NULL is true whereas it would normally
|
||||||
|
** be NULL. Similarly, NULL!=123 is true.
|
||||||
|
*/
|
||||||
|
sqlite3VdbeMemSetInt64(pTos, (pTos->flags & MEM_Null)==0);
|
||||||
|
sqlite3VdbeMemSetInt64(pNos, (pNos->flags & MEM_Null)==0);
|
||||||
|
}else{
|
||||||
|
/* If the 0x200 bit of P1 is clear and either operand is NULL then
|
||||||
|
** the result is always NULL. The jump is taken if the 0x100 bit
|
||||||
|
** of P1 is set.
|
||||||
|
*/
|
||||||
popStack(&pTos, 2);
|
popStack(&pTos, 2);
|
||||||
if( pOp->p2 ){
|
if( pOp->p2 ){
|
||||||
if( pOp->p1 & 0x100 ) pc = pOp->p2-1;
|
if( pOp->p1 & 0x100 ){
|
||||||
|
pc = pOp->p2-1;
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
pTos++;
|
pTos++;
|
||||||
pTos->flags = MEM_Null;
|
pTos->flags = MEM_Null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
affinity = pOp->p1 & 0xFF;
|
affinity = pOp->p1 & 0xFF;
|
||||||
if( affinity ){
|
if( affinity ){
|
||||||
|
@ -1710,6 +1674,13 @@ case OP_BitNot: { /* same as TK_BITNOT, no-push */
|
||||||
** Do nothing. This instruction is often useful as a jump
|
** Do nothing. This instruction is often useful as a jump
|
||||||
** destination.
|
** destination.
|
||||||
*/
|
*/
|
||||||
|
/*
|
||||||
|
** The magic Explain opcode are only inserted when explain==2 (which
|
||||||
|
** is to say when the EXPLAIN QUERY PLAN syntax is used.)
|
||||||
|
** This opcode records information from the optimizer. It is the
|
||||||
|
** the same as a no-op. This opcodesnever appears in a real VM program.
|
||||||
|
*/
|
||||||
|
case OP_Explain:
|
||||||
case OP_Noop: { /* no-push */
|
case OP_Noop: { /* no-push */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2020,7 +1991,7 @@ case OP_Column: {
|
||||||
** we are dealing with a malformed record.
|
** we are dealing with a malformed record.
|
||||||
*/
|
*/
|
||||||
if( idx!=szHdr || offset!=payloadSize ){
|
if( idx!=szHdr || offset!=payloadSize ){
|
||||||
rc = SQLITE_CORRUPT;
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
goto op_column_out;
|
goto op_column_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2574,7 +2545,7 @@ case OP_OpenWrite: { /* no-push */
|
||||||
** only mean that we are dealing with a corrupt database file
|
** only mean that we are dealing with a corrupt database file
|
||||||
*/
|
*/
|
||||||
if( (flags & 0xf0)!=0 || ((flags & 0x07)!=5 && (flags & 0x07)!=2) ){
|
if( (flags & 0xf0)!=0 || ((flags & 0x07)!=5 && (flags & 0x07)!=2) ){
|
||||||
rc = SQLITE_CORRUPT;
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
goto abort_due_to_error;
|
goto abort_due_to_error;
|
||||||
}
|
}
|
||||||
pCur->isTable = (flags & BTREE_INTKEY)!=0;
|
pCur->isTable = (flags & BTREE_INTKEY)!=0;
|
||||||
|
@ -2585,7 +2556,7 @@ case OP_OpenWrite: { /* no-push */
|
||||||
*/
|
*/
|
||||||
if( (pCur->isTable && pOp->p3type==P3_KEYINFO)
|
if( (pCur->isTable && pOp->p3type==P3_KEYINFO)
|
||||||
|| (pCur->isIndex && pOp->p3type!=P3_KEYINFO) ){
|
|| (pCur->isIndex && pOp->p3type!=P3_KEYINFO) ){
|
||||||
rc = SQLITE_CORRUPT;
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
goto abort_due_to_error;
|
goto abort_due_to_error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2603,13 +2574,14 @@ case OP_OpenWrite: { /* no-push */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: OpenVirtual P1 * P3
|
/* Opcode: OpenVirtual P1 P2 P3
|
||||||
**
|
**
|
||||||
** Open a new cursor to a transient or virtual table.
|
** Open a new cursor P1 to a transient or virtual table.
|
||||||
** The cursor is always opened read/write even if
|
** The cursor is always opened read/write even if
|
||||||
** the main database is read-only. The transient or virtual
|
** the main database is read-only. The transient or virtual
|
||||||
** table is deleted automatically when the cursor is closed.
|
** table is deleted automatically when the cursor is closed.
|
||||||
**
|
**
|
||||||
|
** P2 is the number of columns in the virtual table.
|
||||||
** The cursor points to a BTree table if P3==0 and to a BTree index
|
** The cursor points to a BTree table if P3==0 and to a BTree index
|
||||||
** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure
|
** if P3 is not 0. If P3 is not NULL, it points to a KeyInfo structure
|
||||||
** that defines the format of keys in the index.
|
** that defines the format of keys in the index.
|
||||||
|
@ -2650,6 +2622,7 @@ case OP_OpenVirtual: { /* no-push */
|
||||||
pCx->pIncrKey = &pCx->bogusIncrKey;
|
pCx->pIncrKey = &pCx->bogusIncrKey;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pCx->nField = pOp->p2;
|
||||||
pCx->isIndex = !pCx->isTable;
|
pCx->isIndex = !pCx->isTable;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3035,6 +3008,24 @@ case OP_NotExists: { /* no-push */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Opcode: Sequence P1 * *
|
||||||
|
**
|
||||||
|
** Push an integer onto the stack which is the next available
|
||||||
|
** sequence number for cursor P1. The sequence number on the
|
||||||
|
** cursor is incremented after the push.
|
||||||
|
*/
|
||||||
|
case OP_Sequence: {
|
||||||
|
int i = pOp->p1;
|
||||||
|
assert( pTos>=p->aStack );
|
||||||
|
assert( i>=0 && i<p->nCursor );
|
||||||
|
assert( p->apCsr[i]!=0 );
|
||||||
|
pTos++;
|
||||||
|
pTos->i = p->apCsr[i]->seqCount++;
|
||||||
|
pTos->flags = MEM_Int;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Opcode: NewRowid P1 P2 *
|
/* Opcode: NewRowid P1 P2 *
|
||||||
**
|
**
|
||||||
** Get a new integer record number (a.k.a "rowid") used as the key to a table.
|
** Get a new integer record number (a.k.a "rowid") used as the key to a table.
|
||||||
|
@ -3094,7 +3085,7 @@ case OP_NewRowid: {
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
if( (sqlite3BtreeFlags(pC->pCursor)&(BTREE_INTKEY|BTREE_ZERODATA)) !=
|
if( (sqlite3BtreeFlags(pC->pCursor)&(BTREE_INTKEY|BTREE_ZERODATA)) !=
|
||||||
BTREE_INTKEY ){
|
BTREE_INTKEY ){
|
||||||
rc = SQLITE_CORRUPT;
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
goto abort_due_to_error;
|
goto abort_due_to_error;
|
||||||
}
|
}
|
||||||
assert( (sqlite3BtreeFlags(pC->pCursor) & BTREE_INTKEY)!=0 );
|
assert( (sqlite3BtreeFlags(pC->pCursor) & BTREE_INTKEY)!=0 );
|
||||||
|
@ -3464,6 +3455,24 @@ case OP_Last: { /* no-push */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Opcode: Sort P1 P2 *
|
||||||
|
**
|
||||||
|
** This opcode does exactly the same thing as OP_Rewind except that
|
||||||
|
** it increments an undocumented global variable used for testing.
|
||||||
|
**
|
||||||
|
** Sorting is accomplished by writing records into a sorting index,
|
||||||
|
** then rewinding that index and playing it back from beginning to
|
||||||
|
** end. We use the OP_Sort opcode instead of OP_Rewind to do the
|
||||||
|
** rewinding so that the global variable will be incremented and
|
||||||
|
** regression tests can determine whether or not the optimizer is
|
||||||
|
** correctly optimizing out sorts.
|
||||||
|
*/
|
||||||
|
case OP_Sort: { /* no-push */
|
||||||
|
sqlite3_sort_count++;
|
||||||
|
sqlite3_search_count--;
|
||||||
|
/* Fall through into OP_Rewind */
|
||||||
|
}
|
||||||
/* Opcode: Rewind P1 P2 *
|
/* Opcode: Rewind P1 P2 *
|
||||||
**
|
**
|
||||||
** The next use of the Rowid or Column or Next instruction for P1
|
** The next use of the Rowid or Column or Next instruction for P1
|
||||||
|
@ -3685,13 +3694,12 @@ case OP_IdxLT: /* no-push */
|
||||||
case OP_IdxGT: /* no-push */
|
case OP_IdxGT: /* no-push */
|
||||||
case OP_IdxGE: { /* no-push */
|
case OP_IdxGE: { /* no-push */
|
||||||
int i= pOp->p1;
|
int i= pOp->p1;
|
||||||
BtCursor *pCrsr;
|
|
||||||
Cursor *pC;
|
Cursor *pC;
|
||||||
|
|
||||||
assert( i>=0 && i<p->nCursor );
|
assert( i>=0 && i<p->nCursor );
|
||||||
assert( p->apCsr[i]!=0 );
|
assert( p->apCsr[i]!=0 );
|
||||||
assert( pTos>=p->aStack );
|
assert( pTos>=p->aStack );
|
||||||
if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){
|
if( (pC = p->apCsr[i])->pCursor!=0 ){
|
||||||
int res, rc;
|
int res, rc;
|
||||||
|
|
||||||
assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */
|
assert( pTos->flags & MEM_Blob ); /* Created using OP_Make*Key */
|
||||||
|
@ -4023,31 +4031,6 @@ case OP_FifoRead: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_SUBQUERY
|
|
||||||
/* Opcode: AggContextPush * * *
|
|
||||||
**
|
|
||||||
** Save the state of the current aggregator. It is restored an
|
|
||||||
** AggContextPop opcode.
|
|
||||||
**
|
|
||||||
*/
|
|
||||||
case OP_AggContextPush: { /* no-push */
|
|
||||||
p->pAgg++;
|
|
||||||
assert( p->pAgg<&p->apAgg[p->nAgg] );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Opcode: AggContextPop * * *
|
|
||||||
**
|
|
||||||
** Restore the aggregator to the state it was in when AggContextPush
|
|
||||||
** was last called. Any data in the current aggregator is deleted.
|
|
||||||
*/
|
|
||||||
case OP_AggContextPop: { /* no-push */
|
|
||||||
p->pAgg--;
|
|
||||||
assert( p->pAgg>=p->apAgg );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_TRIGGER
|
#ifndef SQLITE_OMIT_TRIGGER
|
||||||
/* Opcode: ContextPush * * *
|
/* Opcode: ContextPush * * *
|
||||||
**
|
**
|
||||||
|
@ -4063,7 +4046,7 @@ case OP_ContextPush: { /* no-push */
|
||||||
/* FIX ME: This should be allocated as part of the vdbe at compile-time */
|
/* FIX ME: This should be allocated as part of the vdbe at compile-time */
|
||||||
if( i>=p->contextStackDepth ){
|
if( i>=p->contextStackDepth ){
|
||||||
p->contextStackDepth = i+1;
|
p->contextStackDepth = i+1;
|
||||||
p->contextStack = sqliteRealloc(p->contextStack, sizeof(Context)*(i+1));
|
sqlite3ReallocOrFree((void**)&p->contextStack, sizeof(Context)*(i+1));
|
||||||
if( p->contextStack==0 ) goto no_mem;
|
if( p->contextStack==0 ) goto no_mem;
|
||||||
}
|
}
|
||||||
pContext = &p->contextStack[i];
|
pContext = &p->contextStack[i];
|
||||||
|
@ -4091,108 +4074,6 @@ case OP_ContextPop: { /* no-push */
|
||||||
}
|
}
|
||||||
#endif /* #ifndef SQLITE_OMIT_TRIGGER */
|
#endif /* #ifndef SQLITE_OMIT_TRIGGER */
|
||||||
|
|
||||||
/* Opcode: SortInsert * * *
|
|
||||||
**
|
|
||||||
** The TOS is the key and the NOS is the data. Pop both from the stack
|
|
||||||
** and put them on the sorter. The key and data should have been
|
|
||||||
** made using the MakeRecord opcode.
|
|
||||||
*/
|
|
||||||
case OP_SortInsert: { /* no-push */
|
|
||||||
Mem *pNos = &pTos[-1];
|
|
||||||
Sorter *pSorter;
|
|
||||||
assert( pNos>=p->aStack );
|
|
||||||
if( Dynamicify(pTos, db->enc) ) goto no_mem;
|
|
||||||
pSorter = sqliteMallocRaw( sizeof(Sorter) );
|
|
||||||
if( pSorter==0 ) goto no_mem;
|
|
||||||
pSorter->pNext = 0;
|
|
||||||
if( p->pSortTail ){
|
|
||||||
p->pSortTail->pNext = pSorter;
|
|
||||||
}else{
|
|
||||||
p->pSort = pSorter;
|
|
||||||
}
|
|
||||||
p->pSortTail = pSorter;
|
|
||||||
assert( pTos->flags & MEM_Dyn );
|
|
||||||
pSorter->nKey = pTos->n;
|
|
||||||
pSorter->zKey = pTos->z;
|
|
||||||
pSorter->data.flags = MEM_Null;
|
|
||||||
rc = sqlite3VdbeMemMove(&pSorter->data, pNos);
|
|
||||||
pTos -= 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Opcode: Sort * * P3
|
|
||||||
**
|
|
||||||
** Sort all elements on the sorter. The algorithm is a
|
|
||||||
** mergesort. The P3 argument is a pointer to a KeyInfo structure
|
|
||||||
** that describes the keys to be sorted.
|
|
||||||
*/
|
|
||||||
case OP_Sort: { /* no-push */
|
|
||||||
int i;
|
|
||||||
KeyInfo *pKeyInfo = (KeyInfo*)pOp->p3;
|
|
||||||
Sorter *pElem;
|
|
||||||
Sorter *apSorter[NSORT];
|
|
||||||
sqlite3_sort_count++;
|
|
||||||
pKeyInfo->enc = p->db->enc;
|
|
||||||
for(i=0; i<NSORT; i++){
|
|
||||||
apSorter[i] = 0;
|
|
||||||
}
|
|
||||||
while( p->pSort ){
|
|
||||||
pElem = p->pSort;
|
|
||||||
p->pSort = pElem->pNext;
|
|
||||||
pElem->pNext = 0;
|
|
||||||
for(i=0; i<NSORT-1; i++){
|
|
||||||
if( apSorter[i]==0 ){
|
|
||||||
apSorter[i] = pElem;
|
|
||||||
break;
|
|
||||||
}else{
|
|
||||||
pElem = Merge(apSorter[i], pElem, pKeyInfo);
|
|
||||||
apSorter[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( i>=NSORT-1 ){
|
|
||||||
apSorter[NSORT-1] = Merge(apSorter[NSORT-1],pElem, pKeyInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pElem = 0;
|
|
||||||
for(i=0; i<NSORT; i++){
|
|
||||||
pElem = Merge(apSorter[i], pElem, pKeyInfo);
|
|
||||||
}
|
|
||||||
p->pSort = pElem;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Opcode: SortNext * P2 *
|
|
||||||
**
|
|
||||||
** Push the data for the topmost element in the sorter onto the
|
|
||||||
** stack, then remove the element from the sorter. If the sorter
|
|
||||||
** is empty, push nothing on the stack and instead jump immediately
|
|
||||||
** to instruction P2.
|
|
||||||
*/
|
|
||||||
case OP_SortNext: {
|
|
||||||
Sorter *pSorter = p->pSort;
|
|
||||||
CHECK_FOR_INTERRUPT;
|
|
||||||
if( pSorter!=0 ){
|
|
||||||
p->pSort = pSorter->pNext;
|
|
||||||
pTos++;
|
|
||||||
pTos->flags = MEM_Null;
|
|
||||||
rc = sqlite3VdbeMemMove(pTos, &pSorter->data);
|
|
||||||
sqliteFree(pSorter->zKey);
|
|
||||||
sqliteFree(pSorter);
|
|
||||||
}else{
|
|
||||||
pc = pOp->p2 - 1;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Opcode: SortReset * * *
|
|
||||||
**
|
|
||||||
** Remove any elements that remain on the sorter.
|
|
||||||
*/
|
|
||||||
case OP_SortReset: { /* no-push */
|
|
||||||
sqlite3VdbeSorterReset(p);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Opcode: MemStore P1 P2 *
|
/* Opcode: MemStore P1 P2 *
|
||||||
**
|
**
|
||||||
** Write the top of the stack into memory location P1.
|
** Write the top of the stack into memory location P1.
|
||||||
|
@ -4296,64 +4177,49 @@ case OP_IfMemPos: { /* no-push */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: AggReset P1 P2 P3
|
/* Opcode: MemNull P1 * *
|
||||||
**
|
**
|
||||||
** Reset the current aggregator context so that it no longer contains any
|
** Store a NULL in memory cell P1
|
||||||
** data. Future aggregator elements will contain P2 values each and be sorted
|
|
||||||
** using the KeyInfo structure pointed to by P3.
|
|
||||||
**
|
|
||||||
** If P1 is non-zero, then only a single aggregator row is available (i.e.
|
|
||||||
** there is no GROUP BY expression). In this case it is illegal to invoke
|
|
||||||
** OP_AggFocus.
|
|
||||||
*/
|
*/
|
||||||
case OP_AggReset: { /* no-push */
|
case OP_MemNull: {
|
||||||
assert( !pOp->p3 || pOp->p3type==P3_KEYINFO );
|
assert( pOp->p1>=0 && pOp->p1<p->nMem );
|
||||||
if( pOp->p1 ){
|
sqlite3VdbeMemSetNull(&p->aMem[pOp->p1]);
|
||||||
rc = sqlite3VdbeAggReset(0, p->pAgg, (KeyInfo *)pOp->p3);
|
|
||||||
p->pAgg->nMem = pOp->p2; /* Agg.nMem is used by AggInsert() */
|
|
||||||
rc = AggInsert(p->pAgg, 0, 0);
|
|
||||||
}else{
|
|
||||||
rc = sqlite3VdbeAggReset(db, p->pAgg, (KeyInfo *)pOp->p3);
|
|
||||||
p->pAgg->nMem = pOp->p2;
|
|
||||||
}
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
goto abort_due_to_error;
|
|
||||||
}
|
|
||||||
p->pAgg->apFunc = sqliteMalloc( p->pAgg->nMem*sizeof(p->pAgg->apFunc[0]) );
|
|
||||||
if( p->pAgg->apFunc==0 ) goto no_mem;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: AggInit P1 P2 P3
|
/* Opcode: MemInt P1 P2 *
|
||||||
**
|
**
|
||||||
** Initialize the function parameters for an aggregate function.
|
** Store the integer value P1 in memory cell P2.
|
||||||
** The aggregate will operate out of aggregate column P2.
|
|
||||||
** P3 is a pointer to the FuncDef structure for the function.
|
|
||||||
**
|
|
||||||
** The P1 argument is not used by this opcode. However if the SSE
|
|
||||||
** extension is compiled in, P1 is set to the number of arguments that
|
|
||||||
** will be passed to the aggregate function, if any. This is used
|
|
||||||
** by SSE to select the correct function when (de)serializing statements.
|
|
||||||
*/
|
*/
|
||||||
case OP_AggInit: { /* no-push */
|
case OP_MemInt: {
|
||||||
int i = pOp->p2;
|
assert( pOp->p2>=0 && pOp->p2<p->nMem );
|
||||||
assert( i>=0 && i<p->pAgg->nMem );
|
sqlite3VdbeMemSetInt64(&p->aMem[pOp->p2], pOp->p1);
|
||||||
p->pAgg->apFunc[i] = (FuncDef*)pOp->p3;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: AggFunc * P2 P3
|
/* Opcode: MemMove P1 P2 *
|
||||||
|
**
|
||||||
|
** Move the content of memory cell P2 over to memory cell P1.
|
||||||
|
** Any prior content of P1 is erased. Memory cell P2 is left
|
||||||
|
** containing a NULL.
|
||||||
|
*/
|
||||||
|
case OP_MemMove: {
|
||||||
|
assert( pOp->p1>=0 && pOp->p1<p->nMem );
|
||||||
|
assert( pOp->p2>=0 && pOp->p2<p->nMem );
|
||||||
|
rc = sqlite3VdbeMemMove(&p->aMem[pOp->p1], &p->aMem[pOp->p2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Opcode: AggStep P1 P2 P3
|
||||||
**
|
**
|
||||||
** Execute the step function for an aggregate. The
|
** Execute the step function for an aggregate. The
|
||||||
** function has P2 arguments. P3 is a pointer to the FuncDef
|
** function has P2 arguments. P3 is a pointer to the FuncDef
|
||||||
** structure that specifies the function.
|
** structure that specifies the function. Use memory location
|
||||||
|
** P1 as the accumulator.
|
||||||
**
|
**
|
||||||
** The top of the stack must be an integer which is the index of
|
** The P2 arguments are popped from the stack.
|
||||||
** the aggregate column that corresponds to this aggregate function.
|
|
||||||
** Ideally, this index would be another parameter, but there are
|
|
||||||
** no free parameters left. The integer is popped from the stack.
|
|
||||||
*/
|
*/
|
||||||
case OP_AggFunc: { /* no-push */
|
case OP_AggStep: { /* no-push */
|
||||||
int n = pOp->p2;
|
int n = pOp->p2;
|
||||||
int i;
|
int i;
|
||||||
Mem *pMem, *pRec;
|
Mem *pMem, *pRec;
|
||||||
|
@ -4361,24 +4227,18 @@ case OP_AggFunc: { /* no-push */
|
||||||
sqlite3_value **apVal;
|
sqlite3_value **apVal;
|
||||||
|
|
||||||
assert( n>=0 );
|
assert( n>=0 );
|
||||||
assert( pTos->flags==MEM_Int );
|
pRec = &pTos[1-n];
|
||||||
pRec = &pTos[-n];
|
|
||||||
assert( pRec>=p->aStack );
|
assert( pRec>=p->aStack );
|
||||||
|
|
||||||
apVal = p->apArg;
|
apVal = p->apArg;
|
||||||
assert( apVal || n==0 );
|
assert( apVal || n==0 );
|
||||||
|
|
||||||
for(i=0; i<n; i++, pRec++){
|
for(i=0; i<n; i++, pRec++){
|
||||||
apVal[i] = pRec;
|
apVal[i] = pRec;
|
||||||
storeTypeInfo(pRec, db->enc);
|
storeTypeInfo(pRec, db->enc);
|
||||||
}
|
}
|
||||||
i = pTos->i;
|
|
||||||
assert( i>=0 && i<p->pAgg->nMem );
|
|
||||||
ctx.pFunc = (FuncDef*)pOp->p3;
|
ctx.pFunc = (FuncDef*)pOp->p3;
|
||||||
pMem = &p->pAgg->pCurrent->aMem[i];
|
assert( pOp->p1>=0 && pOp->p1<p->nMem );
|
||||||
ctx.s.z = pMem->zShort; /* Space used for small aggregate contexts */
|
ctx.pMem = pMem = &p->aMem[pOp->p1];
|
||||||
ctx.pAgg = pMem->z;
|
pMem->n++;
|
||||||
ctx.cnt = ++pMem->i;
|
|
||||||
ctx.isError = 0;
|
ctx.isError = 0;
|
||||||
ctx.pColl = 0;
|
ctx.pColl = 0;
|
||||||
if( ctx.pFunc->needCollSeq ){
|
if( ctx.pFunc->needCollSeq ){
|
||||||
|
@ -4388,182 +4248,34 @@ case OP_AggFunc: { /* no-push */
|
||||||
ctx.pColl = (CollSeq *)pOp[-1].p3;
|
ctx.pColl = (CollSeq *)pOp[-1].p3;
|
||||||
}
|
}
|
||||||
(ctx.pFunc->xStep)(&ctx, n, apVal);
|
(ctx.pFunc->xStep)(&ctx, n, apVal);
|
||||||
pMem->z = ctx.pAgg;
|
popStack(&pTos, n);
|
||||||
pMem->flags = MEM_AggCtx;
|
|
||||||
popStack(&pTos, n+1);
|
|
||||||
if( ctx.isError ){
|
if( ctx.isError ){
|
||||||
rc = SQLITE_ERROR;
|
rc = SQLITE_ERROR;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: AggFocus * P2 *
|
/* Opcode: AggFinal P1 P2 P3
|
||||||
**
|
**
|
||||||
** Pop the top of the stack and use that as an aggregator key. If
|
** Execute the finalizer function for an aggregate. P1 is
|
||||||
** an aggregator with that same key already exists, then make the
|
** the memory location that is the accumulator for the aggregate.
|
||||||
** aggregator the current aggregator and jump to P2. If no aggregator
|
|
||||||
** with the given key exists, create one and make it current but
|
|
||||||
** do not jump.
|
|
||||||
**
|
**
|
||||||
** The order of aggregator opcodes is important. The order is:
|
** P2 is the number of arguments that the step function takes and
|
||||||
** AggReset AggFocus AggNext. In other words, you must execute
|
** P3 is a pointer to the FuncDef for this function. The P2
|
||||||
** AggReset first, then zero or more AggFocus operations, then
|
** argument is not used by this opcode. It is only there to disambiguate
|
||||||
** zero or more AggNext operations. You must not execute an AggFocus
|
** functions that can take varying numbers of arguments. The
|
||||||
** in between an AggNext and an AggReset.
|
** P3 argument is only needed for the degenerate case where
|
||||||
|
** the step function was not previously called.
|
||||||
*/
|
*/
|
||||||
case OP_AggFocus: { /* no-push */
|
case OP_AggFinal: { /* no-push */
|
||||||
char *zKey;
|
Mem *pMem;
|
||||||
int nKey;
|
assert( pOp->p1>=0 && pOp->p1<p->nMem );
|
||||||
int res;
|
pMem = &p->aMem[pOp->p1];
|
||||||
assert( pTos>=p->aStack );
|
assert( (pMem->flags & ~(MEM_Null|MEM_Agg))==0 );
|
||||||
Stringify(pTos, db->enc);
|
sqlite3VdbeMemFinalize(pMem, (FuncDef*)pOp->p3);
|
||||||
zKey = pTos->z;
|
|
||||||
nKey = pTos->n;
|
|
||||||
assert( p->pAgg->pBtree );
|
|
||||||
assert( p->pAgg->pCsr );
|
|
||||||
rc = sqlite3BtreeMoveto(p->pAgg->pCsr, zKey, nKey, &res);
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
goto abort_due_to_error;
|
|
||||||
}
|
|
||||||
if( res==0 ){
|
|
||||||
rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
|
|
||||||
(char *)&p->pAgg->pCurrent);
|
|
||||||
pc = pOp->p2 - 1;
|
|
||||||
}else{
|
|
||||||
rc = AggInsert(p->pAgg, zKey, nKey);
|
|
||||||
}
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
goto abort_due_to_error;
|
|
||||||
}
|
|
||||||
Release(pTos);
|
|
||||||
pTos--;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Opcode: AggSet * P2 *
|
|
||||||
**
|
|
||||||
** Move the top of the stack into the P2-th field of the current
|
|
||||||
** aggregate. String values are duplicated into new memory.
|
|
||||||
*/
|
|
||||||
case OP_AggSet: { /* no-push */
|
|
||||||
AggElem *pFocus;
|
|
||||||
int i = pOp->p2;
|
|
||||||
pFocus = p->pAgg->pCurrent;
|
|
||||||
assert( pTos>=p->aStack );
|
|
||||||
if( pFocus==0 ) goto no_mem;
|
|
||||||
assert( i>=0 && i<p->pAgg->nMem );
|
|
||||||
rc = sqlite3VdbeMemMove(&pFocus->aMem[i], pTos);
|
|
||||||
pTos--;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Opcode: AggGet P1 P2 *
|
|
||||||
**
|
|
||||||
** Push a new entry onto the stack which is a copy of the P2-th field
|
|
||||||
** of the current aggregate. Strings are not duplicated so
|
|
||||||
** string values will be ephemeral.
|
|
||||||
**
|
|
||||||
** If P1 is zero, then the value is pulled out of the current aggregate
|
|
||||||
** in the current aggregate context. If P1 is greater than zero, then
|
|
||||||
** the value is taken from the P1th outer aggregate context. (i.e. if
|
|
||||||
** P1==1 then read from the aggregate context that will be restored
|
|
||||||
** by the next OP_AggContextPop opcode).
|
|
||||||
*/
|
|
||||||
case OP_AggGet: {
|
|
||||||
AggElem *pFocus;
|
|
||||||
int i = pOp->p2;
|
|
||||||
Agg *pAgg = &p->pAgg[-pOp->p1];
|
|
||||||
assert( pAgg>=p->apAgg );
|
|
||||||
pFocus = pAgg->pCurrent;
|
|
||||||
if( pFocus==0 ){
|
|
||||||
int res;
|
|
||||||
if( sqlite3_malloc_failed ) goto no_mem;
|
|
||||||
rc = sqlite3BtreeFirst(pAgg->pCsr, &res);
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if( res!=0 ){
|
|
||||||
rc = AggInsert(pAgg, "", 1);
|
|
||||||
pFocus = pAgg->pCurrent;
|
|
||||||
}else{
|
|
||||||
rc = sqlite3BtreeData(pAgg->pCsr, 0, 4, (char *)&pFocus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert( i>=0 && i<pAgg->nMem );
|
|
||||||
pTos++;
|
|
||||||
sqlite3VdbeMemShallowCopy(pTos, &pFocus->aMem[i], MEM_Ephem);
|
|
||||||
if( pTos->flags&MEM_Str ){
|
|
||||||
sqlite3VdbeChangeEncoding(pTos, db->enc);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Opcode: AggNext * P2 *
|
|
||||||
**
|
|
||||||
** Make the next aggregate value the current aggregate. The prior
|
|
||||||
** aggregate is deleted. If all aggregate values have been consumed,
|
|
||||||
** jump to P2.
|
|
||||||
**
|
|
||||||
** The order of aggregator opcodes is important. The order is:
|
|
||||||
** AggReset AggFocus AggNext. In other words, you must execute
|
|
||||||
** AggReset first, then zero or more AggFocus operations, then
|
|
||||||
** zero or more AggNext operations. You must not execute an AggFocus
|
|
||||||
** in between an AggNext and an AggReset.
|
|
||||||
*/
|
|
||||||
case OP_AggNext: { /* no-push */
|
|
||||||
int res;
|
|
||||||
assert( rc==SQLITE_OK );
|
|
||||||
CHECK_FOR_INTERRUPT;
|
|
||||||
if( p->pAgg->searching==0 ){
|
|
||||||
p->pAgg->searching = 1;
|
|
||||||
if( p->pAgg->pCsr ){
|
|
||||||
rc = sqlite3BtreeFirst(p->pAgg->pCsr, &res);
|
|
||||||
}else{
|
|
||||||
res = 0;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
if( p->pAgg->pCsr ){
|
|
||||||
rc = sqlite3BtreeNext(p->pAgg->pCsr, &res);
|
|
||||||
}else{
|
|
||||||
res = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
|
||||||
if( res!=0 ){
|
|
||||||
pc = pOp->p2 - 1;
|
|
||||||
}else{
|
|
||||||
int i;
|
|
||||||
sqlite3_context ctx;
|
|
||||||
Mem *aMem;
|
|
||||||
|
|
||||||
if( p->pAgg->pCsr ){
|
|
||||||
rc = sqlite3BtreeData(p->pAgg->pCsr, 0, sizeof(AggElem*),
|
|
||||||
(char *)&p->pAgg->pCurrent);
|
|
||||||
if( rc!=SQLITE_OK ) goto abort_due_to_error;
|
|
||||||
}
|
|
||||||
aMem = p->pAgg->pCurrent->aMem;
|
|
||||||
for(i=0; i<p->pAgg->nMem; i++){
|
|
||||||
FuncDef *pFunc = p->pAgg->apFunc[i];
|
|
||||||
Mem *pMem = &aMem[i];
|
|
||||||
if( pFunc==0 || pFunc->xFinalize==0 ) continue;
|
|
||||||
ctx.s.flags = MEM_Null;
|
|
||||||
ctx.s.z = pMem->zShort;
|
|
||||||
ctx.pAgg = (void*)pMem->z;
|
|
||||||
ctx.cnt = pMem->i;
|
|
||||||
ctx.pFunc = pFunc;
|
|
||||||
pFunc->xFinalize(&ctx);
|
|
||||||
pMem->z = ctx.pAgg;
|
|
||||||
if( pMem->z && pMem->z!=pMem->zShort ){
|
|
||||||
sqliteFree( pMem->z );
|
|
||||||
}
|
|
||||||
*pMem = ctx.s;
|
|
||||||
if( pMem->flags & MEM_Short ){
|
|
||||||
pMem->z = pMem->zShort;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Opcode: Vacuum * * *
|
/* Opcode: Vacuum * * *
|
||||||
**
|
**
|
||||||
|
|
|
@ -104,11 +104,12 @@ int sqlite3VdbeOp3(Vdbe*,int,int,int,const char *zP3,int);
|
||||||
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
|
int sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp);
|
||||||
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
void sqlite3VdbeChangeP1(Vdbe*, int addr, int P1);
|
||||||
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
void sqlite3VdbeChangeP2(Vdbe*, int addr, int P2);
|
||||||
|
void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
||||||
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
|
void sqlite3VdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
|
||||||
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
VdbeOp *sqlite3VdbeGetOp(Vdbe*, int);
|
||||||
int sqlite3VdbeMakeLabel(Vdbe*);
|
int sqlite3VdbeMakeLabel(Vdbe*);
|
||||||
void sqlite3VdbeDelete(Vdbe*);
|
void sqlite3VdbeDelete(Vdbe*);
|
||||||
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int,int);
|
void sqlite3VdbeMakeReady(Vdbe*,int,int,int,int);
|
||||||
int sqlite3VdbeFinalize(Vdbe*);
|
int sqlite3VdbeFinalize(Vdbe*);
|
||||||
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
void sqlite3VdbeResolveLabel(Vdbe*, int);
|
||||||
int sqlite3VdbeCurrentAddr(Vdbe*);
|
int sqlite3VdbeCurrentAddr(Vdbe*);
|
||||||
|
|
|
@ -81,6 +81,7 @@ struct Cursor {
|
||||||
u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */
|
u8 *pIncrKey; /* Pointer to pKeyInfo->incrKey */
|
||||||
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
|
||||||
int nField; /* Number of fields in the header */
|
int nField; /* Number of fields in the header */
|
||||||
|
i64 seqCount; /* Sequence counter */
|
||||||
|
|
||||||
/* Cached information about the header for the data record that the
|
/* Cached information about the header for the data record that the
|
||||||
** cursor is currently pointing to. Only valid if cacheValid is true.
|
** cursor is currently pointing to. Only valid if cacheValid is true.
|
||||||
|
@ -113,35 +114,18 @@ typedef struct Cursor Cursor;
|
||||||
** SQLITE_BLOB.
|
** SQLITE_BLOB.
|
||||||
*/
|
*/
|
||||||
struct Mem {
|
struct Mem {
|
||||||
i64 i; /* Integer value */
|
i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */
|
||||||
|
double r; /* Real value */
|
||||||
|
char *z; /* String or BLOB value */
|
||||||
int n; /* Number of characters in string value, including '\0' */
|
int n; /* Number of characters in string value, including '\0' */
|
||||||
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */
|
||||||
u8 type; /* One of MEM_Null, MEM_Str, etc. */
|
u8 type; /* One of MEM_Null, MEM_Str, etc. */
|
||||||
u8 enc; /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */
|
u8 enc; /* TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be */
|
||||||
double r; /* Real value */
|
|
||||||
char *z; /* String or BLOB value */
|
|
||||||
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
|
void (*xDel)(void *); /* If not null, call this function to delete Mem.z */
|
||||||
char zShort[NBFS]; /* Space for short strings */
|
char zShort[NBFS]; /* Space for short strings */
|
||||||
};
|
};
|
||||||
typedef struct Mem Mem;
|
typedef struct Mem Mem;
|
||||||
|
|
||||||
/*
|
|
||||||
** A sorter builds a list of elements to be sorted. Each element of
|
|
||||||
** the list is an instance of the following structure.
|
|
||||||
*/
|
|
||||||
typedef struct Sorter Sorter;
|
|
||||||
struct Sorter {
|
|
||||||
int nKey; /* Number of bytes in the key */
|
|
||||||
char *zKey; /* The key by which we will sort */
|
|
||||||
Mem data;
|
|
||||||
Sorter *pNext; /* Next in the list */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Number of buckets used for merge-sort.
|
|
||||||
*/
|
|
||||||
#define NSORT 30
|
|
||||||
|
|
||||||
/* One or more of the following flags are set to indicate the validOK
|
/* One or more of the following flags are set to indicate the validOK
|
||||||
** representations of the value stored in the Mem struct.
|
** representations of the value stored in the Mem struct.
|
||||||
**
|
**
|
||||||
|
@ -173,12 +157,7 @@ struct Sorter {
|
||||||
#define MEM_Static 0x0080 /* Mem.z points to a static string */
|
#define MEM_Static 0x0080 /* Mem.z points to a static string */
|
||||||
#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */
|
#define MEM_Ephem 0x0100 /* Mem.z points to an ephemeral string */
|
||||||
#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */
|
#define MEM_Short 0x0200 /* Mem.z points to Mem.zShort */
|
||||||
|
#define MEM_Agg 0x0400 /* Mem.z points to an agg function context */
|
||||||
/* 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 MEM_AggCtx 0x0400 /* Mem.z points to an agg function context */
|
|
||||||
|
|
||||||
|
|
||||||
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
|
/* A VdbeFunc is just a FuncDef (defined in sqliteInt.h) that contains
|
||||||
|
@ -210,41 +189,16 @@ typedef struct VdbeFunc VdbeFunc;
|
||||||
** But this file is the only place where the internal details of this
|
** But this file is the only place where the internal details of this
|
||||||
** structure are known.
|
** structure are known.
|
||||||
**
|
**
|
||||||
** This structure is defined inside of vdbe.c because it uses substructures
|
** This structure is defined inside of vdbeInt.h because it uses substructures
|
||||||
** (Mem) which are only defined there.
|
** (Mem) which are only defined there.
|
||||||
*/
|
*/
|
||||||
struct sqlite3_context {
|
struct sqlite3_context {
|
||||||
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
|
FuncDef *pFunc; /* Pointer to function information. MUST BE FIRST */
|
||||||
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
|
VdbeFunc *pVdbeFunc; /* Auxilary data, if created. */
|
||||||
Mem s; /* The return value is stored here */
|
Mem s; /* The return value is stored here */
|
||||||
void *pAgg; /* Aggregate context */
|
Mem *pMem; /* Memory cell used to store aggregate context */
|
||||||
u8 isError; /* Set to true for an error */
|
u8 isError; /* Set to true for an error */
|
||||||
int cnt; /* Number of times that the step function has been called */
|
CollSeq *pColl; /* Collating sequence */
|
||||||
CollSeq *pColl;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
** An Agg structure describes an Aggregator. Each Agg consists of
|
|
||||||
** zero or more Aggregator elements (AggElem). Each AggElem contains
|
|
||||||
** a key and one or more values. The values are used in processing
|
|
||||||
** aggregate functions in a SELECT. The key is used to implement
|
|
||||||
** the GROUP BY clause of a select.
|
|
||||||
*/
|
|
||||||
typedef struct Agg Agg;
|
|
||||||
typedef struct AggElem AggElem;
|
|
||||||
struct Agg {
|
|
||||||
int nMem; /* Number of values stored in each AggElem */
|
|
||||||
AggElem *pCurrent; /* The AggElem currently in focus */
|
|
||||||
FuncDef **apFunc; /* Information about aggregate functions */
|
|
||||||
Btree *pBtree; /* The tmp. btree used to group elements, if required. */
|
|
||||||
BtCursor *pCsr; /* Read/write cursor to the table in pBtree */
|
|
||||||
int nTab; /* Root page of the table in pBtree */
|
|
||||||
u8 searching; /* True between the first AggNext and AggReset */
|
|
||||||
};
|
|
||||||
struct AggElem {
|
|
||||||
char *zKey; /* The key to this AggElem */
|
|
||||||
int nKey; /* Number of bytes in the key, including '\0' at end */
|
|
||||||
Mem aMem[1]; /* The values for this AggElem */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -324,8 +278,6 @@ struct Vdbe {
|
||||||
Mem *aColName; /* Column names to return */
|
Mem *aColName; /* Column names to return */
|
||||||
int nCursor; /* Number of slots in apCsr[] */
|
int nCursor; /* Number of slots in apCsr[] */
|
||||||
Cursor **apCsr; /* One element of this array for each open cursor */
|
Cursor **apCsr; /* One element of this array for each open cursor */
|
||||||
Sorter *pSort; /* A linked list of objects to be sorted */
|
|
||||||
Sorter *pSortTail; /* Last element on the pSort list */
|
|
||||||
int nVar; /* Number of entries in aVar[] */
|
int nVar; /* Number of entries in aVar[] */
|
||||||
Mem *aVar; /* Values for the OP_Variable opcode. */
|
Mem *aVar; /* Values for the OP_Variable opcode. */
|
||||||
char **azVar; /* Name of variables */
|
char **azVar; /* Name of variables */
|
||||||
|
@ -333,9 +285,6 @@ struct Vdbe {
|
||||||
int magic; /* Magic number for sanity checking */
|
int magic; /* Magic number for sanity checking */
|
||||||
int nMem; /* Number of memory locations currently allocated */
|
int nMem; /* Number of memory locations currently allocated */
|
||||||
Mem *aMem; /* The memory locations */
|
Mem *aMem; /* The memory locations */
|
||||||
int nAgg; /* Number of elements in apAgg */
|
|
||||||
Agg *apAgg; /* Array of aggregate contexts */
|
|
||||||
Agg *pAgg; /* Current aggregate context */
|
|
||||||
int nCallback; /* Number of callbacks invoked so far */
|
int nCallback; /* Number of callbacks invoked so far */
|
||||||
Fifo sFifo; /* A list of ROWIDs */
|
Fifo sFifo; /* A list of ROWIDs */
|
||||||
int contextStackTop; /* Index of top element in the context stack */
|
int contextStackTop; /* Index of top element in the context stack */
|
||||||
|
@ -358,6 +307,7 @@ struct Vdbe {
|
||||||
u8 aborted; /* True if ROLLBACK in another VM causes an abort */
|
u8 aborted; /* True if ROLLBACK in another VM causes an abort */
|
||||||
u8 expired; /* True if the VM needs to be recompiled */
|
u8 expired; /* True if the VM needs to be recompiled */
|
||||||
int nChange; /* Number of db changes made since last reset */
|
int nChange; /* Number of db changes made since last reset */
|
||||||
|
i64 startTime; /* Time when query started - used for profiling */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -372,8 +322,6 @@ struct Vdbe {
|
||||||
** Function prototypes
|
** Function prototypes
|
||||||
*/
|
*/
|
||||||
void sqlite3VdbeFreeCursor(Cursor*);
|
void sqlite3VdbeFreeCursor(Cursor*);
|
||||||
void sqlite3VdbeSorterReset(Vdbe*);
|
|
||||||
int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *);
|
|
||||||
void sqliteVdbePopStack(Vdbe*,int);
|
void sqliteVdbePopStack(Vdbe*,int);
|
||||||
int sqlite3VdbeCursorMoveto(Cursor*);
|
int sqlite3VdbeCursorMoveto(Cursor*);
|
||||||
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE)
|
||||||
|
@ -415,6 +363,7 @@ double sqlite3VdbeRealValue(Mem*);
|
||||||
int sqlite3VdbeMemRealify(Mem*);
|
int sqlite3VdbeMemRealify(Mem*);
|
||||||
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
|
int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
|
||||||
void sqlite3VdbeMemRelease(Mem *p);
|
void sqlite3VdbeMemRelease(Mem *p);
|
||||||
|
void sqlite3VdbeMemFinalize(Mem*, FuncDef*);
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
void sqlite3VdbeMemSanity(Mem*, u8);
|
void sqlite3VdbeMemSanity(Mem*, u8);
|
||||||
int sqlite3VdbeOpcodeNoPush(u8);
|
int sqlite3VdbeOpcodeNoPush(u8);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "vdbeInt.h"
|
#include "vdbeInt.h"
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return TRUE (non-zero) of the statement supplied as an argument needs
|
** Return TRUE (non-zero) of the statement supplied as an argument needs
|
||||||
|
@ -173,9 +174,10 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
||||||
return SQLITE_MISUSE;
|
return SQLITE_MISUSE;
|
||||||
}
|
}
|
||||||
if( p->pc<0 ){
|
if( p->pc<0 ){
|
||||||
|
#ifndef SQLITE_OMIT_TRACE
|
||||||
/* Invoke the trace callback if there is one
|
/* Invoke the trace callback if there is one
|
||||||
*/
|
*/
|
||||||
if( (db = p->db)->xTrace && !db->init.busy ){
|
if( db->xTrace && !db->init.busy ){
|
||||||
assert( p->nOp>0 );
|
assert( p->nOp>0 );
|
||||||
assert( p->aOp[p->nOp-1].opcode==OP_Noop );
|
assert( p->aOp[p->nOp-1].opcode==OP_Noop );
|
||||||
assert( p->aOp[p->nOp-1].p3!=0 );
|
assert( p->aOp[p->nOp-1].p3!=0 );
|
||||||
|
@ -187,6 +189,12 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
||||||
return SQLITE_MISUSE;
|
return SQLITE_MISUSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if( db->xProfile && !db->init.busy ){
|
||||||
|
double rNow;
|
||||||
|
sqlite3OsCurrentTime(&rNow);
|
||||||
|
p->startTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned
|
/* Print a copy of SQL as it is executed if the SQL_TRACE pragma is turned
|
||||||
** on in debugging mode.
|
** on in debugging mode.
|
||||||
|
@ -213,6 +221,23 @@ int sqlite3_step(sqlite3_stmt *pStmt){
|
||||||
rc = SQLITE_MISUSE;
|
rc = SQLITE_MISUSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_TRACE
|
||||||
|
/* Invoke the profile callback if there is one
|
||||||
|
*/
|
||||||
|
if( rc!=SQLITE_ROW && db->xProfile && !db->init.busy ){
|
||||||
|
double rNow;
|
||||||
|
u64 elapseTime;
|
||||||
|
|
||||||
|
sqlite3OsCurrentTime(&rNow);
|
||||||
|
elapseTime = (rNow - (int)rNow)*3600.0*24.0*1000000000.0 - p->startTime;
|
||||||
|
assert( p->nOp>0 );
|
||||||
|
assert( p->aOp[p->nOp-1].opcode==OP_Noop );
|
||||||
|
assert( p->aOp[p->nOp-1].p3!=0 );
|
||||||
|
assert( p->aOp[p->nOp-1].p3type==P3_DYNAMIC );
|
||||||
|
db->xProfile(db->pProfileArg, p->aOp[p->nOp-1].p3, elapseTime);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
sqlite3Error(p->db, rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
|
sqlite3Error(p->db, rc, p->zErrMsg ? "%s" : 0, p->zErrMsg);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -232,16 +257,25 @@ void *sqlite3_user_data(sqlite3_context *p){
|
||||||
** same context that was returned on prior calls.
|
** same context that was returned on prior calls.
|
||||||
*/
|
*/
|
||||||
void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
|
void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){
|
||||||
|
Mem *pMem = p->pMem;
|
||||||
assert( p && p->pFunc && p->pFunc->xStep );
|
assert( p && p->pFunc && p->pFunc->xStep );
|
||||||
if( p->pAgg==0 ){
|
if( (pMem->flags & MEM_Agg)==0 ){
|
||||||
if( nByte<=NBFS ){
|
if( nByte==0 ){
|
||||||
p->pAgg = (void*)p->s.z;
|
assert( pMem->flags==MEM_Null );
|
||||||
memset(p->pAgg, 0, nByte);
|
pMem->z = 0;
|
||||||
}else{
|
}else{
|
||||||
p->pAgg = sqliteMalloc( nByte );
|
pMem->flags = MEM_Agg;
|
||||||
|
pMem->xDel = sqlite3FreeX;
|
||||||
|
*(FuncDef**)&pMem->i = p->pFunc;
|
||||||
|
if( nByte<=NBFS ){
|
||||||
|
pMem->z = pMem->zShort;
|
||||||
|
memset(pMem->z, 0, nByte);
|
||||||
|
}else{
|
||||||
|
pMem->z = sqliteMalloc( nByte );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return p->pAgg;
|
}
|
||||||
|
return (void*)pMem->z;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -274,8 +308,9 @@ void sqlite3_set_auxdata(
|
||||||
pVdbeFunc = pCtx->pVdbeFunc;
|
pVdbeFunc = pCtx->pVdbeFunc;
|
||||||
if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){
|
if( !pVdbeFunc || pVdbeFunc->nAux<=iArg ){
|
||||||
int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg;
|
int nMalloc = sizeof(VdbeFunc) + sizeof(struct AuxData)*iArg;
|
||||||
pCtx->pVdbeFunc = pVdbeFunc = sqliteRealloc(pVdbeFunc, nMalloc);
|
pVdbeFunc = sqliteRealloc(pVdbeFunc, nMalloc);
|
||||||
if( !pVdbeFunc ) return;
|
if( !pVdbeFunc ) return;
|
||||||
|
pCtx->pVdbeFunc = pVdbeFunc;
|
||||||
memset(&pVdbeFunc->apAux[pVdbeFunc->nAux], 0,
|
memset(&pVdbeFunc->apAux[pVdbeFunc->nAux], 0,
|
||||||
sizeof(struct AuxData)*(iArg+1-pVdbeFunc->nAux));
|
sizeof(struct AuxData)*(iArg+1-pVdbeFunc->nAux));
|
||||||
pVdbeFunc->nAux = iArg+1;
|
pVdbeFunc->nAux = iArg+1;
|
||||||
|
@ -300,7 +335,7 @@ void sqlite3_set_auxdata(
|
||||||
*/
|
*/
|
||||||
int sqlite3_aggregate_count(sqlite3_context *p){
|
int sqlite3_aggregate_count(sqlite3_context *p){
|
||||||
assert( p && p->pFunc && p->pFunc->xStep );
|
assert( p && p->pFunc && p->pFunc->xStep );
|
||||||
return p->cnt;
|
return p->pMem->n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -62,16 +62,18 @@ void sqlite3VdbeTrace(Vdbe *p, FILE *trace){
|
||||||
** elements.
|
** elements.
|
||||||
*/
|
*/
|
||||||
static void resizeOpArray(Vdbe *p, int N){
|
static void resizeOpArray(Vdbe *p, int N){
|
||||||
if( p->magic==VDBE_MAGIC_RUN ){
|
int runMode = p->magic==VDBE_MAGIC_RUN;
|
||||||
assert( N==p->nOp );
|
if( runMode || p->nOpAlloc<N ){
|
||||||
p->nOpAlloc = N;
|
VdbeOp *pNew;
|
||||||
p->aOp = sqliteRealloc(p->aOp, N*sizeof(Op));
|
int nNew = N + 100*(!runMode);
|
||||||
}else if( p->nOpAlloc<N ){
|
|
||||||
int oldSize = p->nOpAlloc;
|
int oldSize = p->nOpAlloc;
|
||||||
p->nOpAlloc = N+100;
|
pNew = sqliteRealloc(p->aOp, nNew*sizeof(Op));
|
||||||
p->aOp = sqliteRealloc(p->aOp, p->nOpAlloc*sizeof(Op));
|
if( pNew ){
|
||||||
if( p->aOp ){
|
p->nOpAlloc = nNew;
|
||||||
memset(&p->aOp[oldSize], 0, (p->nOpAlloc-oldSize)*sizeof(Op));
|
p->aOp = pNew;
|
||||||
|
if( nNew>oldSize ){
|
||||||
|
memset(&p->aOp[oldSize], 0, (nNew-oldSize)*sizeof(Op));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +102,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){
|
||||||
p->nOp++;
|
p->nOp++;
|
||||||
assert( p->magic==VDBE_MAGIC_INIT );
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
resizeOpArray(p, i+1);
|
resizeOpArray(p, i+1);
|
||||||
if( p->aOp==0 ){
|
if( sqlite3_malloc_failed ){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pOp = &p->aOp[i];
|
pOp = &p->aOp[i];
|
||||||
|
@ -145,7 +147,8 @@ int sqlite3VdbeMakeLabel(Vdbe *p){
|
||||||
assert( p->magic==VDBE_MAGIC_INIT );
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( i>=p->nLabelAlloc ){
|
if( i>=p->nLabelAlloc ){
|
||||||
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
|
p->nLabelAlloc = p->nLabelAlloc*2 + 10;
|
||||||
p->aLabel = sqliteRealloc( p->aLabel, p->nLabelAlloc*sizeof(p->aLabel[0]));
|
sqlite3ReallocOrFree((void**)&p->aLabel,
|
||||||
|
p->nLabelAlloc*sizeof(p->aLabel[0]));
|
||||||
}
|
}
|
||||||
if( p->aLabel ){
|
if( p->aLabel ){
|
||||||
p->aLabel[i] = -1;
|
p->aLabel[i] = -1;
|
||||||
|
@ -215,8 +218,8 @@ int sqlite3VdbeOpcodeNoPush(u8 op){
|
||||||
**
|
**
|
||||||
** This routine is called once after all opcodes have been inserted.
|
** This routine is called once after all opcodes have been inserted.
|
||||||
**
|
**
|
||||||
** Variable *pMaxFuncArgs is set to the maximum value of any P1 argument
|
** Variable *pMaxFuncArgs is set to the maximum value of any P2 argument
|
||||||
** to an OP_Function or P2 to an OP_AggFunc opcode. This is used by
|
** to an OP_Function or OP_AggStep opcode. This is used by
|
||||||
** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
|
** sqlite3VdbeMakeReady() to size the Vdbe.apArg[] array.
|
||||||
**
|
**
|
||||||
** The integer *pMaxStack is set to the maximum number of vdbe stack
|
** The integer *pMaxStack is set to the maximum number of vdbe stack
|
||||||
|
@ -239,12 +242,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs, int *pMaxStack){
|
||||||
for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
|
for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){
|
||||||
u8 opcode = pOp->opcode;
|
u8 opcode = pOp->opcode;
|
||||||
|
|
||||||
/* Todo: Maybe OP_AggFunc should change to use P1 in the same
|
if( opcode==OP_Function || opcode==OP_AggStep ){
|
||||||
* way as OP_Function.
|
|
||||||
*/
|
|
||||||
if( opcode==OP_Function ){
|
|
||||||
if( pOp->p1>nMaxArgs ) nMaxArgs = pOp->p1;
|
|
||||||
}else if( opcode==OP_AggFunc ){
|
|
||||||
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
|
if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2;
|
||||||
}else if( opcode==OP_Halt ){
|
}else if( opcode==OP_Halt ){
|
||||||
if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){
|
if( pOp->p1==SQLITE_CONSTRAINT && pOp->p2==OE_Abort ){
|
||||||
|
@ -302,7 +300,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){
|
||||||
int addr;
|
int addr;
|
||||||
assert( p->magic==VDBE_MAGIC_INIT );
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
resizeOpArray(p, p->nOp + nOp);
|
resizeOpArray(p, p->nOp + nOp);
|
||||||
if( p->aOp==0 ){
|
if( sqlite3_malloc_failed ){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
addr = p->nOp;
|
addr = p->nOp;
|
||||||
|
@ -353,6 +351,41 @@ void sqlite3VdbeChangeP2(Vdbe *p, int addr, int val){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Change teh P2 operand of instruction addr so that it points to
|
||||||
|
** the address of the next instruction to be coded.
|
||||||
|
*/
|
||||||
|
void sqlite3VdbeJumpHere(Vdbe *p, int addr){
|
||||||
|
sqlite3VdbeChangeP2(p, addr, p->nOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Delete a P3 value if necessary.
|
||||||
|
*/
|
||||||
|
static void freeP3(int p3type, void *p3){
|
||||||
|
if( p3 ){
|
||||||
|
switch( p3type ){
|
||||||
|
case P3_DYNAMIC:
|
||||||
|
case P3_KEYINFO:
|
||||||
|
case P3_KEYINFO_HANDOFF: {
|
||||||
|
sqliteFree(p3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case P3_VDBEFUNC: {
|
||||||
|
VdbeFunc *pVdbeFunc = (VdbeFunc *)p3;
|
||||||
|
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
|
||||||
|
sqliteFree(pVdbeFunc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case P3_MEM: {
|
||||||
|
sqlite3ValueFree((sqlite3_value*)p3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Change the value of the P3 operand for a specific instruction.
|
** Change the value of the P3 operand for a specific instruction.
|
||||||
** This routine is useful when a large program is loaded from a
|
** This routine is useful when a large program is loaded from a
|
||||||
|
@ -382,12 +415,7 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
||||||
Op *pOp;
|
Op *pOp;
|
||||||
assert( p->magic==VDBE_MAGIC_INIT );
|
assert( p->magic==VDBE_MAGIC_INIT );
|
||||||
if( p==0 || p->aOp==0 ){
|
if( p==0 || p->aOp==0 ){
|
||||||
if( n==P3_DYNAMIC || n==P3_KEYINFO_HANDOFF ){
|
freeP3(n, (void*)*(char**)&zP3);
|
||||||
sqliteFree((void*)zP3);
|
|
||||||
}
|
|
||||||
if( n==P3_MEM ){
|
|
||||||
sqlite3ValueFree((sqlite3_value *)zP3);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if( addr<0 || addr>=p->nOp ){
|
if( addr<0 || addr>=p->nOp ){
|
||||||
|
@ -395,16 +423,19 @@ void sqlite3VdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
|
||||||
if( addr<0 ) return;
|
if( addr<0 ) return;
|
||||||
}
|
}
|
||||||
pOp = &p->aOp[addr];
|
pOp = &p->aOp[addr];
|
||||||
if( pOp->p3 && pOp->p3type==P3_DYNAMIC ){
|
freeP3(pOp->p3type, pOp->p3);
|
||||||
sqliteFree(pOp->p3);
|
|
||||||
pOp->p3 = 0;
|
pOp->p3 = 0;
|
||||||
}
|
|
||||||
if( zP3==0 ){
|
if( zP3==0 ){
|
||||||
pOp->p3 = 0;
|
pOp->p3 = 0;
|
||||||
pOp->p3type = P3_NOTUSED;
|
pOp->p3type = P3_NOTUSED;
|
||||||
}else if( n==P3_KEYINFO ){
|
}else if( n==P3_KEYINFO ){
|
||||||
KeyInfo *pKeyInfo;
|
KeyInfo *pKeyInfo;
|
||||||
int nField, nByte;
|
int nField, nByte;
|
||||||
|
|
||||||
|
/* KeyInfo structures that include an KeyInfo.aSortOrder are always
|
||||||
|
** sent in using P3_KEYINFO_HANDOFF. The KeyInfo.aSortOrder array
|
||||||
|
** is not duplicated when P3_KEYINFO is used. */
|
||||||
|
/* assert( pKeyInfo->aSortOrder==0 ); */
|
||||||
nField = ((KeyInfo*)zP3)->nField;
|
nField = ((KeyInfo*)zP3)->nField;
|
||||||
nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]);
|
nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]);
|
||||||
pKeyInfo = sqliteMallocRaw( nByte );
|
pKeyInfo = sqliteMallocRaw( nByte );
|
||||||
|
@ -577,8 +608,9 @@ int sqlite3VdbeList(
|
||||||
}
|
}
|
||||||
p->resOnStack = 0;
|
p->resOnStack = 0;
|
||||||
|
|
||||||
|
do{
|
||||||
i = p->pc++;
|
i = p->pc++;
|
||||||
|
}while( i<p->nOp && p->explain==2 && p->aOp[i].opcode!=OP_Explain );
|
||||||
if( i>=p->nOp ){
|
if( i>=p->nOp ){
|
||||||
p->rc = SQLITE_OK;
|
p->rc = SQLITE_OK;
|
||||||
rc = SQLITE_DONE;
|
rc = SQLITE_DONE;
|
||||||
|
@ -617,7 +649,7 @@ int sqlite3VdbeList(
|
||||||
pMem->type = SQLITE_TEXT;
|
pMem->type = SQLITE_TEXT;
|
||||||
pMem->enc = SQLITE_UTF8;
|
pMem->enc = SQLITE_UTF8;
|
||||||
|
|
||||||
p->nResColumn = 5;
|
p->nResColumn = 5 - 2*(p->explain-1);
|
||||||
p->pTos = pMem;
|
p->pTos = pMem;
|
||||||
p->rc = SQLITE_OK;
|
p->rc = SQLITE_OK;
|
||||||
p->resOnStack = 1;
|
p->resOnStack = 1;
|
||||||
|
@ -658,7 +690,6 @@ void sqlite3VdbeMakeReady(
|
||||||
int nVar, /* Number of '?' see in the SQL statement */
|
int nVar, /* Number of '?' see in the SQL statement */
|
||||||
int nMem, /* Number of memory cells to allocate */
|
int nMem, /* Number of memory cells to allocate */
|
||||||
int nCursor, /* Number of cursors to allocate */
|
int nCursor, /* Number of cursors to allocate */
|
||||||
int nAgg, /* Number of aggregate contexts required */
|
|
||||||
int isExplain /* True if the EXPLAIN keywords is present */
|
int isExplain /* True if the EXPLAIN keywords is present */
|
||||||
){
|
){
|
||||||
int n;
|
int n;
|
||||||
|
@ -701,7 +732,6 @@ void sqlite3VdbeMakeReady(
|
||||||
+ nVar*sizeof(char*) /* azVar */
|
+ nVar*sizeof(char*) /* azVar */
|
||||||
+ nMem*sizeof(Mem) /* aMem */
|
+ nMem*sizeof(Mem) /* aMem */
|
||||||
+ nCursor*sizeof(Cursor*) /* apCsr */
|
+ nCursor*sizeof(Cursor*) /* apCsr */
|
||||||
+ nAgg*sizeof(Agg) /* Aggregate contexts */
|
|
||||||
);
|
);
|
||||||
if( !sqlite3_malloc_failed ){
|
if( !sqlite3_malloc_failed ){
|
||||||
p->aMem = &p->aStack[nStack];
|
p->aMem = &p->aStack[nStack];
|
||||||
|
@ -712,17 +742,12 @@ void sqlite3VdbeMakeReady(
|
||||||
p->apArg = (Mem**)&p->aVar[nVar];
|
p->apArg = (Mem**)&p->aVar[nVar];
|
||||||
p->azVar = (char**)&p->apArg[nArg];
|
p->azVar = (char**)&p->apArg[nArg];
|
||||||
p->apCsr = (Cursor**)&p->azVar[nVar];
|
p->apCsr = (Cursor**)&p->azVar[nVar];
|
||||||
if( nAgg>0 ){
|
|
||||||
p->nAgg = nAgg;
|
|
||||||
p->apAgg = (Agg*)&p->apCsr[nCursor];
|
|
||||||
}
|
|
||||||
p->nCursor = nCursor;
|
p->nCursor = nCursor;
|
||||||
for(n=0; n<nVar; n++){
|
for(n=0; n<nVar; n++){
|
||||||
p->aVar[n].flags = MEM_Null;
|
p->aVar[n].flags = MEM_Null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p->pAgg = p->apAgg;
|
|
||||||
for(n=0; n<p->nMem; n++){
|
for(n=0; n<p->nMem; n++){
|
||||||
p->aMem[n].flags = MEM_Null;
|
p->aMem[n].flags = MEM_Null;
|
||||||
}
|
}
|
||||||
|
@ -763,155 +788,6 @@ void sqlite3VdbeMakeReady(
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Remove any elements that remain on the sorter for the VDBE given.
|
|
||||||
*/
|
|
||||||
void sqlite3VdbeSorterReset(Vdbe *p){
|
|
||||||
while( p->pSort ){
|
|
||||||
Sorter *pSorter = p->pSort;
|
|
||||||
p->pSort = pSorter->pNext;
|
|
||||||
sqliteFree(pSorter->zKey);
|
|
||||||
sqlite3VdbeMemRelease(&pSorter->data);
|
|
||||||
sqliteFree(pSorter);
|
|
||||||
}
|
|
||||||
p->pSortTail = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Free all resources allociated with AggElem pElem, an element of
|
|
||||||
** aggregate pAgg.
|
|
||||||
*/
|
|
||||||
static void freeAggElem(AggElem *pElem, Agg *pAgg){
|
|
||||||
int i;
|
|
||||||
for(i=0; i<pAgg->nMem; i++){
|
|
||||||
Mem *pMem = &pElem->aMem[i];
|
|
||||||
if( pAgg->apFunc && pAgg->apFunc[i] && (pMem->flags & MEM_AggCtx)!=0 ){
|
|
||||||
sqlite3_context ctx;
|
|
||||||
ctx.pFunc = pAgg->apFunc[i];
|
|
||||||
ctx.s.flags = MEM_Null;
|
|
||||||
ctx.pAgg = pMem->z;
|
|
||||||
ctx.cnt = pMem->i;
|
|
||||||
ctx.isError = 0;
|
|
||||||
(*ctx.pFunc->xFinalize)(&ctx);
|
|
||||||
pMem->z = ctx.pAgg;
|
|
||||||
if( pMem->z!=0 && pMem->z!=pMem->zShort ){
|
|
||||||
sqliteFree(pMem->z);
|
|
||||||
}
|
|
||||||
sqlite3VdbeMemRelease(&ctx.s);
|
|
||||||
}else{
|
|
||||||
sqlite3VdbeMemRelease(pMem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sqliteFree(pElem);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Reset an Agg structure. Delete all its contents.
|
|
||||||
**
|
|
||||||
** For installable aggregate functions, if the step function has been
|
|
||||||
** called, make sure the finalizer function has also been called. The
|
|
||||||
** finalizer might need to free memory that was allocated as part of its
|
|
||||||
** private context. If the finalizer has not been called yet, call it
|
|
||||||
** now.
|
|
||||||
**
|
|
||||||
** If db is NULL, then this is being called from sqliteVdbeReset(). In
|
|
||||||
** this case clean up all references to the temp-table used for
|
|
||||||
** aggregates (if it was ever opened).
|
|
||||||
**
|
|
||||||
** If db is not NULL, then this is being called from with an OP_AggReset
|
|
||||||
** opcode. Open the temp-table, if it has not already been opened and
|
|
||||||
** delete the contents of the table used for aggregate information, ready
|
|
||||||
** for the next round of aggregate processing.
|
|
||||||
*/
|
|
||||||
int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){
|
|
||||||
int rc = 0;
|
|
||||||
BtCursor *pCsr;
|
|
||||||
|
|
||||||
if( !pAgg ) return SQLITE_OK;
|
|
||||||
pCsr = pAgg->pCsr;
|
|
||||||
assert( (pCsr && pAgg->nTab>0) || (!pCsr && pAgg->nTab==0)
|
|
||||||
|| sqlite3_malloc_failed );
|
|
||||||
|
|
||||||
/* If pCsr is not NULL, then the table used for aggregate information
|
|
||||||
** is open. Loop through it and free the AggElem* structure pointed at
|
|
||||||
** by each entry. If the finalizer has not been called for an AggElem,
|
|
||||||
** do that too. Finally, clear the btree table itself.
|
|
||||||
*/
|
|
||||||
if( pCsr ){
|
|
||||||
int res;
|
|
||||||
assert( pAgg->pBtree );
|
|
||||||
assert( pAgg->nTab>0 );
|
|
||||||
|
|
||||||
rc=sqlite3BtreeFirst(pCsr, &res);
|
|
||||||
while( res==0 && rc==SQLITE_OK ){
|
|
||||||
AggElem *pElem;
|
|
||||||
rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem);
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
assert( pAgg->apFunc!=0 );
|
|
||||||
freeAggElem(pElem, pAgg);
|
|
||||||
rc=sqlite3BtreeNext(pCsr, &res);
|
|
||||||
}
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlite3BtreeCloseCursor(pCsr);
|
|
||||||
sqlite3BtreeClearTable(pAgg->pBtree, pAgg->nTab);
|
|
||||||
}else{
|
|
||||||
/* The cursor may not be open because the aggregator was never used,
|
|
||||||
** or it could be that it was used but there was no GROUP BY clause.
|
|
||||||
*/
|
|
||||||
if( pAgg->pCurrent ){
|
|
||||||
freeAggElem(pAgg->pCurrent, pAgg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If db is not NULL and we have not yet and we have not yet opened
|
|
||||||
** the temporary btree then do so and create the table to store aggregate
|
|
||||||
** information.
|
|
||||||
**
|
|
||||||
** If db is NULL, then close the temporary btree if it is open.
|
|
||||||
*/
|
|
||||||
if( db ){
|
|
||||||
if( !pAgg->pBtree ){
|
|
||||||
assert( pAgg->nTab==0 );
|
|
||||||
#ifndef SQLITE_OMIT_MEMORYDB
|
|
||||||
rc = sqlite3BtreeFactory(db, ":memory:", 0, TEMP_PAGES, &pAgg->pBtree);
|
|
||||||
#else
|
|
||||||
rc = sqlite3BtreeFactory(db, 0, 0, TEMP_PAGES, &pAgg->pBtree);
|
|
||||||
#endif
|
|
||||||
if( rc!=SQLITE_OK ) return rc;
|
|
||||||
sqlite3BtreeBeginTrans(pAgg->pBtree, 1);
|
|
||||||
rc = sqlite3BtreeCreateTable(pAgg->pBtree, &pAgg->nTab, 0);
|
|
||||||
if( rc!=SQLITE_OK ) return rc;
|
|
||||||
}
|
|
||||||
assert( pAgg->nTab!=0 );
|
|
||||||
|
|
||||||
rc = sqlite3BtreeCursor(pAgg->pBtree, pAgg->nTab, 1,
|
|
||||||
sqlite3VdbeRecordCompare, pKeyInfo, &pAgg->pCsr);
|
|
||||||
if( rc!=SQLITE_OK ) return rc;
|
|
||||||
}else{
|
|
||||||
if( pAgg->pBtree ){
|
|
||||||
sqlite3BtreeClose(pAgg->pBtree);
|
|
||||||
pAgg->pBtree = 0;
|
|
||||||
pAgg->nTab = 0;
|
|
||||||
}
|
|
||||||
pAgg->pCsr = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( pAgg->apFunc ){
|
|
||||||
sqliteFree(pAgg->apFunc);
|
|
||||||
pAgg->apFunc = 0;
|
|
||||||
}
|
|
||||||
pAgg->pCurrent = 0;
|
|
||||||
pAgg->nMem = 0;
|
|
||||||
pAgg->searching = 0;
|
|
||||||
return SQLITE_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Close a cursor and release all the resources that cursor happens
|
** Close a cursor and release all the resources that cursor happens
|
||||||
** to hold.
|
** to hold.
|
||||||
|
@ -965,10 +841,6 @@ static void Cleanup(Vdbe *p){
|
||||||
}
|
}
|
||||||
sqliteFree(p->contextStack);
|
sqliteFree(p->contextStack);
|
||||||
}
|
}
|
||||||
sqlite3VdbeSorterReset(p);
|
|
||||||
for(i=0; i<p->nAgg; i++){
|
|
||||||
sqlite3VdbeAggReset(0, &p->apAgg[i], 0);
|
|
||||||
}
|
|
||||||
p->contextStack = 0;
|
p->contextStack = 0;
|
||||||
p->contextStackDepth = 0;
|
p->contextStackDepth = 0;
|
||||||
p->contextStackTop = 0;
|
p->contextStackTop = 0;
|
||||||
|
@ -1145,7 +1017,8 @@ static int vdbeCommit(sqlite3 *db){
|
||||||
*/
|
*/
|
||||||
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
|
zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);
|
||||||
rc = sqlite3OsOpenDirectory(zMainFile, &master);
|
rc = sqlite3OsOpenDirectory(zMainFile, &master);
|
||||||
if( rc!=SQLITE_OK || (needSync && (rc=sqlite3OsSync(&master))!=SQLITE_OK) ){
|
if( rc!=SQLITE_OK ||
|
||||||
|
(needSync && (rc=sqlite3OsSync(&master,0))!=SQLITE_OK) ){
|
||||||
sqlite3OsClose(&master);
|
sqlite3OsClose(&master);
|
||||||
sqlite3OsDelete(zMaster);
|
sqlite3OsDelete(zMaster);
|
||||||
sqliteFree(zMaster);
|
sqliteFree(zMaster);
|
||||||
|
@ -1489,17 +1362,7 @@ void sqlite3VdbeDelete(Vdbe *p){
|
||||||
if( p->aOp ){
|
if( p->aOp ){
|
||||||
for(i=0; i<p->nOp; i++){
|
for(i=0; i<p->nOp; i++){
|
||||||
Op *pOp = &p->aOp[i];
|
Op *pOp = &p->aOp[i];
|
||||||
if( pOp->p3type==P3_DYNAMIC || pOp->p3type==P3_KEYINFO ){
|
freeP3(pOp->p3type, pOp->p3);
|
||||||
sqliteFree(pOp->p3);
|
|
||||||
}
|
|
||||||
if( pOp->p3type==P3_VDBEFUNC ){
|
|
||||||
VdbeFunc *pVdbeFunc = (VdbeFunc *)pOp->p3;
|
|
||||||
sqlite3VdbeDeleteAuxData(pVdbeFunc, 0);
|
|
||||||
sqliteFree(pVdbeFunc);
|
|
||||||
}
|
|
||||||
if( pOp->p3type==P3_MEM ){
|
|
||||||
sqlite3ValueFree((sqlite3_value*)pOp->p3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
sqliteFree(p->aOp);
|
sqliteFree(p->aOp);
|
||||||
}
|
}
|
||||||
|
@ -1714,8 +1577,18 @@ int sqlite3VdbeSerialGet(
|
||||||
}
|
}
|
||||||
case 6: /* 8-byte signed integer */
|
case 6: /* 8-byte signed integer */
|
||||||
case 7: { /* IEEE floating point */
|
case 7: { /* IEEE floating point */
|
||||||
u64 x = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
u64 x;
|
||||||
u32 y = (buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7];
|
u32 y;
|
||||||
|
#ifndef NDEBUG
|
||||||
|
/* Verify that integers and floating point values use the same
|
||||||
|
** byte order. The byte order differs on some (broken) architectures.
|
||||||
|
*/
|
||||||
|
static const u64 t1 = ((u64)0x3ff00000)<<32;
|
||||||
|
assert( 1.0==*(double*)&t1 );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
x = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
|
||||||
|
y = (buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7];
|
||||||
x = (x<<32) | y;
|
x = (x<<32) | y;
|
||||||
if( serial_type==6 ){
|
if( serial_type==6 ){
|
||||||
pMem->i = *(i64*)&x;
|
pMem->i = *(i64*)&x;
|
||||||
|
@ -1853,7 +1726,7 @@ int sqlite3VdbeIdxRowid(BtCursor *pCur, i64 *rowid){
|
||||||
|
|
||||||
sqlite3BtreeKeySize(pCur, &nCellKey);
|
sqlite3BtreeKeySize(pCur, &nCellKey);
|
||||||
if( nCellKey<=0 ){
|
if( nCellKey<=0 ){
|
||||||
return SQLITE_CORRUPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
rc = sqlite3VdbeMemFromBtree(pCur, 0, nCellKey, 1, &m);
|
rc = sqlite3VdbeMemFromBtree(pCur, 0, nCellKey, 1, &m);
|
||||||
if( rc ){
|
if( rc ){
|
||||||
|
|
|
@ -187,15 +187,45 @@ int sqlite3VdbeMemStringify(Mem *pMem, int enc){
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Memory cell pMem contains the context of an aggregate function.
|
||||||
|
** This routine calls the finalize method for that function. The
|
||||||
|
** result of the aggregate is stored back into pMem.
|
||||||
|
*/
|
||||||
|
void sqlite3VdbeMemFinalize(Mem *pMem, FuncDef *pFunc){
|
||||||
|
if( pFunc && pFunc->xFinalize ){
|
||||||
|
sqlite3_context ctx;
|
||||||
|
assert( (pMem->flags & MEM_Null)!=0 || pFunc==*(FuncDef**)&pMem->i );
|
||||||
|
ctx.s.flags = MEM_Null;
|
||||||
|
ctx.s.z = pMem->zShort;
|
||||||
|
ctx.pMem = pMem;
|
||||||
|
ctx.pFunc = pFunc;
|
||||||
|
pFunc->xFinalize(&ctx);
|
||||||
|
if( pMem->z && pMem->z!=pMem->zShort ){
|
||||||
|
sqliteFree( pMem->z );
|
||||||
|
}
|
||||||
|
*pMem = ctx.s;
|
||||||
|
if( pMem->flags & MEM_Short ){
|
||||||
|
pMem->z = pMem->zShort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Release any memory held by the Mem. This may leave the Mem in an
|
** Release any memory held by the Mem. This may leave the Mem in an
|
||||||
** inconsistent state, for example with (Mem.z==0) and
|
** inconsistent state, for example with (Mem.z==0) and
|
||||||
** (Mem.type==SQLITE_TEXT).
|
** (Mem.type==SQLITE_TEXT).
|
||||||
*/
|
*/
|
||||||
void sqlite3VdbeMemRelease(Mem *p){
|
void sqlite3VdbeMemRelease(Mem *p){
|
||||||
if( p->flags & MEM_Dyn ){
|
if( p->flags & (MEM_Dyn|MEM_Agg) ){
|
||||||
if( p->xDel ){
|
if( p->xDel ){
|
||||||
|
if( p->flags & MEM_Agg ){
|
||||||
|
sqlite3VdbeMemFinalize(p, *(FuncDef**)&p->i);
|
||||||
|
assert( (p->flags & MEM_Agg)==0 );
|
||||||
|
sqlite3VdbeMemRelease(p);
|
||||||
|
}else{
|
||||||
p->xDel((void *)p->z);
|
p->xDel((void *)p->z);
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
sqliteFree(p->z);
|
sqliteFree(p->z);
|
||||||
}
|
}
|
||||||
|
@ -287,6 +317,7 @@ void sqlite3VdbeMemSetNull(Mem *pMem){
|
||||||
sqlite3VdbeMemRelease(pMem);
|
sqlite3VdbeMemRelease(pMem);
|
||||||
pMem->flags = MEM_Null;
|
pMem->flags = MEM_Null;
|
||||||
pMem->type = SQLITE_NULL;
|
pMem->type = SQLITE_NULL;
|
||||||
|
pMem->n = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -699,7 +730,7 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){
|
||||||
/*
|
/*
|
||||||
** Create a new sqlite3_value object.
|
** Create a new sqlite3_value object.
|
||||||
*/
|
*/
|
||||||
sqlite3_value* sqlite3ValueNew(){
|
sqlite3_value* sqlite3ValueNew(void){
|
||||||
Mem *p = sqliteMalloc(sizeof(*p));
|
Mem *p = sqliteMalloc(sizeof(*p));
|
||||||
if( p ){
|
if( p ){
|
||||||
p->flags = MEM_Null;
|
p->flags = MEM_Null;
|
||||||
|
|
|
@ -232,7 +232,7 @@ static int whereClauseInsert(WhereClause *pWC, Expr *p, int flags){
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This routine identifies subexpressions in the WHERE clause where
|
** This routine identifies subexpressions in the WHERE clause where
|
||||||
** each subexpression is separate by the AND operator or some other
|
** each subexpression is separated by the AND operator or some other
|
||||||
** operator specified in the op parameter. The WhereClause structure
|
** operator specified in the op parameter. The WhereClause structure
|
||||||
** is filled with pointers to subexpressions. For example:
|
** is filled with pointers to subexpressions. For example:
|
||||||
**
|
**
|
||||||
|
@ -281,7 +281,7 @@ static Bitmask getMask(ExprMaskSet *pMaskSet, int iCursor){
|
||||||
**
|
**
|
||||||
** There is one cursor per table in the FROM clause. The number of
|
** There is one cursor per table in the FROM clause. The number of
|
||||||
** tables in the FROM clause is limited by a test early in the
|
** tables in the FROM clause is limited by a test early in the
|
||||||
** sqlite3WhereBegin() routien. So we know that the pMaskSet->ix[]
|
** sqlite3WhereBegin() routine. So we know that the pMaskSet->ix[]
|
||||||
** array will never overflow.
|
** array will never overflow.
|
||||||
*/
|
*/
|
||||||
static void createMask(ExprMaskSet *pMaskSet, int iCursor){
|
static void createMask(ExprMaskSet *pMaskSet, int iCursor){
|
||||||
|
@ -304,6 +304,7 @@ static void createMask(ExprMaskSet *pMaskSet, int iCursor){
|
||||||
** the bitmasks together.
|
** the bitmasks together.
|
||||||
*/
|
*/
|
||||||
static Bitmask exprListTableUsage(ExprMaskSet*, ExprList*);
|
static Bitmask exprListTableUsage(ExprMaskSet*, ExprList*);
|
||||||
|
static Bitmask exprSelectTableUsage(ExprMaskSet*, Select*);
|
||||||
static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
|
static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
|
||||||
Bitmask mask = 0;
|
Bitmask mask = 0;
|
||||||
if( p==0 ) return 0;
|
if( p==0 ) return 0;
|
||||||
|
@ -314,14 +315,7 @@ static Bitmask exprTableUsage(ExprMaskSet *pMaskSet, Expr *p){
|
||||||
mask = exprTableUsage(pMaskSet, p->pRight);
|
mask = exprTableUsage(pMaskSet, p->pRight);
|
||||||
mask |= exprTableUsage(pMaskSet, p->pLeft);
|
mask |= exprTableUsage(pMaskSet, p->pLeft);
|
||||||
mask |= exprListTableUsage(pMaskSet, p->pList);
|
mask |= exprListTableUsage(pMaskSet, p->pList);
|
||||||
if( p->pSelect ){
|
mask |= exprSelectTableUsage(pMaskSet, p->pSelect);
|
||||||
Select *pS = p->pSelect;
|
|
||||||
mask |= exprListTableUsage(pMaskSet, pS->pEList);
|
|
||||||
mask |= exprListTableUsage(pMaskSet, pS->pGroupBy);
|
|
||||||
mask |= exprListTableUsage(pMaskSet, pS->pOrderBy);
|
|
||||||
mask |= exprTableUsage(pMaskSet, pS->pWhere);
|
|
||||||
mask |= exprTableUsage(pMaskSet, pS->pHaving);
|
|
||||||
}
|
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
static Bitmask exprListTableUsage(ExprMaskSet *pMaskSet, ExprList *pList){
|
static Bitmask exprListTableUsage(ExprMaskSet *pMaskSet, ExprList *pList){
|
||||||
|
@ -334,6 +328,19 @@ static Bitmask exprListTableUsage(ExprMaskSet *pMaskSet, ExprList *pList){
|
||||||
}
|
}
|
||||||
return mask;
|
return mask;
|
||||||
}
|
}
|
||||||
|
static Bitmask exprSelectTableUsage(ExprMaskSet *pMaskSet, Select *pS){
|
||||||
|
Bitmask mask;
|
||||||
|
if( pS==0 ){
|
||||||
|
mask = 0;
|
||||||
|
}else{
|
||||||
|
mask = exprListTableUsage(pMaskSet, pS->pEList);
|
||||||
|
mask |= exprListTableUsage(pMaskSet, pS->pGroupBy);
|
||||||
|
mask |= exprListTableUsage(pMaskSet, pS->pOrderBy);
|
||||||
|
mask |= exprTableUsage(pMaskSet, pS->pWhere);
|
||||||
|
mask |= exprTableUsage(pMaskSet, pS->pHaving);
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return TRUE if the given operator is one of the operators that is
|
** Return TRUE if the given operator is one of the operators that is
|
||||||
|
@ -479,8 +486,11 @@ static int isLikeOrGlob(
|
||||||
Expr *pRight, *pLeft;
|
Expr *pRight, *pLeft;
|
||||||
ExprList *pList;
|
ExprList *pList;
|
||||||
int c, cnt;
|
int c, cnt;
|
||||||
|
int noCase;
|
||||||
char wc[3];
|
char wc[3];
|
||||||
if( !sqlite3IsLikeFunction(db, pExpr, wc) ){
|
CollSeq *pColl;
|
||||||
|
|
||||||
|
if( !sqlite3IsLikeFunction(db, pExpr, &noCase, wc) ){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pList = pExpr->pList;
|
pList = pExpr->pList;
|
||||||
|
@ -492,6 +502,14 @@ static int isLikeOrGlob(
|
||||||
if( pLeft->op!=TK_COLUMN ){
|
if( pLeft->op!=TK_COLUMN ){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
pColl = pLeft->pColl;
|
||||||
|
if( pColl==0 ){
|
||||||
|
pColl = db->pDfltColl;
|
||||||
|
}
|
||||||
|
if( (pColl->type!=SQLITE_COLL_BINARY || noCase) &&
|
||||||
|
(pColl->type!=SQLITE_COLL_NOCASE || !noCase) ){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
sqlite3DequoteExpr(pRight);
|
sqlite3DequoteExpr(pRight);
|
||||||
z = pRight->token.z;
|
z = pRight->token.z;
|
||||||
for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){}
|
for(cnt=0; (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2]; cnt++){}
|
||||||
|
@ -514,7 +532,7 @@ static int isLikeOrGlob(
|
||||||
** to the standard form of "X <op> <expr>". If the expression is of
|
** to the standard form of "X <op> <expr>". If the expression is of
|
||||||
** the form "X <op> Y" where both X and Y are columns, then the original
|
** the form "X <op> Y" where both X and Y are columns, then the original
|
||||||
** expression is unchanged and a new virtual expression of the form
|
** expression is unchanged and a new virtual expression of the form
|
||||||
** "Y <op> X" is added to the WHERE clause.
|
** "Y <op> X" is added to the WHERE clause and analyzed separately.
|
||||||
*/
|
*/
|
||||||
static void exprAnalyze(
|
static void exprAnalyze(
|
||||||
SrcList *pSrc, /* the FROM clause */
|
SrcList *pSrc, /* the FROM clause */
|
||||||
|
@ -526,18 +544,26 @@ static void exprAnalyze(
|
||||||
Expr *pExpr = pTerm->pExpr;
|
Expr *pExpr = pTerm->pExpr;
|
||||||
Bitmask prereqLeft;
|
Bitmask prereqLeft;
|
||||||
Bitmask prereqAll;
|
Bitmask prereqAll;
|
||||||
int idxRight;
|
|
||||||
int nPattern;
|
int nPattern;
|
||||||
int isComplete;
|
int isComplete;
|
||||||
|
|
||||||
if( sqlite3_malloc_failed ) return;
|
if( sqlite3_malloc_failed ) return;
|
||||||
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
|
prereqLeft = exprTableUsage(pMaskSet, pExpr->pLeft);
|
||||||
|
if( pExpr->op==TK_IN ){
|
||||||
|
assert( pExpr->pRight==0 );
|
||||||
|
pTerm->prereqRight = exprListTableUsage(pMaskSet, pExpr->pList)
|
||||||
|
| exprSelectTableUsage(pMaskSet, pExpr->pSelect);
|
||||||
|
}else{
|
||||||
pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
|
pTerm->prereqRight = exprTableUsage(pMaskSet, pExpr->pRight);
|
||||||
pTerm->prereqAll = prereqAll = exprTableUsage(pMaskSet, pExpr);
|
}
|
||||||
|
prereqAll = exprTableUsage(pMaskSet, pExpr);
|
||||||
|
if( ExprHasProperty(pExpr, EP_FromJoin) ){
|
||||||
|
prereqAll |= getMask(pMaskSet, pExpr->iRightJoinTable);
|
||||||
|
}
|
||||||
|
pTerm->prereqAll = prereqAll;
|
||||||
pTerm->leftCursor = -1;
|
pTerm->leftCursor = -1;
|
||||||
pTerm->iParent = -1;
|
pTerm->iParent = -1;
|
||||||
pTerm->operator = 0;
|
pTerm->operator = 0;
|
||||||
idxRight = -1;
|
|
||||||
if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
|
if( allowedOp(pExpr->op) && (pTerm->prereqRight & prereqLeft)==0 ){
|
||||||
Expr *pLeft = pExpr->pLeft;
|
Expr *pLeft = pExpr->pLeft;
|
||||||
Expr *pRight = pExpr->pRight;
|
Expr *pRight = pExpr->pRight;
|
||||||
|
@ -599,7 +625,13 @@ static void exprAnalyze(
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
|
#ifndef SQLITE_OMIT_OR_OPTIMIZATION
|
||||||
/* Attempt to convert OR-connected terms into an IN operator so that
|
/* Attempt to convert OR-connected terms into an IN operator so that
|
||||||
** they can make use of indices.
|
** they can make use of indices. Example:
|
||||||
|
**
|
||||||
|
** x = expr1 OR expr2 = x OR x = expr3
|
||||||
|
**
|
||||||
|
** is converted into
|
||||||
|
**
|
||||||
|
** x IN (expr1,expr2,expr3)
|
||||||
*/
|
*/
|
||||||
else if( pExpr->op==TK_OR ){
|
else if( pExpr->op==TK_OR ){
|
||||||
int ok;
|
int ok;
|
||||||
|
@ -647,7 +679,11 @@ static void exprAnalyze(
|
||||||
pDup->iColumn = iColumn;
|
pDup->iColumn = iColumn;
|
||||||
}
|
}
|
||||||
pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
|
pNew = sqlite3Expr(TK_IN, pDup, 0, 0);
|
||||||
if( pNew ) pNew->pList = pList;
|
if( pNew ){
|
||||||
|
pNew->pList = pList;
|
||||||
|
}else{
|
||||||
|
sqlite3ExprListDelete(pList);
|
||||||
|
}
|
||||||
pTerm->pExpr = pNew;
|
pTerm->pExpr = pNew;
|
||||||
pTerm->flags |= TERM_DYNAMIC;
|
pTerm->flags |= TERM_DYNAMIC;
|
||||||
exprAnalyze(pSrc, pMaskSet, pWC, idxTerm);
|
exprAnalyze(pSrc, pMaskSet, pWC, idxTerm);
|
||||||
|
@ -726,7 +762,7 @@ static int isSortingIndex(
|
||||||
int *pbRev /* Set to 1 if ORDER BY is DESC */
|
int *pbRev /* Set to 1 if ORDER BY is DESC */
|
||||||
){
|
){
|
||||||
int i, j; /* Loop counters */
|
int i, j; /* Loop counters */
|
||||||
int sortOrder; /* Which direction we are sorting */
|
int sortOrder = SQLITE_SO_ASC; /* Which direction we are sorting */
|
||||||
int nTerm; /* Number of ORDER BY terms */
|
int nTerm; /* Number of ORDER BY terms */
|
||||||
struct ExprList_item *pTerm; /* A term of the ORDER BY clause */
|
struct ExprList_item *pTerm; /* A term of the ORDER BY clause */
|
||||||
sqlite3 *db = pParse->db;
|
sqlite3 *db = pParse->db;
|
||||||
|
@ -802,7 +838,8 @@ static int sortableByRowid(
|
||||||
assert( pOrderBy!=0 );
|
assert( pOrderBy!=0 );
|
||||||
assert( pOrderBy->nExpr>0 );
|
assert( pOrderBy->nExpr>0 );
|
||||||
p = pOrderBy->a[0].pExpr;
|
p = pOrderBy->a[0].pExpr;
|
||||||
if( p->op==TK_COLUMN && p->iTable==base && p->iColumn==-1 ){
|
if( pOrderBy->nExpr==1 && p->op==TK_COLUMN && p->iTable==base
|
||||||
|
&& p->iColumn==-1 ){
|
||||||
*pbRev = pOrderBy->a[0].sortOrder;
|
*pbRev = pOrderBy->a[0].sortOrder;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -810,7 +847,7 @@ static int sortableByRowid(
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Prepare a crude estimate of the logorithm of the input value.
|
** Prepare a crude estimate of the logarithm of the input value.
|
||||||
** The results need not be exact. This is only used for estimating
|
** The results need not be exact. This is only used for estimating
|
||||||
** the total cost of performing operatings with O(logN) or O(NlogN)
|
** the total cost of performing operatings with O(logN) or O(NlogN)
|
||||||
** complexity. Because N is just a guess, it is no great tragedy if
|
** complexity. Because N is just a guess, it is no great tragedy if
|
||||||
|
@ -1069,11 +1106,12 @@ static double bestIndex(
|
||||||
** of a LEFT OUTER JOIN. In (1), the term is not disabled.
|
** of a LEFT OUTER JOIN. In (1), the term is not disabled.
|
||||||
**
|
**
|
||||||
** Disabling a term causes that term to not be tested in the inner loop
|
** Disabling a term causes that term to not be tested in the inner loop
|
||||||
** of the join. Disabling is an optimization. We would get the correct
|
** of the join. Disabling is an optimization. When terms are satisfied
|
||||||
** results if nothing were ever disabled, but joins might run a little
|
** by indices, we disable them to prevent redundant tests in the inner
|
||||||
** slower. The trick is to disable as much as we can without disabling
|
** loop. We would get the correct results if nothing were ever disabled,
|
||||||
** too much. If we disabled in (1), we'd get the wrong answer.
|
** but joins might run a little slower. The trick is to disable as much
|
||||||
** See ticket #813.
|
** as we can without disabling too much. If we disabled in (1), we'd get
|
||||||
|
** the wrong answer. See ticket #813.
|
||||||
*/
|
*/
|
||||||
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
static void disableTerm(WhereLevel *pLevel, WhereTerm *pTerm){
|
||||||
if( pTerm
|
if( pTerm
|
||||||
|
@ -1142,8 +1180,9 @@ static void codeEqualityTerm(
|
||||||
sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
|
sqlite3VdbeAddOp(v, OP_Rewind, iTab, brk);
|
||||||
VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
|
VdbeComment((v, "# %.*s", pX->span.n, pX->span.z));
|
||||||
pLevel->nIn++;
|
pLevel->nIn++;
|
||||||
pLevel->aInLoop = aIn = sqliteRealloc(pLevel->aInLoop,
|
sqlite3ReallocOrFree((void**)&pLevel->aInLoop,
|
||||||
sizeof(pLevel->aInLoop[0])*3*pLevel->nIn);
|
sizeof(pLevel->aInLoop[0])*3*pLevel->nIn);
|
||||||
|
aIn = pLevel->aInLoop;
|
||||||
if( aIn ){
|
if( aIn ){
|
||||||
aIn += pLevel->nIn*3 - 3;
|
aIn += pLevel->nIn*3 - 3;
|
||||||
aIn[0] = OP_Next;
|
aIn[0] = OP_Next;
|
||||||
|
@ -1229,7 +1268,7 @@ static void codeAllEqualityTerms(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SQLITE_TEST
|
#if defined(SQLITE_TEST)
|
||||||
/*
|
/*
|
||||||
** The following variable holds a text description of query plan generated
|
** The following variable holds a text description of query plan generated
|
||||||
** by the most recent call to sqlite3WhereBegin(). Each call to WhereBegin
|
** by the most recent call to sqlite3WhereBegin(). Each call to WhereBegin
|
||||||
|
@ -1387,7 +1426,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||||
/* Analyze all of the subexpressions. Note that exprAnalyze() might
|
/* Analyze all of the subexpressions. Note that exprAnalyze() might
|
||||||
** add new virtual terms onto the end of the WHERE clause. We do not
|
** add new virtual terms onto the end of the WHERE clause. We do not
|
||||||
** want to analyze these virtual terms, so start analyzing at the end
|
** want to analyze these virtual terms, so start analyzing at the end
|
||||||
** and work forward so that they added virtual terms are never processed.
|
** and work forward so that the added virtual terms are never processed.
|
||||||
*/
|
*/
|
||||||
for(i=0; i<pTabList->nSrc; i++){
|
for(i=0; i<pTabList->nSrc; i++){
|
||||||
createMask(&maskSet, pTabList->a[i].iCursor);
|
createMask(&maskSet, pTabList->a[i].iCursor);
|
||||||
|
@ -1415,6 +1454,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||||
pTabItem = pTabList->a;
|
pTabItem = pTabList->a;
|
||||||
pLevel = pWInfo->a;
|
pLevel = pWInfo->a;
|
||||||
andFlags = ~0;
|
andFlags = ~0;
|
||||||
|
TRACE(("*** Optimizer Start ***\n"));
|
||||||
for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
|
for(i=iFrom=0, pLevel=pWInfo->a; i<pTabList->nSrc; i++, pLevel++){
|
||||||
Index *pIdx; /* Index for FROM table at pTabItem */
|
Index *pIdx; /* Index for FROM table at pTabItem */
|
||||||
int flags; /* Flags asssociated with pIdx */
|
int flags; /* Flags asssociated with pIdx */
|
||||||
|
@ -1435,7 +1475,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cost = bestIndex(pParse, &wc, pTabItem, notReady,
|
cost = bestIndex(pParse, &wc, pTabItem, notReady,
|
||||||
(j==0 && ppOrderBy) ? *ppOrderBy : 0,
|
(i==0 && ppOrderBy) ? *ppOrderBy : 0,
|
||||||
&pIdx, &flags, &nEq);
|
&pIdx, &flags, &nEq);
|
||||||
if( cost<lowestCost ){
|
if( cost<lowestCost ){
|
||||||
lowestCost = cost;
|
lowestCost = cost;
|
||||||
|
@ -1444,12 +1484,14 @@ WhereInfo *sqlite3WhereBegin(
|
||||||
bestNEq = nEq;
|
bestNEq = nEq;
|
||||||
bestJ = j;
|
bestJ = j;
|
||||||
}
|
}
|
||||||
if( (pTabItem->jointype & JT_LEFT)!=0
|
if( (pTabItem->jointype & (JT_LEFT|JT_CROSS))!=0
|
||||||
|| (j>0 && (pTabItem[-1].jointype & JT_LEFT)!=0)
|
|| (j>0 && (pTabItem[-1].jointype & (JT_LEFT|JT_CROSS))!=0)
|
||||||
){
|
){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TRACE(("*** Optimizer choose table %d for loop %d\n", bestJ,
|
||||||
|
pLevel-pWInfo->a));
|
||||||
if( (bestFlags & WHERE_ORDERBY)!=0 ){
|
if( (bestFlags & WHERE_ORDERBY)!=0 ){
|
||||||
*ppOrderBy = 0;
|
*ppOrderBy = 0;
|
||||||
}
|
}
|
||||||
|
@ -1467,6 +1509,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||||
notReady &= ~getMask(&maskSet, pTabList->a[bestJ].iCursor);
|
notReady &= ~getMask(&maskSet, pTabList->a[bestJ].iCursor);
|
||||||
pLevel->iFrom = bestJ;
|
pLevel->iFrom = bestJ;
|
||||||
}
|
}
|
||||||
|
TRACE(("*** Optimizer Finished ***\n"));
|
||||||
|
|
||||||
/* If the total query only selects a single row, then the ORDER BY
|
/* If the total query only selects a single row, then the ORDER BY
|
||||||
** clause is irrelevant.
|
** clause is irrelevant.
|
||||||
|
@ -1485,6 +1528,20 @@ WhereInfo *sqlite3WhereBegin(
|
||||||
Index *pIx;
|
Index *pIx;
|
||||||
int iIdxCur = pLevel->iIdxCur;
|
int iIdxCur = pLevel->iIdxCur;
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_EXPLAIN
|
||||||
|
if( pParse->explain==2 ){
|
||||||
|
char *zMsg;
|
||||||
|
struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom];
|
||||||
|
zMsg = sqlite3MPrintf("TABLE %s", pItem->zName);
|
||||||
|
if( pItem->zAlias ){
|
||||||
|
zMsg = sqlite3MPrintf("%z AS %s", zMsg, pItem->zAlias);
|
||||||
|
}
|
||||||
|
if( (pIx = pLevel->pIdx)!=0 ){
|
||||||
|
zMsg = sqlite3MPrintf("%z WITH INDEX %s", zMsg, pIx->zName);
|
||||||
|
}
|
||||||
|
sqlite3VdbeOp3(v, OP_Explain, i, pLevel->iFrom, zMsg, P3_DYNAMIC);
|
||||||
|
}
|
||||||
|
#endif /* SQLITE_OMIT_EXPLAIN */
|
||||||
pTabItem = &pTabList->a[pLevel->iFrom];
|
pTabItem = &pTabList->a[pLevel->iFrom];
|
||||||
pTab = pTabItem->pTab;
|
pTab = pTabItem->pTab;
|
||||||
if( pTab->isTransient || pTab->pSelect ) continue;
|
if( pTab->isTransient || pTab->pSelect ) continue;
|
||||||
|
@ -1540,8 +1597,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||||
if( pLevel->iFrom>0 && (pTabItem[-1].jointype & JT_LEFT)!=0 ){
|
if( pLevel->iFrom>0 && (pTabItem[-1].jointype & JT_LEFT)!=0 ){
|
||||||
if( !pParse->nMem ) pParse->nMem++;
|
if( !pParse->nMem ) pParse->nMem++;
|
||||||
pLevel->iLeftJoin = pParse->nMem++;
|
pLevel->iLeftJoin = pParse->nMem++;
|
||||||
sqlite3VdbeAddOp(v, OP_Null, 0, 0);
|
sqlite3VdbeAddOp(v, OP_MemInt, 0, pLevel->iLeftJoin);
|
||||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
|
|
||||||
VdbeComment((v, "# init LEFT JOIN no-match flag"));
|
VdbeComment((v, "# init LEFT JOIN no-match flag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1821,8 +1877,7 @@ WhereInfo *sqlite3WhereBegin(
|
||||||
*/
|
*/
|
||||||
if( pLevel->iLeftJoin ){
|
if( pLevel->iLeftJoin ){
|
||||||
pLevel->top = sqlite3VdbeCurrentAddr(v);
|
pLevel->top = sqlite3VdbeCurrentAddr(v);
|
||||||
sqlite3VdbeAddOp(v, OP_Integer, 1, 0);
|
sqlite3VdbeAddOp(v, OP_MemInt, 1, pLevel->iLeftJoin);
|
||||||
sqlite3VdbeAddOp(v, OP_MemStore, pLevel->iLeftJoin, 1);
|
|
||||||
VdbeComment((v, "# record LEFT JOIN hit"));
|
VdbeComment((v, "# record LEFT JOIN hit"));
|
||||||
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
|
for(pTerm=wc.a, j=0; j<wc.nTerm; j++, pTerm++){
|
||||||
if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
if( pTerm->flags & (TERM_VIRTUAL|TERM_CODED) ) continue;
|
||||||
|
@ -1924,13 +1979,13 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
|
||||||
}
|
}
|
||||||
if( pLevel->iLeftJoin ){
|
if( pLevel->iLeftJoin ){
|
||||||
int addr;
|
int addr;
|
||||||
addr = sqlite3VdbeAddOp(v, OP_MemLoad, pLevel->iLeftJoin, 0);
|
addr = sqlite3VdbeAddOp(v, OP_IfMemPos, pLevel->iLeftJoin, 0);
|
||||||
sqlite3VdbeAddOp(v, OP_NotNull, 1, addr+4 + (pLevel->iIdxCur>=0));
|
|
||||||
sqlite3VdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0);
|
sqlite3VdbeAddOp(v, OP_NullRow, pTabList->a[i].iCursor, 0);
|
||||||
if( pLevel->iIdxCur>=0 ){
|
if( pLevel->iIdxCur>=0 ){
|
||||||
sqlite3VdbeAddOp(v, OP_NullRow, pLevel->iIdxCur, 0);
|
sqlite3VdbeAddOp(v, OP_NullRow, pLevel->iIdxCur, 0);
|
||||||
}
|
}
|
||||||
sqlite3VdbeAddOp(v, OP_Goto, 0, pLevel->top);
|
sqlite3VdbeAddOp(v, OP_Goto, 0, pLevel->top);
|
||||||
|
sqlite3VdbeJumpHere(v, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue