aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2013-11-26 18:00:29 +0000
committerdrh <drh@noemail.net>2013-11-26 18:00:29 +0000
commit1b2ee4fe1afb4edd3d04e62daeb133df41809e38 (patch)
tree3f90016343959f3349a8086cb43c38cb4de975a3 /src
parent212c6be1417860712de4b93b31342b72c9fa89dd (diff)
parent55fcab39be8186caac6c7d1262a7c943564623bb (diff)
downloadsqlite-1b2ee4fe1afb4edd3d04e62daeb133df41809e38.tar.gz
sqlite-1b2ee4fe1afb4edd3d04e62daeb133df41809e38.zip
Merge in performance enhancements from trunk.
FossilOrigin-Name: fc9ae839569eb28eb734c52d95676c59b2e27494
Diffstat (limited to 'src')
-rw-r--r--src/backup.c1
-rw-r--r--src/btree.c116
-rw-r--r--src/btree.h4
-rw-r--r--src/build.c25
-rw-r--r--src/delete.c246
-rw-r--r--src/expr.c331
-rw-r--r--src/fkey.c2
-rw-r--r--src/func.c10
-rw-r--r--src/insert.c26
-rw-r--r--src/main.c7
-rw-r--r--src/mem5.c22
-rw-r--r--src/os_win.c78
-rw-r--r--src/parse.y7
-rw-r--r--src/pragma.c2
-rw-r--r--src/prepare.c8
-rw-r--r--src/resolve.c29
-rw-r--r--src/select.c22
-rw-r--r--src/shell.c38
-rw-r--r--src/sqlite.h.in21
-rw-r--r--src/sqliteInt.h44
-rw-r--r--src/tclsqlite.c12
-rw-r--r--src/test_config.c6
-rw-r--r--src/test_malloc.c28
-rw-r--r--src/trigger.c1
-rw-r--r--src/update.c75
-rw-r--r--src/util.c3
-rw-r--r--src/vdbe.c572
-rw-r--r--src/vdbeInt.h49
-rw-r--r--src/vdbeaux.c24
-rw-r--r--src/vdbeblob.c8
-rw-r--r--src/vdbemem.c39
-rw-r--r--src/vtab.c1
-rw-r--r--src/where.c52
33 files changed, 976 insertions, 933 deletions
diff --git a/src/backup.c b/src/backup.c
index afbaeeb10..1bac821f3 100644
--- a/src/backup.c
+++ b/src/backup.c
@@ -96,6 +96,7 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){
rc = SQLITE_ERROR;
}
sqlite3DbFree(pErrorDb, pParse->zErrMsg);
+ sqlite3ParserReset(pParse);
sqlite3StackFree(pErrorDb, pParse);
}
if( rc ){
diff --git a/src/btree.c b/src/btree.c
index cebf95e8d..27e714689 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -4206,7 +4206,7 @@ int sqlite3BtreeData(BtCursor *pCur, u32 offset, u32 amt, void *pBuf){
*/
static const unsigned char *fetchPayload(
BtCursor *pCur, /* Cursor pointing to entry to read from */
- int *pAmt, /* Write the number of available bytes here */
+ u32 *pAmt, /* Write the number of available bytes here */
int skipKey /* read beginning at data if this is true */
){
unsigned char *aPayload;
@@ -4219,7 +4219,7 @@ static const unsigned char *fetchPayload(
assert( cursorHoldsMutex(pCur) );
pPage = pCur->apPage[pCur->iPage];
assert( pCur->aiIdx[pCur->iPage]<pPage->nCell );
- if( NEVER(pCur->info.nSize==0) ){
+ if( pCur->info.nSize==0 ){
btreeParseCell(pCur->apPage[pCur->iPage], pCur->aiIdx[pCur->iPage],
&pCur->info);
}
@@ -4256,7 +4256,7 @@ static const unsigned char *fetchPayload(
** These routines is used to get quick access to key and data
** in the common case where no overflow pages are used.
*/
-const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){
+const void *sqlite3BtreeKeyFetch(BtCursor *pCur, u32 *pAmt){
const void *p = 0;
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorHoldsMutex(pCur) );
@@ -4265,7 +4265,7 @@ const void *sqlite3BtreeKeyFetch(BtCursor *pCur, int *pAmt){
}
return p;
}
-const void *sqlite3BtreeDataFetch(BtCursor *pCur, int *pAmt){
+const void *sqlite3BtreeDataFetch(BtCursor *pCur, u32 *pAmt){
const void *p = 0;
assert( sqlite3_mutex_held(pCur->pBtree->db->mutex) );
assert( cursorHoldsMutex(pCur) );
@@ -4647,10 +4647,10 @@ int sqlite3BtreeMovetoUnpacked(
}
assert( pCur->apPage[0]->intKey || pIdxKey );
for(;;){
- int lwr, upr, idx;
+ int lwr, upr, idx, c;
Pgno chldPg;
MemPage *pPage = pCur->apPage[pCur->iPage];
- int c;
+ u8 *pCell; /* Pointer to current cell in pPage */
/* pPage->nCell must be greater than zero. If this is the root-page
** the cursor would have been INVALID above and this for(;;) loop
@@ -4662,35 +4662,47 @@ int sqlite3BtreeMovetoUnpacked(
assert( pPage->intKey==(pIdxKey==0) );
lwr = 0;
upr = pPage->nCell-1;
- if( biasRight ){
- pCur->aiIdx[pCur->iPage] = (u16)(idx = upr);
- }else{
- pCur->aiIdx[pCur->iPage] = (u16)(idx = (upr+lwr)/2);
- }
- for(;;){
- u8 *pCell; /* Pointer to current cell in pPage */
-
- assert( idx==pCur->aiIdx[pCur->iPage] );
- pCur->info.nSize = 0;
- pCell = findCell(pPage, idx) + pPage->childPtrSize;
- if( pPage->intKey ){
+ assert( biasRight==0 || biasRight==1 );
+ idx = upr>>(1-biasRight); /* idx = biasRight ? upr : (lwr+upr)/2; */
+ pCur->aiIdx[pCur->iPage] = (u16)idx;
+ if( pPage->intKey ){
+ for(;;){
i64 nCellKey;
+ pCell = findCell(pPage, idx) + pPage->childPtrSize;
if( pPage->hasData ){
- u32 dummy;
- pCell += getVarint32(pCell, dummy);
+ while( 0x80 <= *(pCell++) ){
+ if( pCell>=pPage->aDataEnd ) return SQLITE_CORRUPT_BKPT;
+ }
}
getVarint(pCell, (u64*)&nCellKey);
- if( nCellKey==intKey ){
- c = 0;
- }else if( nCellKey<intKey ){
- c = -1;
+ if( nCellKey<intKey ){
+ lwr = idx+1;
+ if( lwr>upr ){ c = -1; break; }
+ }else if( nCellKey>intKey ){
+ upr = idx-1;
+ if( lwr>upr ){ c = +1; break; }
}else{
- assert( nCellKey>intKey );
- c = +1;
+ assert( nCellKey==intKey );
+ pCur->validNKey = 1;
+ pCur->info.nKey = nCellKey;
+ pCur->aiIdx[pCur->iPage] = (u16)idx;
+ if( !pPage->leaf ){
+ lwr = idx;
+ goto moveto_next_layer;
+ }else{
+ *pRes = 0;
+ rc = SQLITE_OK;
+ goto moveto_finish;
+ }
}
- pCur->validNKey = 1;
- pCur->info.nKey = nCellKey;
- }else{
+ assert( lwr+upr>=0 );
+ idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2; */
+ }
+ }else{
+ for(;;){
+ int nCell;
+ pCell = findCell(pPage, idx) + pPage->childPtrSize;
+
/* The maximum supported page-size is 65536 bytes. This means that
** the maximum number of record bytes stored on an index B-Tree
** page is less than 16384 bytes and may be stored as a 2-byte
@@ -4699,7 +4711,7 @@ int sqlite3BtreeMovetoUnpacked(
** stored entirely within the b-tree page by inspecting the first
** 2 bytes of the cell.
*/
- int nCell = pCell[0];
+ nCell = pCell[0];
if( nCell<=pPage->max1bytePayload
/* && (pCell+nCell)<pPage->aDataEnd */
){
@@ -4730,6 +4742,7 @@ int sqlite3BtreeMovetoUnpacked(
rc = SQLITE_NOMEM;
goto moveto_finish;
}
+ pCur->aiIdx[pCur->iPage] = (u16)idx;
rc = accessPayload(pCur, 0, nCell, (unsigned char*)pCellKey, 0);
if( rc ){
sqlite3_free(pCellKey);
@@ -4738,49 +4751,44 @@ int sqlite3BtreeMovetoUnpacked(
c = sqlite3VdbeRecordCompare(nCell, pCellKey, pIdxKey);
sqlite3_free(pCellKey);
}
- }
- if( c==0 ){
- if( pPage->intKey && !pPage->leaf ){
- lwr = idx;
- break;
+ if( c<0 ){
+ lwr = idx+1;
+ }else if( c>0 ){
+ upr = idx-1;
}else{
+ assert( c==0 );
*pRes = 0;
rc = SQLITE_OK;
+ pCur->aiIdx[pCur->iPage] = (u16)idx;
goto moveto_finish;
}
+ if( lwr>upr ) break;
+ assert( lwr+upr>=0 );
+ idx = (lwr+upr)>>1; /* idx = (lwr+upr)/2 */
}
- if( c<0 ){
- lwr = idx+1;
- }else{
- upr = idx-1;
- }
- if( lwr>upr ){
- break;
- }
- pCur->aiIdx[pCur->iPage] = (u16)(idx = (lwr+upr)/2);
}
assert( lwr==upr+1 || (pPage->intKey && !pPage->leaf) );
assert( pPage->isInit );
if( pPage->leaf ){
- chldPg = 0;
- }else if( lwr>=pPage->nCell ){
- chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
- }else{
- chldPg = get4byte(findCell(pPage, lwr));
- }
- if( chldPg==0 ){
assert( pCur->aiIdx[pCur->iPage]<pCur->apPage[pCur->iPage]->nCell );
+ pCur->aiIdx[pCur->iPage] = (u16)idx;
*pRes = c;
rc = SQLITE_OK;
goto moveto_finish;
}
+moveto_next_layer:
+ if( lwr>=pPage->nCell ){
+ chldPg = get4byte(&pPage->aData[pPage->hdrOffset+8]);
+ }else{
+ chldPg = get4byte(findCell(pPage, lwr));
+ }
pCur->aiIdx[pCur->iPage] = (u16)lwr;
- pCur->info.nSize = 0;
- pCur->validNKey = 0;
rc = moveToChild(pCur, chldPg);
- if( rc ) goto moveto_finish;
+ if( rc ) break;
}
moveto_finish:
+ pCur->info.nSize = 0;
+ pCur->validNKey = 0;
return rc;
}
diff --git a/src/btree.h b/src/btree.h
index 33b3ed1f0..3eb590695 100644
--- a/src/btree.h
+++ b/src/btree.h
@@ -178,8 +178,8 @@ int sqlite3BtreeEof(BtCursor*);
int sqlite3BtreePrevious(BtCursor*, int *pRes);
int sqlite3BtreeKeySize(BtCursor*, i64 *pSize);
int sqlite3BtreeKey(BtCursor*, u32 offset, u32 amt, void*);
-const void *sqlite3BtreeKeyFetch(BtCursor*, int *pAmt);
-const void *sqlite3BtreeDataFetch(BtCursor*, int *pAmt);
+const void *sqlite3BtreeKeyFetch(BtCursor*, u32 *pAmt);
+const void *sqlite3BtreeDataFetch(BtCursor*, u32 *pAmt);
int sqlite3BtreeDataSize(BtCursor*, u32 *pSize);
int sqlite3BtreeData(BtCursor*, u32 offset, u32 amt, void*);
void sqlite3BtreeSetCachedRowid(BtCursor*, sqlite3_int64);
diff --git a/src/build.c b/src/build.c
index d1615a128..27f026c8d 100644
--- a/src/build.c
+++ b/src/build.c
@@ -150,7 +150,7 @@ void sqlite3FinishCoding(Parse *pParse){
*/
if( pParse->cookieGoto>0 ){
yDbMask mask;
- int iDb;
+ int iDb, i, addr;
sqlite3VdbeJumpHere(v, pParse->cookieGoto-1);
for(iDb=0, mask=1; iDb<db->nDb; mask<<=1, iDb++){
if( (mask & pParse->cookieMask)==0 ) continue;
@@ -164,14 +164,11 @@ void sqlite3FinishCoding(Parse *pParse){
}
}
#ifndef SQLITE_OMIT_VIRTUALTABLE
- {
- int i;
- for(i=0; i<pParse->nVtabLock; i++){
- char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
- sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
- }
- pParse->nVtabLock = 0;
+ for(i=0; i<pParse->nVtabLock; i++){
+ char *vtab = (char *)sqlite3GetVTable(db, pParse->apVtabLock[i]);
+ sqlite3VdbeAddOp4(v, OP_VBegin, 0, 0, 0, vtab, P4_VTAB);
}
+ pParse->nVtabLock = 0;
#endif
/* Once all the cookies have been verified and transactions opened,
@@ -184,8 +181,18 @@ void sqlite3FinishCoding(Parse *pParse){
*/
sqlite3AutoincrementBegin(pParse);
+ /* Code constant expressions that where factored out of inner loops */
+ addr = pParse->cookieGoto;
+ if( pParse->pConstExpr ){
+ ExprList *pEL = pParse->pConstExpr;
+ pParse->cookieGoto = 0;
+ for(i=0; i<pEL->nExpr; i++){
+ sqlite3ExprCode(pParse, pEL->a[i].pExpr, pEL->a[i].u.iConstExprReg);
+ }
+ }
+
/* Finally, jump back to the beginning of the executable code. */
- sqlite3VdbeAddOp2(v, OP_Goto, 0, pParse->cookieGoto);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
}
}
diff --git a/src/delete.c b/src/delete.c
index 9ebb56eca..e43072235 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -227,20 +227,34 @@ void sqlite3DeleteFrom(
Vdbe *v; /* The virtual database engine */
Table *pTab; /* The table from which records will be deleted */
const char *zDb; /* Name of database holding pTab */
- int end, addr = 0; /* A couple addresses of generated code */
int i; /* Loop counter */
WhereInfo *pWInfo; /* Information about the WHERE clause */
Index *pIdx; /* For looping over indices of the table */
int iTabCur; /* Cursor number for the table */
int iDataCur; /* VDBE cursor for the canonical data source */
int iIdxCur; /* Cursor number of the first index */
+ int nIdx; /* Number of indices */
sqlite3 *db; /* Main database structure */
AuthContext sContext; /* Authorization context */
NameContext sNC; /* Name context to resolve expressions in */
int iDb; /* Database number */
int memCnt = -1; /* Memory cell used for change counting */
int rcauth; /* Value returned by authorization callback */
-
+ int okOnePass; /* True for one-pass algorithm without the FIFO */
+ int aiCurOnePass[2]; /* The write cursors opened by WHERE_ONEPASS */
+ u8 *aToOpen = 0; /* Open cursor iTabCur+j if aToOpen[j] is true */
+ Index *pPk; /* The PRIMARY KEY index on the table */
+ int iPk = 0; /* First of nPk registers holding PRIMARY KEY value */
+ i16 nPk = 1; /* Number of columns in the PRIMARY KEY */
+ int iKey; /* Memory cell holding key of row to be deleted */
+ i16 nKey; /* Number of memory cells in the row key */
+ int iEphCur = 0; /* Ephemeral table holding all primary key values */
+ int iRowSet = 0; /* Register for rowset of rows to delete */
+ int addrBypass = 0; /* Address of jump over the delete logic */
+ int addrLoop = 0; /* Top of the delete loop */
+ int addrDelete = 0; /* Jump directly to the delete logic */
+ int addrEphOpen = 0; /* Instruction to open the Ephermeral table */
+
#ifndef SQLITE_OMIT_TRIGGER
int isView; /* True if attempting to delete from a view */
Trigger *pTrigger; /* List of table triggers, if required */
@@ -295,11 +309,11 @@ void sqlite3DeleteFrom(
}
assert(!isView || pTrigger);
- /* Assign cursor number to the table and all its indices.
+ /* Assign cursor numbers to the table and all its indices.
*/
assert( pTabList->nSrc==1 );
iTabCur = pTabList->a[0].iCursor = pParse->nTab++;
- for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+ for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
pParse->nTab++;
}
@@ -372,106 +386,129 @@ void sqlite3DeleteFrom(
}
}else
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
- if( !HasRowid(pTab) ){
- /* There is a WHERE clause on a WITHOUT ROWID table.
+ {
+ if( HasRowid(pTab) ){
+ /* For a rowid table, initialize the RowSet to an empty set */
+ pPk = 0;
+ nPk = 1;
+ iRowSet = ++pParse->nMem;
+ sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
+ }else{
+ /* For a WITHOUT ROWID table, create an ephermeral table used to
+ ** hold all primary keys for rows to be deleted. */
+ pPk = sqlite3PrimaryKeyIndex(pTab);
+ assert( pPk!=0 );
+ nPk = pPk->nKeyCol;
+ iPk = pParse->nMem+1;
+ pParse->nMem += nPk;
+ iEphCur = pParse->nTab++;
+ addrEphOpen = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEphCur, nPk);
+ sqlite3VdbeSetP4KeyInfo(pParse, pPk);
+ }
+
+ /* Construct a query to find the rowid or primary key for every row
+ ** to be deleted, based on the WHERE clause.
*/
- Index *pPk; /* The PRIMARY KEY index on the table */
- int iPk; /* First of nPk memory cells holding PRIMARY KEY value */
- int iEph; /* Ephemeral table holding all primary key values */
- int iKey; /* Key value inserting into iEph */
- i16 nPk; /* Number of components of the PRIMARY KEY */
-
- pPk = sqlite3PrimaryKeyIndex(pTab);
- assert( pPk!=0 );
- nPk = pPk->nKeyCol;
- iPk = pParse->nMem+1;
- pParse->nMem += nPk;
- iKey = ++pParse->nMem;
- iEph = pParse->nTab++;
-
- sqlite3VdbeAddOp2(v, OP_OpenEphemeral, iEph, nPk);
- sqlite3VdbeSetP4KeyInfo(pParse, pPk);
- pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, 0, 0);
+ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0,
+ WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK,
+ iTabCur+1);
if( pWInfo==0 ) goto delete_from_cleanup;
- for(i=0; i<nPk; i++){
- sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i],iPk+i);
- }
- sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
- sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT);
- sqlite3VdbeAddOp2(v, OP_IdxInsert, iEph, iKey);
+ okOnePass = sqlite3WhereOkOnePass(pWInfo, aiCurOnePass);
+
+ /* Keep track of the number of rows to be deleted */
if( db->flags & SQLITE_CountRows ){
sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
}
- sqlite3WhereEnd(pWInfo);
-
- /* Open cursors for all indices of the table.
- */
- sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite,
- iTabCur, &iDataCur, &iIdxCur);
-
- /* Loop over the primary keys to be deleted. */
- addr = sqlite3VdbeAddOp1(v, OP_Rewind, iEph);
- sqlite3VdbeAddOp2(v, OP_RowKey, iEph, iPk);
-
- /* Delete the row */
- sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
- iPk, 0, 1, OE_Default, 0);
-
- /* End of the delete loop */
- sqlite3VdbeAddOp2(v, OP_Next, iEph, addr+1);
- sqlite3VdbeJumpHere(v, addr);
-
- /* Close the cursors open on the table and its indexes. */
- assert( iDataCur>=iIdxCur );
- for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
- sqlite3VdbeAddOp1(v, OP_Close, iIdxCur+i);
+
+ /* Extract the rowid or primary key for the current row */
+ if( pPk ){
+ for(i=0; i<nPk; i++){
+ sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur,
+ pPk->aiColumn[i], iPk+i);
+ }
+ iKey = iPk;
+ }else{
+ iKey = pParse->nMem + 1;
+ iKey = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iKey, 0);
+ if( iKey>pParse->nMem ) pParse->nMem = iKey;
}
- }else{
- /* There is a WHERE clause on a rowid table. Run a loop that extracts
- ** all rowids to be deleted into a RowSet.
- */
- int iRowSet = ++pParse->nMem; /* Register for rowset of rows to delete */
- int iRowid = ++pParse->nMem; /* Used for storing rowid values. */
- int regRowid; /* Actual register containing rowids */
-
- /* Collect rowids of every row to be deleted.
- */
- sqlite3VdbeAddOp2(v, OP_Null, 0, iRowSet);
- pWInfo = sqlite3WhereBegin(
- pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK, 0
- );
- if( pWInfo==0 ) goto delete_from_cleanup;
- regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iRowid, 0);
- sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
- if( db->flags & SQLITE_CountRows ){
- sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
+
+ if( okOnePass ){
+ /* For ONEPASS, no need to store the rowid/primary-key. There is only
+ ** one, so just keep it in its register(s) and fall through to the
+ ** delete code.
+ */
+ nKey = nPk; /* OP_Found will use an unpacked key */
+ aToOpen = sqlite3DbMallocRaw(db, nIdx+2);
+ if( aToOpen==0 ){
+ sqlite3WhereEnd(pWInfo);
+ goto delete_from_cleanup;
+ }
+ memset(aToOpen, 1, nIdx+1);
+ aToOpen[nIdx+1] = 0;
+ if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iTabCur] = 0;
+ if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iTabCur] = 0;
+ if( addrEphOpen ) sqlite3VdbeChangeToNoop(v, addrEphOpen);
+ addrDelete = sqlite3VdbeAddOp0(v, OP_Goto); /* Jump to DELETE logic */
+ }else if( pPk ){
+ /* Construct a composite key for the row to be deleted and remember it */
+ iKey = ++pParse->nMem;
+ nKey = 0; /* Zero tells OP_Found to use a composite key */
+ sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
+ sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT);
+ sqlite3VdbeAddOp2(v, OP_IdxInsert, iEphCur, iKey);
+ }else{
+ /* Get the rowid of the row to be deleted and remember it in the RowSet */
+ nKey = 1; /* OP_Seek always uses a single rowid */
+ sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, iKey);
}
+
+ /* End of the WHERE loop */
sqlite3WhereEnd(pWInfo);
-
- /* Delete every item whose key was written to the list during the
- ** database scan. We have to delete items after the scan is complete
- ** because deleting an item can change the scan order. */
- end = sqlite3VdbeMakeLabel(v);
-
+ if( okOnePass ){
+ /* Bypass the delete logic below if the WHERE loop found zero rows */
+ addrBypass = sqlite3VdbeMakeLabel(v);
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrBypass);
+ sqlite3VdbeJumpHere(v, addrDelete);
+ }
+
/* Unless this is a view, open cursors for the table we are
** deleting from and all its indices. If this is a view, then the
** only effect this statement has is to fire the INSTEAD OF
- ** triggers. */
+ ** triggers.
+ */
if( !isView ){
- sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur,
+ sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen,
&iDataCur, &iIdxCur);
- assert( iDataCur==iTabCur );
- assert( iIdxCur==iDataCur+1 );
+ assert( pPk || iDataCur==iTabCur );
+ assert( pPk || iIdxCur==iDataCur+1 );
}
-
- addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid);
-
+
+ /* Set up a loop over the rowids/primary-keys that were found in the
+ ** where-clause loop above.
+ */
+ if( okOnePass ){
+ /* Just one row. Hence the top-of-loop is a no-op */
+ assert( nKey==nPk ); /* OP_Found will use an unpacked key */
+ if( aToOpen[iDataCur-iTabCur] ){
+ assert( pPk!=0 );
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, addrBypass, iKey, nKey);
+ }
+ }else if( pPk ){
+ addrLoop = sqlite3VdbeAddOp1(v, OP_Rewind, iEphCur);
+ sqlite3VdbeAddOp2(v, OP_RowKey, iEphCur, iKey);
+ assert( nKey==0 ); /* OP_Found will use a composite key */
+ }else{
+ addrLoop = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, 0, iKey);
+ assert( nKey==1 );
+ }
+
/* Delete the row */
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( IsVirtual(pTab) ){
const char *pVTab = (const char *)sqlite3GetVTable(db, pTab);
sqlite3VtabMakeWritable(pParse, pTab);
- sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iRowid, (char*)pVTab, P4_VTAB);
+ sqlite3VdbeAddOp4(v, OP_VUpdate, 0, 1, iKey, pVTab, P4_VTAB);
sqlite3VdbeChangeP5(v, OE_Abort);
sqlite3MayAbort(pParse);
}else
@@ -479,21 +516,28 @@ void sqlite3DeleteFrom(
{
int count = (pParse->nested==0); /* True to count changes */
sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
- iRowid, 1, count, OE_Default, 0);
+ iKey, nKey, count, OE_Default, okOnePass);
}
-
- /* End of the delete loop */
- sqlite3VdbeAddOp2(v, OP_Goto, 0, addr);
- sqlite3VdbeResolveLabel(v, end);
-
+
+ /* End of the loop over all rowids/primary-keys. */
+ if( okOnePass ){
+ sqlite3VdbeResolveLabel(v, addrBypass);
+ }else if( pPk ){
+ sqlite3VdbeAddOp2(v, OP_Next, iEphCur, addrLoop+1);
+ sqlite3VdbeJumpHere(v, addrLoop);
+ }else{
+ sqlite3VdbeAddOp2(v, OP_Goto, 0, addrLoop);
+ sqlite3VdbeJumpHere(v, addrLoop);
+ }
+
/* Close the cursors open on the table and its indexes. */
if( !isView && !IsVirtual(pTab) ){
- sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
+ if( !pPk ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i);
}
}
- }
+ } /* End non-truncate path */
/* Update the sqlite_sequence table by storing the content of the
** maximum rowid counter values recorded while inserting into
@@ -517,6 +561,7 @@ delete_from_cleanup:
sqlite3AuthContextPop(&sContext);
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprDelete(db, pWhere);
+ sqlite3DbFree(db, aToOpen);
return;
}
/* Make sure "isView" and other macros defined above are undefined. Otherwise
@@ -583,6 +628,7 @@ void sqlite3GenerateRowDelete(
if( sqlite3FkRequired(pParse, pTab, 0, 0) || pTrigger ){
u32 mask; /* Mask of OLD.* columns in use */
int iCol; /* Iterator used while populating OLD.* */
+ int addrStart; /* Start of BEFORE trigger programs */
/* TODO: Could use temporary registers here. Also could attempt to
** avoid copying the contents of the rowid register. */
@@ -603,15 +649,19 @@ void sqlite3GenerateRowDelete(
}
/* Invoke BEFORE DELETE trigger programs. */
+ addrStart = sqlite3VdbeCurrentAddr(v);
sqlite3CodeRowTrigger(pParse, pTrigger,
TK_DELETE, 0, TRIGGER_BEFORE, pTab, iOld, onconf, iLabel
);
- /* Seek the cursor to the row to be deleted again. It may be that
- ** the BEFORE triggers coded above have already removed the row
- ** being deleted. Do not attempt to delete the row a second time, and
- ** do not fire AFTER triggers. */
- sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
+ /* If any BEFORE triggers were coded, then seek the cursor to the
+ ** row to be deleted again. It may be that the BEFORE triggers moved
+ ** the cursor or of already deleted the row that the cursor was
+ ** pointing to.
+ */
+ if( addrStart<sqlite3VdbeCurrentAddr(v) ){
+ sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
+ }
/* Do FK processing. This call checks that any FK constraints that
** refer to this table (i.e. constraints attached to other tables)
diff --git a/src/expr.c b/src/expr.c
index 7e72b44f9..6c8a8cce7 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -930,8 +930,7 @@ ExprList *sqlite3ExprListDup(sqlite3 *db, ExprList *p, int flags){
pItem->sortOrder = pOldItem->sortOrder;
pItem->done = 0;
pItem->bSpanIsTab = pOldItem->bSpanIsTab;
- pItem->iOrderByCol = pOldItem->iOrderByCol;
- pItem->iAlias = pOldItem->iAlias;
+ pItem->u = pOldItem->u;
}
return pNew;
}
@@ -1192,9 +1191,12 @@ static int exprNodeIsConstant(Walker *pWalker, Expr *pExpr){
switch( pExpr->op ){
/* Consider functions to be constant if all their arguments are constant
- ** and pWalker->u.i==2 */
+ ** and either pWalker->u.i==2 or the function as the SQLITE_FUNC_CONST
+ ** flag. */
case TK_FUNCTION:
- if( pWalker->u.i==2 ) return 0;
+ if( pWalker->u.i==2 || ExprHasProperty(pExpr,EP_Constant) ){
+ return WRC_Continue;
+ }
/* Fall through */
case TK_ID:
case TK_COLUMN:
@@ -2356,6 +2358,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
int regFree2 = 0; /* If non-zero free this temporary register */
int r1, r2, r3, r4; /* Various register numbers */
sqlite3 *db = pParse->db; /* The database connection */
+ Expr tempX; /* Temporary expression node */
assert( target>0 && target<=pParse->nMem );
if( v==0 ){
@@ -2575,8 +2578,10 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
codeReal(v, pLeft->u.zToken, 1, target);
#endif
}else{
- regFree1 = r1 = sqlite3GetTempReg(pParse);
- sqlite3VdbeAddOp2(v, OP_Integer, 0, r1);
+ tempX.op = TK_INTEGER;
+ tempX.flags = EP_IntValue|EP_TokenOnly;
+ tempX.u.iValue = 0;
+ r1 = sqlite3ExprCodeTemp(pParse, &tempX, &regFree1);
r2 = sqlite3ExprCodeTemp(pParse, pExpr->pLeft, &regFree2);
sqlite3VdbeAddOp3(v, OP_Subtract, r2, r1, target);
testcase( regFree2==0 );
@@ -2621,7 +2626,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
break;
}
- case TK_CONST_FUNC:
case TK_FUNCTION: {
ExprList *pFarg; /* List of function arguments */
int nFarg; /* Number of function arguments */
@@ -2634,8 +2638,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
CollSeq *pColl = 0; /* A collating sequence */
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- testcase( op==TK_CONST_FUNC );
- testcase( op==TK_FUNCTION );
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
pFarg = 0;
}else{
@@ -2679,8 +2681,21 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
break;
}
+ for(i=0; i<nFarg; i++){
+ if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
+ constMask |= (1<<i);
+ }
+ if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
+ pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr);
+ }
+ }
if( pFarg ){
- r1 = sqlite3GetTempRange(pParse, nFarg);
+ if( constMask ){
+ r1 = pParse->nMem+1;
+ pParse->nMem += nFarg;
+ }else{
+ r1 = sqlite3GetTempRange(pParse, nFarg);
+ }
/* For length() and typeof() functions with a column argument,
** set the P5 parameter to the OP_Column opcode to OPFLAG_LENGTHARG
@@ -2695,14 +2710,15 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
if( exprOp==TK_COLUMN || exprOp==TK_AGG_COLUMN ){
assert( SQLITE_FUNC_LENGTH==OPFLAG_LENGTHARG );
assert( SQLITE_FUNC_TYPEOF==OPFLAG_TYPEOFARG );
- testcase( (pDef->funcFlags&~SQLITE_FUNC_ENCMASK)
- ==SQLITE_FUNC_LENGTH );
- pFarg->a[0].pExpr->op2 = pDef->funcFlags&~SQLITE_FUNC_ENCMASK;
+ testcase( pDef->funcFlags & OPFLAG_LENGTHARG );
+ pFarg->a[0].pExpr->op2 =
+ pDef->funcFlags & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG);
}
}
sqlite3ExprCachePush(pParse); /* Ticket 2ea2425d34be */
- sqlite3ExprCodeExprList(pParse, pFarg, r1, 1);
+ sqlite3ExprCodeExprList(pParse, pFarg, r1,
+ SQLITE_ECEL_DUP|SQLITE_ECEL_FACTOR);
sqlite3ExprCachePop(pParse, 1); /* Ticket 2ea2425d34be */
}else{
r1 = 0;
@@ -2726,14 +2742,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
pDef = sqlite3VtabOverloadFunction(db, pDef, nFarg, pFarg->a[0].pExpr);
}
#endif
- for(i=0; i<nFarg; i++){
- if( i<32 && sqlite3ExprIsConstant(pFarg->a[i].pExpr) ){
- constMask |= (1<<i);
- }
- if( (pDef->funcFlags & SQLITE_FUNC_NEEDCOLL)!=0 && !pColl ){
- pColl = sqlite3ExprCollSeq(pParse, pFarg->a[i].pExpr);
- }
- }
if( pDef->funcFlags & SQLITE_FUNC_NEEDCOLL ){
if( !pColl ) pColl = db->pDfltColl;
sqlite3VdbeAddOp4(v, OP_CollSeq, 0, 0, 0, (char *)pColl, P4_COLLSEQ);
@@ -2741,7 +2749,7 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
sqlite3VdbeAddOp4(v, OP_Function, constMask, r1, target,
(char*)pDef, P4_FUNCDEF);
sqlite3VdbeChangeP5(v, (u8)nFarg);
- if( nFarg ){
+ if( nFarg && constMask==0 ){
sqlite3ReleaseTempRange(pParse, r1, nFarg);
}
break;
@@ -2892,7 +2900,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
ExprList *pEList; /* List of WHEN terms */
struct ExprList_item *aListelem; /* Array of WHEN terms */
Expr opCompare; /* The X==Ei expression */
- Expr cacheX; /* Cached expression X */
Expr *pX; /* The X expression */
Expr *pTest = 0; /* X==Ei (form A) or just Ei (form B) */
VVA_ONLY( int iCacheLevel = pParse->iCacheLevel; )
@@ -2904,13 +2911,12 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
nExpr = pEList->nExpr;
endLabel = sqlite3VdbeMakeLabel(v);
if( (pX = pExpr->pLeft)!=0 ){
- cacheX = *pX;
+ tempX = *pX;
testcase( pX->op==TK_COLUMN );
- testcase( pX->op==TK_REGISTER );
- exprToRegister(&cacheX, sqlite3ExprCodeTemp(pParse, pX, &regFree1));
+ exprToRegister(&tempX, sqlite3ExprCodeTemp(pParse, pX, &regFree1));
testcase( regFree1==0 );
opCompare.op = TK_EQ;
- opCompare.pLeft = &cacheX;
+ opCompare.pLeft = &tempX;
pTest = &opCompare;
/* Ticket b351d95f9cd5ef17e9d9dbae18f5ca8611190001:
** The value in regFree1 might get SCopy-ed into the file result.
@@ -2930,7 +2936,6 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
testcase( pTest->op==TK_COLUMN );
sqlite3ExprIfFalse(pParse, pTest, nextCase, SQLITE_JUMPIFNULL);
testcase( aListelem[i+1].pExpr->op==TK_COLUMN );
- testcase( aListelem[i+1].pExpr->op==TK_REGISTER );
sqlite3ExprCode(pParse, aListelem[i+1].pExpr, target);
sqlite3VdbeAddOp2(v, OP_Goto, 0, endLabel);
sqlite3ExprCachePop(pParse, 1);
@@ -2982,6 +2987,28 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
}
/*
+** Factor out the code of the given expression to initialization time.
+*/
+void sqlite3ExprCodeAtInit(
+ Parse *pParse, /* Parsing context */
+ Expr *pExpr, /* The expression to code when the VDBE initializes */
+ int regDest, /* Store the value in this register */
+ u8 reusable /* True if this expression is reusable */
+){
+ ExprList *p;
+ assert( ConstFactorOk(pParse) );
+ p = pParse->pConstExpr;
+ pExpr = sqlite3ExprDup(pParse->db, pExpr, 0);
+ p = sqlite3ExprListAppend(pParse, p, pExpr);
+ if( p ){
+ struct ExprList_item *pItem = &p->a[p->nExpr-1];
+ pItem->u.iConstExprReg = regDest;
+ pItem->reusable = reusable;
+ }
+ pParse->pConstExpr = p;
+}
+
+/*
** Generate code to evaluate an expression and store the results
** into a register. Return the register number where the results
** are stored.
@@ -2989,15 +3016,40 @@ int sqlite3ExprCodeTarget(Parse *pParse, Expr *pExpr, int target){
** If the register is a temporary register that can be deallocated,
** then write its number into *pReg. If the result register is not
** a temporary, then set *pReg to zero.
+**
+** If pExpr is a constant, then this routine might generate this
+** code to fill the register in the initialization section of the
+** VDBE program, in order to factor it out of the evaluation loop.
*/
int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){
- int r1 = sqlite3GetTempReg(pParse);
- int r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
- if( r2==r1 ){
- *pReg = r1;
+ int r2;
+ pExpr = sqlite3ExprSkipCollate(pExpr);
+ if( ConstFactorOk(pParse)
+ && pExpr->op!=TK_REGISTER
+ && sqlite3ExprIsConstantNotJoin(pExpr)
+ ){
+ ExprList *p = pParse->pConstExpr;
+ int i;
+ *pReg = 0;
+ if( p ){
+ struct ExprList_item *pItem;
+ for(pItem=p->a, i=p->nExpr; i>0; pItem++, i--){
+ if( pItem->reusable && sqlite3ExprCompare(pItem->pExpr,pExpr,-1)==0 ){
+ return pItem->u.iConstExprReg;
+ }
+ }
+ }
+ r2 = ++pParse->nMem;
+ sqlite3ExprCodeAtInit(pParse, pExpr, r2, 1);
}else{
- sqlite3ReleaseTempReg(pParse, r1);
- *pReg = 0;
+ int r1 = sqlite3GetTempReg(pParse);
+ r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
+ if( r2==r1 ){
+ *pReg = r1;
+ }else{
+ sqlite3ReleaseTempReg(pParse, r1);
+ *pReg = 0;
+ }
}
return r2;
}
@@ -3040,12 +3092,13 @@ int sqlite3ExprCodeAndCache(Parse *pParse, Expr *pExpr, int target){
int inReg;
inReg = sqlite3ExprCode(pParse, pExpr, target);
assert( target>0 );
- /* This routine is called for terms to INSERT or UPDATE. And the only
- ** other place where expressions can be converted into TK_REGISTER is
- ** in WHERE clause processing. So as currently implemented, there is
- ** no way for a TK_REGISTER to exist here. But it seems prudent to
- ** keep the ALWAYS() in case the conditions above change with future
- ** modifications or enhancements. */
+ /* The only place, other than this routine, where expressions can be
+ ** converted to TK_REGISTER is internal subexpressions in BETWEEN and
+ ** CASE operators. Neither ever calls this routine. And this routine
+ ** is never called twice on the same expression. Hence it is impossible
+ ** for the input to this routine to already be a register. Nevertheless,
+ ** it seems prudent to keep the ALWAYS() in case the conditions above
+ ** change with future modifications or enhancements. */
if( ALWAYS(pExpr->op!=TK_REGISTER) ){
int iMem;
iMem = ++pParse->nMem;
@@ -3177,7 +3230,6 @@ void sqlite3ExplainExpr(Vdbe *pOut, Expr *pExpr){
}
case TK_AGG_FUNCTION:
- case TK_CONST_FUNC:
case TK_FUNCTION: {
ExprList *pFarg; /* List of function arguments */
if( ExprHasProperty(pExpr, EP_TokenOnly) ){
@@ -3329,163 +3381,40 @@ void sqlite3ExplainExprList(Vdbe *pOut, ExprList *pList){
#endif /* SQLITE_DEBUG */
/*
-** Return TRUE if pExpr is an constant expression that is appropriate
-** for factoring out of a loop. Appropriate expressions are:
-**
-** * Any expression that evaluates to two or more opcodes.
-**
-** * Any OP_Integer, OP_Real, OP_String, OP_Blob, OP_Null,
-** or OP_Variable that does not need to be placed in a
-** specific register.
-**
-** There is no point in factoring out single-instruction constant
-** expressions that need to be placed in a particular register.
-** We could factor them out, but then we would end up adding an
-** OP_SCopy instruction to move the value into the correct register
-** later. We might as well just use the original instruction and
-** avoid the OP_SCopy.
-*/
-static int isAppropriateForFactoring(Expr *p){
- if( !sqlite3ExprIsConstantNotJoin(p) ){
- return 0; /* Only constant expressions are appropriate for factoring */
- }
- if( (p->flags & EP_FixedDest)==0 ){
- return 1; /* Any constant without a fixed destination is appropriate */
- }
- while( p->op==TK_UPLUS ) p = p->pLeft;
- switch( p->op ){
-#ifndef SQLITE_OMIT_BLOB_LITERAL
- case TK_BLOB:
-#endif
- case TK_VARIABLE:
- case TK_INTEGER:
- case TK_FLOAT:
- case TK_NULL:
- case TK_STRING: {
- testcase( p->op==TK_BLOB );
- testcase( p->op==TK_VARIABLE );
- testcase( p->op==TK_INTEGER );
- testcase( p->op==TK_FLOAT );
- testcase( p->op==TK_NULL );
- testcase( p->op==TK_STRING );
- /* Single-instruction constants with a fixed destination are
- ** better done in-line. If we factor them, they will just end
- ** up generating an OP_SCopy to move the value to the destination
- ** register. */
- return 0;
- }
- case TK_UMINUS: {
- if( p->pLeft->op==TK_FLOAT || p->pLeft->op==TK_INTEGER ){
- return 0;
- }
- break;
- }
- default: {
- break;
- }
- }
- return 1;
-}
-
-/*
-** If pExpr is a constant expression that is appropriate for
-** factoring out of a loop, then evaluate the expression
-** into a register and convert the expression into a TK_REGISTER
-** expression.
-*/
-static int evalConstExpr(Walker *pWalker, Expr *pExpr){
- Parse *pParse = pWalker->pParse;
- switch( pExpr->op ){
- case TK_IN:
- case TK_REGISTER: {
- return WRC_Prune;
- }
- case TK_COLLATE: {
- return WRC_Continue;
- }
- case TK_FUNCTION:
- case TK_AGG_FUNCTION:
- case TK_CONST_FUNC: {
- /* The arguments to a function have a fixed destination.
- ** Mark them this way to avoid generated unneeded OP_SCopy
- ** instructions.
- */
- ExprList *pList = pExpr->x.pList;
- assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
- if( pList ){
- int i = pList->nExpr;
- struct ExprList_item *pItem = pList->a;
- for(; i>0; i--, pItem++){
- if( ALWAYS(pItem->pExpr) ) pItem->pExpr->flags |= EP_FixedDest;
- }
- }
- break;
- }
- }
- if( isAppropriateForFactoring(pExpr) ){
- int r1 = ++pParse->nMem;
- int r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1);
- /* If r2!=r1, it means that register r1 is never used. That is harmless
- ** but suboptimal, so we want to know about the situation to fix it.
- ** Hence the following assert: */
- assert( r2==r1 );
- exprToRegister(pExpr, r2);
- return WRC_Prune;
- }
- return WRC_Continue;
-}
-
-/*
-** Preevaluate constant subexpressions within pExpr and store the
-** results in registers. Modify pExpr so that the constant subexpresions
-** are TK_REGISTER opcodes that refer to the precomputed values.
-**
-** This routine is a no-op if the jump to the cookie-check code has
-** already occur. Since the cookie-check jump is generated prior to
-** any other serious processing, this check ensures that there is no
-** way to accidently bypass the constant initializations.
-**
-** This routine is also a no-op if the SQLITE_FactorOutConst optimization
-** is disabled via the sqlite3_test_control(SQLITE_TESTCTRL_OPTIMIZATIONS)
-** interface. This allows test logic to verify that the same answer is
-** obtained for queries regardless of whether or not constants are
-** precomputed into registers or if they are inserted in-line.
-*/
-void sqlite3ExprCodeConstants(Parse *pParse, Expr *pExpr){
- Walker w;
- if( pParse->cookieGoto ) return;
- if( OptimizationDisabled(pParse->db, SQLITE_FactorOutConst) ) return;
- memset(&w, 0, sizeof(w));
- w.xExprCallback = evalConstExpr;
- w.pParse = pParse;
- sqlite3WalkExpr(&w, pExpr);
-}
-
-
-/*
** Generate code that pushes the value of every element of the given
** expression list into a sequence of registers beginning at target.
**
** Return the number of elements evaluated.
+**
+** The SQLITE_ECEL_DUP flag prevents the arguments from being
+** filled using OP_SCopy. OP_Copy must be used instead.
+**
+** The SQLITE_ECEL_FACTOR argument allows constant arguments to be
+** factored out into initialization code.
*/
int sqlite3ExprCodeExprList(
Parse *pParse, /* Parsing context */
ExprList *pList, /* The expression list to be coded */
int target, /* Where to write results */
- int doHardCopy /* Make a hard copy of every element */
+ u8 flags /* SQLITE_ECEL_* flags */
){
struct ExprList_item *pItem;
int i, n;
+ u8 copyOp = (flags & SQLITE_ECEL_DUP) ? OP_Copy : OP_SCopy;
assert( pList!=0 );
assert( target>0 );
assert( pParse->pVdbe!=0 ); /* Never gets this far otherwise */
n = pList->nExpr;
+ if( !ConstFactorOk(pParse) ) flags &= ~SQLITE_ECEL_FACTOR;
for(pItem=pList->a, i=0; i<n; i++, pItem++){
Expr *pExpr = pItem->pExpr;
- int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
- if( inReg!=target+i ){
- sqlite3VdbeAddOp2(pParse->pVdbe, doHardCopy ? OP_Copy : OP_SCopy,
- inReg, target+i);
+ if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstant(pExpr) ){
+ sqlite3ExprCodeAtInit(pParse, pExpr, target+i, 0);
+ }else{
+ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i);
+ if( inReg!=target+i ){
+ sqlite3VdbeAddOp2(pParse->pVdbe, copyOp, inReg, target+i);
+ }
}
}
return n;
@@ -3839,16 +3768,18 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){
** an incorrect 0 or 1 could lead to a malfunction.
*/
int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
- if( pA==0||pB==0 ){
+ u32 combinedFlags;
+ if( pA==0 || pB==0 ){
return pB==pA ? 0 : 2;
}
- assert( !ExprHasProperty(pA, EP_TokenOnly|EP_Reduced) );
- assert( !ExprHasProperty(pB, EP_TokenOnly|EP_Reduced) );
- if( ExprHasProperty(pA, EP_xIsSelect) || ExprHasProperty(pB, EP_xIsSelect) ){
+ combinedFlags = pA->flags | pB->flags;
+ if( combinedFlags & EP_IntValue ){
+ if( (pA->flags&pB->flags&EP_IntValue)!=0 && pA->u.iValue==pB->u.iValue ){
+ return 0;
+ }
return 2;
}
- if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
- if( pA->op!=pB->op && (pA->op!=TK_REGISTER || pA->op2!=pB->op) ){
+ if( pA->op!=pB->op ){
if( pA->op==TK_COLLATE && sqlite3ExprCompare(pA->pLeft, pB, iTab)<2 ){
return 1;
}
@@ -3857,23 +3788,23 @@ int sqlite3ExprCompare(Expr *pA, Expr *pB, int iTab){
}
return 2;
}
- if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2;
- if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2;
- if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
- if( pA->iColumn!=pB->iColumn ) return 2;
- if( pA->iTable!=pB->iTable
- && pA->op!=TK_REGISTER
- && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
- if( ExprHasProperty(pA, EP_IntValue) ){
- if( !ExprHasProperty(pB, EP_IntValue) || pA->u.iValue!=pB->u.iValue ){
- return 2;
- }
- }else if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken){
- if( ExprHasProperty(pB, EP_IntValue) || NEVER(pB->u.zToken==0) ) return 2;
+ if( pA->op!=TK_COLUMN && ALWAYS(pA->op!=TK_AGG_COLUMN) && pA->u.zToken ){
if( strcmp(pA->u.zToken,pB->u.zToken)!=0 ){
return pA->op==TK_COLLATE ? 1 : 2;
}
}
+ if( (pA->flags & EP_Distinct)!=(pB->flags & EP_Distinct) ) return 2;
+ if( ALWAYS((combinedFlags & EP_TokenOnly)==0) ){
+ if( combinedFlags & EP_xIsSelect ) return 2;
+ if( sqlite3ExprCompare(pA->pLeft, pB->pLeft, iTab) ) return 2;
+ if( sqlite3ExprCompare(pA->pRight, pB->pRight, iTab) ) return 2;
+ if( sqlite3ExprListCompare(pA->x.pList, pB->x.pList, iTab) ) return 2;
+ if( ALWAYS((combinedFlags & EP_Reduced)==0) ){
+ if( pA->iColumn!=pB->iColumn ) return 2;
+ if( pA->iTable!=pB->iTable
+ && (pA->iTable!=iTab || NEVER(pB->iTable>=0)) ) return 2;
+ }
+ }
return 0;
}
diff --git a/src/fkey.c b/src/fkey.c
index 1cb6cb0d4..46c90a098 100644
--- a/src/fkey.c
+++ b/src/fkey.c
@@ -548,6 +548,7 @@ static void fkScanChildren(
assert( pIdx==0 || pIdx->pTable==pTab );
assert( pIdx==0 || pIdx->nKeyCol==pFKey->nCol );
assert( pIdx!=0 || pFKey->nCol==1 );
+ assert( pIdx!=0 || HasRowid(pTab) );
if( nIncr<0 ){
iFkIfZero = sqlite3VdbeAddOp2(v, OP_FkIfZero, pFKey->isDeferred, 0);
@@ -600,6 +601,7 @@ static void fkScanChildren(
}else{
Expr *pEq, *pAll = 0;
Index *pPk = sqlite3PrimaryKeyIndex(pTab);
+ assert( pIdx!=0 );
for(i=0; i<pPk->nKeyCol; i++){
i16 iCol = pIdx->aiColumn[i];
pLeft = exprTableRegister(pParse, pTab, regData, iCol);
diff --git a/src/func.c b/src/func.c
index c9962f6d9..46c606ac0 100644
--- a/src/func.c
+++ b/src/func.c
@@ -1664,8 +1664,8 @@ void sqlite3RegisterGlobalFunctions(void){
FUNCTION2(ifnull, 2, 0, 0, noopFunc, SQLITE_FUNC_COALESCE),
FUNCTION2(unlikely, 1, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
FUNCTION2(likelihood, 2, 0, 0, noopFunc, SQLITE_FUNC_UNLIKELY),
- FUNCTION(random, 0, 0, 0, randomFunc ),
- FUNCTION(randomblob, 1, 0, 0, randomBlob ),
+ VFUNCTION(random, 0, 0, 0, randomFunc ),
+ VFUNCTION(randomblob, 1, 0, 0, randomBlob ),
FUNCTION(nullif, 2, 0, 1, nullifFunc ),
FUNCTION(sqlite_version, 0, 0, 0, versionFunc ),
FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ),
@@ -1675,9 +1675,9 @@ void sqlite3RegisterGlobalFunctions(void){
FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ),
#endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */
FUNCTION(quote, 1, 0, 0, quoteFunc ),
- FUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
- FUNCTION(changes, 0, 0, 0, changes ),
- FUNCTION(total_changes, 0, 0, 0, total_changes ),
+ VFUNCTION(last_insert_rowid, 0, 0, 0, last_insert_rowid),
+ VFUNCTION(changes, 0, 0, 0, changes ),
+ VFUNCTION(total_changes, 0, 0, 0, total_changes ),
FUNCTION(replace, 3, 0, 0, replaceFunc ),
FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ),
#ifdef SQLITE_SOUNDEX
diff --git a/src/insert.c b/src/insert.c
index 1c89a38af..df1b3fc9c 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -820,7 +820,7 @@ void sqlite3Insert(
/* If this is not a view, open the table and and all indices */
if( !isView ){
int nIdx;
- nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, -1,
+ nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, -1, 0,
&iDataCur, &iIdxCur);
aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1));
if( aRegIdx==0 ){
@@ -1692,16 +1692,19 @@ int sqlite3OpenTableAndIndices(
Table *pTab, /* Table to be opened */
int op, /* OP_OpenRead or OP_OpenWrite */
int iBase, /* Use this for the table cursor, if there is one */
+ u8 *aToOpen, /* If not NULL: boolean for each table and index */
int *piDataCur, /* Write the database source cursor number here */
int *piIdxCur /* Write the first index cursor number here */
){
int i;
int iDb;
+ int iDataCur;
Index *pIdx;
Vdbe *v;
assert( op==OP_OpenRead || op==OP_OpenWrite );
if( IsVirtual(pTab) ){
+ assert( aToOpen==0 );
*piDataCur = 0;
*piIdxCur = 1;
return 0;
@@ -1710,20 +1713,25 @@ int sqlite3OpenTableAndIndices(
v = sqlite3GetVdbe(pParse);
assert( v!=0 );
if( iBase<0 ) iBase = pParse->nTab;
- if( HasRowid(pTab) ){
- *piDataCur = iBase++;
- sqlite3OpenTable(pParse, *piDataCur, iDb, pTab, op);
+ iDataCur = iBase++;
+ if( piDataCur ) *piDataCur = iDataCur;
+ if( HasRowid(pTab) && (aToOpen==0 || aToOpen[0]) ){
+ sqlite3OpenTable(pParse, iDataCur, iDb, pTab, op);
}else{
sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
}
- *piIdxCur = iBase;
+ if( piIdxCur ) *piIdxCur = iBase;
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
int iIdxCur = iBase++;
assert( pIdx->pSchema==pTab->pSchema );
- if( pIdx->autoIndex==2 && !HasRowid(pTab) ) *piDataCur = iIdxCur;
- sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
- sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
- VdbeComment((v, "%s", pIdx->zName));
+ if( pIdx->autoIndex==2 && !HasRowid(pTab) && piDataCur ){
+ *piDataCur = iIdxCur;
+ }
+ if( aToOpen==0 || aToOpen[i+1] ){
+ sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb);
+ sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
+ VdbeComment((v, "%s", pIdx->zName));
+ }
}
if( iBase>pParse->nTab ) pParse->nTab = iBase;
return i;
diff --git a/src/main.c b/src/main.c
index 653c8f1f1..6bd5ab024 100644
--- a/src/main.c
+++ b/src/main.c
@@ -515,6 +515,13 @@ int sqlite3_config(int op, ...){
break;
}
+#if SQLITE_OS_WIN && defined(SQLITE_WIN32_MALLOC)
+ case SQLITE_CONFIG_WIN32_HEAPSIZE: {
+ sqlite3GlobalConfig.nHeap = va_arg(ap, int);
+ break;
+ }
+#endif
+
default: {
rc = SQLITE_ERROR;
break;
diff --git a/src/mem5.c b/src/mem5.c
index 5f99ebf43..3870e9148 100644
--- a/src/mem5.c
+++ b/src/mem5.c
@@ -210,25 +210,6 @@ static int memsys5Size(void *p){
}
/*
-** Find the first entry on the freelist iLogsize. Unlink that
-** entry and return its index.
-*/
-static int memsys5UnlinkFirst(int iLogsize){
- int i;
- int iFirst;
-
- assert( iLogsize>=0 && iLogsize<=LOGMAX );
- i = iFirst = mem5.aiFreelist[iLogsize];
- assert( iFirst>=0 );
- while( i>0 ){
- if( i<iFirst ) iFirst = i;
- i = MEM5LINK(i)->next;
- }
- memsys5Unlink(iFirst, iLogsize);
- return iFirst;
-}
-
-/*
** Return a block of memory of at least nBytes in size.
** Return NULL if unable. Return NULL if nBytes==0.
**
@@ -273,7 +254,8 @@ static void *memsys5MallocUnsafe(int nByte){
sqlite3_log(SQLITE_NOMEM, "failed to allocate %u bytes", nByte);
return 0;
}
- i = memsys5UnlinkFirst(iBin);
+ i = mem5.aiFreelist[iBin];
+ memsys5Unlink(i, iBin);
while( iBin>iLogsize ){
int newSize;
diff --git a/src/os_win.c b/src/os_win.c
index a2f5513a2..31c4b69df 100644
--- a/src/os_win.c
+++ b/src/os_win.c
@@ -1401,14 +1401,20 @@ static int winMemInit(void *pAppData){
#if !SQLITE_OS_WINRT && SQLITE_WIN32_HEAP_CREATE
if( !pWinMemData->hHeap ){
+ DWORD dwInitialSize = SQLITE_WIN32_HEAP_INIT_SIZE;
+ DWORD dwMaximumSize = (DWORD)sqlite3GlobalConfig.nHeap;
+ if( dwMaximumSize==0 ){
+ dwMaximumSize = SQLITE_WIN32_HEAP_MAX_SIZE;
+ }else if( dwInitialSize>dwMaximumSize ){
+ dwInitialSize = dwMaximumSize;
+ }
pWinMemData->hHeap = osHeapCreate(SQLITE_WIN32_HEAP_FLAGS,
- SQLITE_WIN32_HEAP_INIT_SIZE,
- SQLITE_WIN32_HEAP_MAX_SIZE);
+ dwInitialSize, dwMaximumSize);
if( !pWinMemData->hHeap ){
sqlite3_log(SQLITE_NOMEM,
- "failed to HeapCreate (%lu), flags=%u, initSize=%u, maxSize=%u",
- osGetLastError(), SQLITE_WIN32_HEAP_FLAGS,
- SQLITE_WIN32_HEAP_INIT_SIZE, SQLITE_WIN32_HEAP_MAX_SIZE);
+ "failed to HeapCreate (%lu), flags=%u, initSize=%lu, maxSize=%lu",
+ osGetLastError(), SQLITE_WIN32_HEAP_FLAGS, dwInitialSize,
+ dwMaximumSize);
return SQLITE_NOMEM;
}
pWinMemData->bOwned = TRUE;
@@ -4068,7 +4074,7 @@ static const sqlite3_io_methods winIoMethod = {
** sqlite3_vfs object.
*/
-#if 0
+#if defined(__CYGWIN__)
/*
** Convert a filename from whatever the underlying operating system
** supports for filenames into UTF-8. Space to hold the result is
@@ -4244,23 +4250,17 @@ static int winGetTempname(sqlite3_vfs *pVfs, char **pzBuf){
** be used. However, we may need to convert the string containing
** its name into UTF-8 (i.e. if it is UTF-16 right now).
*/
- if( osIsNT() ){
- char *zUtf8 = winUnicodeToUtf8(zConverted);
- if( !zUtf8 ){
- sqlite3_free(zConverted);
- sqlite3_free(zBuf);
- OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
- return SQLITE_IOERR_NOMEM;
- }
- sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
- sqlite3_free(zUtf8);
- sqlite3_free(zConverted);
- break;
- }else{
- sqlite3_snprintf(nMax, zBuf, "%s", zConverted);
+ char *zUtf8 = winConvertToUtf8Filename(zConverted);
+ if( !zUtf8 ){
sqlite3_free(zConverted);
- break;
+ sqlite3_free(zBuf);
+ OSTRACE(("TEMP-FILENAME rc=SQLITE_IOERR_NOMEM\n"));
+ return SQLITE_IOERR_NOMEM;
}
+ sqlite3_snprintf(nMax, zBuf, "%s", zUtf8);
+ sqlite3_free(zUtf8);
+ sqlite3_free(zConverted);
+ break;
}
sqlite3_free(zConverted);
}
@@ -4945,19 +4945,43 @@ static int winFullPathname(
if( !zOut ){
return SQLITE_IOERR_NOMEM;
}
- if( cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, zRelative, zOut,
- pVfs->mxPathname+1)<0 ){
+ if( cygwin_conv_path(
+ (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A) |
+ CCP_RELATIVE, zRelative, zOut, pVfs->mxPathname+1)<0 ){
sqlite3_free(zOut);
return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
"winFullPathname1", zRelative);
+ }else{
+ char *zUtf8 = winConvertToUtf8Filename(zOut);
+ if( !zUtf8 ){
+ sqlite3_free(zOut);
+ return SQLITE_IOERR_NOMEM;
+ }
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
+ sqlite3_data_directory, winGetDirSep(), zUtf8);
+ sqlite3_free(zUtf8);
+ sqlite3_free(zOut);
}
- sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s%c%s",
- sqlite3_data_directory, winGetDirSep(), zOut);
- sqlite3_free(zOut);
}else{
- if( cygwin_conv_path(CCP_POSIX_TO_WIN_A, zRelative, zFull, nFull)<0 ){
+ char *zOut = sqlite3MallocZero( pVfs->mxPathname+1 );
+ if( !zOut ){
+ return SQLITE_IOERR_NOMEM;
+ }
+ if( cygwin_conv_path(
+ (osIsNT() ? CCP_POSIX_TO_WIN_W : CCP_POSIX_TO_WIN_A),
+ zRelative, zOut, pVfs->mxPathname+1)<0 ){
+ sqlite3_free(zOut);
return winLogError(SQLITE_CANTOPEN_CONVPATH, (DWORD)errno,
"winFullPathname2", zRelative);
+ }else{
+ char *zUtf8 = winConvertToUtf8Filename(zOut);
+ if( !zUtf8 ){
+ sqlite3_free(zOut);
+ return SQLITE_IOERR_NOMEM;
+ }
+ sqlite3_snprintf(MIN(nFull, pVfs->mxPathname), zFull, "%s", zUtf8);
+ sqlite3_free(zUtf8);
+ sqlite3_free(zOut);
}
}
return SQLITE_OK;
diff --git a/src/parse.y b/src/parse.y
index 07e607dcf..ba9feb10f 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -854,12 +854,7 @@ expr(A) ::= ID(X) LP STAR RP(E). {
spanSet(&A,&X,&E);
}
term(A) ::= CTIME_KW(OP). {
- /* The CURRENT_TIME, CURRENT_DATE, and CURRENT_TIMESTAMP values are
- ** treated as functions that return constants */
- A.pExpr = sqlite3ExprFunction(pParse, 0,&OP);
- if( A.pExpr ){
- A.pExpr->op = TK_CONST_FUNC;
- }
+ A.pExpr = sqlite3ExprFunction(pParse, 0, &OP);
spanSet(&A, &OP, &OP);
}
diff --git a/src/pragma.c b/src/pragma.c
index 76a452c46..bbd27b8c1 100644
--- a/src/pragma.c
+++ b/src/pragma.c
@@ -1891,7 +1891,7 @@ void sqlite3Pragma(
sqlite3VdbeJumpHere(v, addr);
sqlite3ExprCacheClear(pParse);
sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead,
- 1, &iDataCur, &iIdxCur);
+ 1, 0, &iDataCur, &iIdxCur);
sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
diff --git a/src/prepare.c b/src/prepare.c
index cfc9c3485..7ea7f3bd6 100644
--- a/src/prepare.c
+++ b/src/prepare.c
@@ -525,6 +525,13 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){
}
/*
+** Free all memory allocations in the pParse object
+*/
+void sqlite3ParserReset(Parse *pParse){
+ if( pParse ) sqlite3ExprListDelete(pParse->db, pParse->pConstExpr);
+}
+
+/*
** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
*/
static int sqlite3Prepare(
@@ -681,6 +688,7 @@ static int sqlite3Prepare(
end_prepare:
+ sqlite3ParserReset(pParse);
sqlite3StackFree(db, pParse);
rc = sqlite3ApiExit(db, rc);
assert( (rc&db->errMask)==rc );
diff --git a/src/resolve.c b/src/resolve.c
index b41f23442..2c0907cc4 100644
--- a/src/resolve.c
+++ b/src/resolve.c
@@ -108,10 +108,10 @@ static void resolveAlias(
pDup = sqlite3PExpr(pParse, TK_AS, pDup, 0, 0);
if( pDup==0 ) return;
ExprSetProperty(pDup, EP_Skip);
- if( pEList->a[iCol].iAlias==0 ){
- pEList->a[iCol].iAlias = (u16)(++pParse->nAlias);
+ if( pEList->a[iCol].u.x.iAlias==0 ){
+ pEList->a[iCol].u.x.iAlias = (u16)(++pParse->nAlias);
}
- pDup->iTable = pEList->a[iCol].iAlias;
+ pDup->iTable = pEList->a[iCol].u.x.iAlias;
}
if( pExpr->op==TK_COLLATE ){
pDup = sqlite3ExprAddCollateString(pParse, pDup, pExpr->u.zToken);
@@ -667,7 +667,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
/* Resolve function names
*/
- case TK_CONST_FUNC:
case TK_FUNCTION: {
ExprList *pList = pExpr->x.pList; /* The argument list */
int n = pList ? pList->nExpr : 0; /* Number of arguments */
@@ -680,7 +679,6 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
FuncDef *pDef; /* Information about the function */
u8 enc = ENC(pParse->db); /* The database encoding */
- testcase( pExpr->op==TK_CONST_FUNC );
assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
notValidPartIdxWhere(pParse, pNC, "functions");
zId = pExpr->u.zToken;
@@ -725,6 +723,7 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
pExpr->op = TK_NULL;
return WRC_Prune;
}
+ if( pDef->funcFlags & SQLITE_FUNC_CONSTANT ) ExprSetProperty(pExpr,EP_Constant);
}
#endif
if( is_agg && (pNC->ncFlags & NC_AllowAgg)==0 ){
@@ -976,7 +975,7 @@ static int resolveCompoundOrderBy(
pItem->pExpr->pLeft = pNew;
}
sqlite3ExprDelete(db, pE);
- pItem->iOrderByCol = (u16)iCol;
+ pItem->u.x.iOrderByCol = (u16)iCol;
pItem->done = 1;
}else{
moreToDo = 1;
@@ -997,8 +996,8 @@ static int resolveCompoundOrderBy(
/*
** Check every term in the ORDER BY or GROUP BY clause pOrderBy of
** the SELECT statement pSelect. If any term is reference to a
-** result set expression (as determined by the ExprList.a.iOrderByCol field)
-** then convert that term into a copy of the corresponding result set
+** result set expression (as determined by the ExprList.a.u.x.iOrderByCol
+** field) then convert that term into a copy of the corresponding result set
** column.
**
** If any errors are detected, add an error message to pParse and
@@ -1025,12 +1024,12 @@ int sqlite3ResolveOrderGroupBy(
pEList = pSelect->pEList;
assert( pEList!=0 ); /* sqlite3SelectNew() guarantees this */
for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){
- if( pItem->iOrderByCol ){
- if( pItem->iOrderByCol>pEList->nExpr ){
+ if( pItem->u.x.iOrderByCol ){
+ if( pItem->u.x.iOrderByCol>pEList->nExpr ){
resolveOutOfRangeError(pParse, zType, i+1, pEList->nExpr);
return 1;
}
- resolveAlias(pParse, pEList, pItem->iOrderByCol-1, pItem->pExpr, zType,0);
+ resolveAlias(pParse, pEList, pItem->u.x.iOrderByCol-1, pItem->pExpr, zType,0);
}
}
return 0;
@@ -1079,7 +1078,7 @@ static int resolveOrderGroupBy(
** a copy of the iCol-th result-set column. The subsequent call to
** sqlite3ResolveOrderGroupBy() will convert the expression to a
** copy of the iCol-th result-set expression. */
- pItem->iOrderByCol = (u16)iCol;
+ pItem->u.x.iOrderByCol = (u16)iCol;
continue;
}
}
@@ -1091,18 +1090,18 @@ static int resolveOrderGroupBy(
resolveOutOfRangeError(pParse, zType, i+1, nResult);
return 1;
}
- pItem->iOrderByCol = (u16)iCol;
+ pItem->u.x.iOrderByCol = (u16)iCol;
continue;
}
/* Otherwise, treat the ORDER BY term as an ordinary expression */
- pItem->iOrderByCol = 0;
+ pItem->u.x.iOrderByCol = 0;
if( sqlite3ResolveExprNames(pNC, pE) ){
return 1;
}
for(j=0; j<pSelect->pEList->nExpr; j++){
if( sqlite3ExprCompare(pE, pSelect->pEList->a[j].pExpr, -1)==0 ){
- pItem->iOrderByCol = j+1;
+ pItem->u.x.iOrderByCol = j+1;
}
}
}
diff --git a/src/select.c b/src/select.c
index 5cdef3aed..aa8e54b02 100644
--- a/src/select.c
+++ b/src/select.c
@@ -599,7 +599,8 @@ static void selectInnerLoop(
** values returned by the SELECT are not required.
*/
sqlite3ExprCacheClear(pParse);
- sqlite3ExprCodeExprList(pParse, pEList, regResult, eDest==SRT_Output);
+ sqlite3ExprCodeExprList(pParse, pEList, regResult,
+ (eDest==SRT_Output)?SQLITE_ECEL_DUP:0);
}
nColumn = nResultCol;
@@ -2372,8 +2373,8 @@ static int multiSelectOrderBy(
for(i=1; db->mallocFailed==0 && i<=p->pEList->nExpr; i++){
struct ExprList_item *pItem;
for(j=0, pItem=pOrderBy->a; j<nOrderBy; j++, pItem++){
- assert( pItem->iOrderByCol>0 );
- if( pItem->iOrderByCol==i ) break;
+ assert( pItem->u.x.iOrderByCol>0 );
+ if( pItem->u.x.iOrderByCol==i ) break;
}
if( j==nOrderBy ){
Expr *pNew = sqlite3Expr(db, TK_INTEGER, 0);
@@ -2381,7 +2382,7 @@ static int multiSelectOrderBy(
pNew->flags |= EP_IntValue;
pNew->u.iValue = i;
pOrderBy = sqlite3ExprListAppend(pParse, pOrderBy, pNew);
- if( pOrderBy ) pOrderBy->a[nOrderBy++].iOrderByCol = (u16)i;
+ if( pOrderBy ) pOrderBy->a[nOrderBy++].u.x.iOrderByCol = (u16)i;
}
}
}
@@ -2397,8 +2398,9 @@ static int multiSelectOrderBy(
if( aPermute ){
struct ExprList_item *pItem;
for(i=0, pItem=pOrderBy->a; i<nOrderBy; i++, pItem++){
- assert( pItem->iOrderByCol>0 && pItem->iOrderByCol<=p->pEList->nExpr );
- aPermute[i] = pItem->iOrderByCol - 1;
+ assert( pItem->u.x.iOrderByCol>0
+ && pItem->u.x.iOrderByCol<=p->pEList->nExpr );
+ aPermute[i] = pItem->u.x.iOrderByCol - 1;
}
pKeyMerge = sqlite3KeyInfoAlloc(db, nOrderBy, 1);
if( pKeyMerge ){
@@ -2978,7 +2980,7 @@ static int flattenSubquery(
if( p->pOrderBy ){
int ii;
for(ii=0; ii<p->pOrderBy->nExpr; ii++){
- if( p->pOrderBy->a[ii].iOrderByCol==0 ) return 0;
+ if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0;
}
}
}
@@ -3884,7 +3886,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){
if( pList ){
nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg);
- sqlite3ExprCodeExprList(pParse, pList, regAgg, 1);
+ sqlite3ExprCodeExprList(pParse, pList, regAgg, SQLITE_ECEL_DUP);
}else{
nArg = 0;
regAgg = 0;
@@ -4385,10 +4387,10 @@ int sqlite3Select(
struct ExprList_item *pItem; /* For looping over expression in a list */
for(k=p->pEList->nExpr, pItem=p->pEList->a; k>0; k--, pItem++){
- pItem->iAlias = 0;
+ pItem->u.x.iAlias = 0;
}
for(k=pGroupBy->nExpr, pItem=pGroupBy->a; k>0; k--, pItem++){
- pItem->iAlias = 0;
+ pItem->u.x.iAlias = 0;
}
if( p->nSelectRow>100 ) p->nSelectRow = 100;
}else{
diff --git a/src/shell.c b/src/shell.c
index 61df7d6d5..1db1e64e7 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -466,6 +466,7 @@ struct callback_data {
FILE *pLog; /* Write log output here */
int *aiIndent; /* Array of indents used in MODE_Explain */
int nIndent; /* Size of array aiIndent[] */
+ int iIndent; /* Index of current op in aiIndent[] */
};
/*
@@ -771,10 +772,10 @@ static int shell_callback(void *pArg, int nArg, char **azArg, char **azCol, int
w = strlen30(azArg[i]);
}
if( i==1 && p->aiIndent && p->pStmt ){
- int iOp = sqlite3_column_int(p->pStmt, 0);
- if( iOp<p->nIndent ){
- fprintf(p->out, "%*.s", p->aiIndent[iOp], "");
+ if( p->iIndent<p->nIndent ){
+ fprintf(p->out, "%*.s", p->aiIndent[p->iIndent], "");
}
+ p->iIndent++;
}
if( w<0 ){
fprintf(p->out,"%*.*s%s",-w,-w,
@@ -1173,9 +1174,10 @@ static int str_in_array(const char *zStr, const char **azArray){
** all opcodes that occur between the p2 jump destination and the opcode
** itself by 2 spaces.
**
-** * For each "Goto", if the jump destination is a "Yield", "SeekGt",
-** or "SeekLt" instruction that occurs earlier in the program than
-** the Goto itself, indent all opcodes between the earlier instruction
+** * For each "Goto", if the jump destination is earlier in the program
+** and ends on one of:
+** Yield SeekGt SeekLt RowSetRead
+** then indent all opcodes between the earlier instruction
** and "Goto" by 2 spaces.
*/
static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
@@ -1183,10 +1185,10 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
const char *z; /* Used to check if this is an EXPLAIN */
int *abYield = 0; /* True if op is an OP_Yield */
int nAlloc = 0; /* Allocated size of p->aiIndent[], abYield */
- int iOp;
+ int iOp; /* Index of operation in p->aiIndent[] */
- const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", 0 };
- const char *azYield[] = { "Yield", "SeekLt", "SeekGt", 0 };
+ const char *azNext[] = { "Next", "Prev", "VPrev", "VNext", "SorterNext", 0 };
+ const char *azYield[] = { "Yield", "SeekLt", "SeekGt", "RowSetRead", 0 };
const char *azGoto[] = { "Goto", 0 };
/* Try to figure out if this is really an EXPLAIN statement. If this
@@ -1198,8 +1200,16 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
for(iOp=0; SQLITE_ROW==sqlite3_step(pSql); iOp++){
int i;
+ int iAddr = sqlite3_column_int(pSql, 0);
const char *zOp = (const char*)sqlite3_column_text(pSql, 1);
+
+ /* Set p2 to the P2 field of the current opcode. Then, assuming that
+ ** p2 is an instruction address, set variable p2op to the index of that
+ ** instruction in the aiIndent[] array. p2 and p2op may be different if
+ ** the current instruction is part of a sub-program generated by an
+ ** SQL trigger or foreign key. */
int p2 = sqlite3_column_int(pSql, 3);
+ int p2op = (p2 + (iOp-iAddr));
/* Grow the p->aiIndent array as required */
if( iOp>=nAlloc ){
@@ -1212,13 +1222,14 @@ static void explain_data_prepare(struct callback_data *p, sqlite3_stmt *pSql){
p->nIndent = iOp+1;
if( str_in_array(zOp, azNext) ){
- for(i=p2; i<iOp; i++) p->aiIndent[i] += 2;
+ for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
}
- if( str_in_array(zOp, azGoto) && p2<p->nIndent && abYield[p2] ){
- for(i=p2+1; i<iOp; i++) p->aiIndent[i] += 2;
+ if( str_in_array(zOp, azGoto) && p2op<p->nIndent && abYield[p2op] ){
+ for(i=p2op; i<iOp; i++) p->aiIndent[i] += 2;
}
}
+ p->iIndent = 0;
sqlite3_free(abYield);
sqlite3_reset(pSql);
}
@@ -1230,6 +1241,7 @@ static void explain_data_delete(struct callback_data *p){
sqlite3_free(p->aiIndent);
p->aiIndent = 0;
p->nIndent = 0;
+ p->iIndent = 0;
}
/*
@@ -1295,7 +1307,7 @@ static int shell_exec(
/* If the shell is currently in ".explain" mode, gather the extra
** data required to add indents to the output.*/
- if( pArg->mode==MODE_Explain ){
+ if( pArg && pArg->mode==MODE_Explain ){
explain_data_prepare(pArg, pStmt);
}
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index f3466cb25..5f048e7a6 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -365,7 +365,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** <ul>
** <li> The application must insure that the 1st parameter to sqlite3_exec()
** is a valid and open [database connection].
-** <li> The application must not close [database connection] specified by
+** <li> The application must not close the [database connection] specified by
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
@@ -442,7 +442,7 @@ int sqlite3_exec(
** [sqlite3_extended_result_codes()] API.
**
** Some of the available extended result codes are listed here.
-** One may expect the number of extended result codes will be expand
+** One may expect the number of extended result codes will increase
** over time. Software that uses extended result codes should expect
** to see new result codes in future releases of SQLite.
**
@@ -1380,7 +1380,7 @@ int sqlite3_db_config(sqlite3*, int op, ...);
** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
** that causes the corresponding memory allocation to fail.
**
-** The xInit method initializes the memory allocator. (For example,
+** The xInit method initializes the memory allocator. For example,
** it might allocate any require mutexes or initialize internal data
** structures. The xShutdown method is invoked (indirectly) by
** [sqlite3_shutdown()] and should deallocate any resources acquired
@@ -1682,6 +1682,13 @@ struct sqlite3_mem_methods {
** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^
** ^If either argument to this option is negative, then that argument is
** changed to its compile-time default.
+**
+** [[SQLITE_CONFIG_WIN32_HEAPSIZE]]
+** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE
+** <dd>^This option is only available if SQLite is compiled for Windows
+** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined.
+** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
+** that specifies the maximum size of the created heap.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@@ -1706,6 +1713,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
+#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
/*
** CAPI3REF: Database Connection Configuration Options
@@ -3106,7 +3114,6 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
-** the
** </li>
** </ol>
*/
@@ -3836,7 +3843,7 @@ int sqlite3_data_count(sqlite3_stmt *pStmt);
** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
** [sqlite3_finalize()] is called. ^The memory space used to hold strings
** and BLOBs is freed automatically. Do <b>not</b> pass the pointers returned
-** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
+** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
** [sqlite3_free()].
**
** ^(If a memory allocation error occurs during the evaluation of any
@@ -4914,8 +4921,8 @@ int sqlite3_release_memory(int);
**
** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap
** memory as possible from database connection D. Unlike the
-** [sqlite3_release_memory()] interface, this interface is effect even
-** when then [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is
+** [sqlite3_release_memory()] interface, this interface is in effect even
+** when the [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is
** omitted.
**
** See also: [sqlite3_release_memory()]
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 06228b291..943b93cc3 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -1086,6 +1086,13 @@ struct sqlite3 {
#endif
/*
+** Return true if it OK to factor constant expressions into the initialization
+** code. The argument is a Parse object for the code generator.
+*/
+#define ConstFactorOk(P) \
+ ((P)->cookieGoto>0 && OptimizationEnabled((P)->db,SQLITE_FactorOutConst))
+
+/*
** Possible values for the sqlite.magic field.
** The numbers are obtained at random and have no special meaning, other
** than being distinct from one another.
@@ -1151,6 +1158,7 @@ struct FuncDestructor {
#define SQLITE_FUNC_COUNT 0x100 /* Built-in count(*) aggregate */
#define SQLITE_FUNC_COALESCE 0x200 /* Built-in coalesce() or ifnull() */
#define SQLITE_FUNC_UNLIKELY 0x400 /* Built-in unlikely() function */
+#define SQLITE_FUNC_CONSTANT 0x800 /* Constant inputs give a constant output */
/*
** The following three macros, FUNCTION(), LIKEFUNC() and AGGREGATE() are
@@ -1163,6 +1171,9 @@ struct FuncDestructor {
** as the user-data (sqlite3_user_data()) for the function. If
** argument bNC is true, then the SQLITE_FUNC_NEEDCOLL flag is set.
**
+** VFUNCTION(zName, nArg, iArg, bNC, xFunc)
+** Like FUNCTION except it omits the SQLITE_FUNC_CONSTANT flag.
+**
** AGGREGATE(zName, nArg, iArg, bNC, xStep, xFinal)
** Used to create an aggregate function definition implemented by
** the C functions xStep and xFinal. The first four parameters
@@ -1178,16 +1189,20 @@ struct FuncDestructor {
** parameter.
*/
#define FUNCTION(zName, nArg, iArg, bNC, xFunc) \
+ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
+ SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
+#define VFUNCTION(zName, nArg, iArg, bNC, xFunc) \
{nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
#define FUNCTION2(zName, nArg, iArg, bNC, xFunc, extraFlags) \
- {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags, \
+ {nArg,SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL)|extraFlags,\
SQLITE_INT_TO_PTR(iArg), 0, xFunc, 0, 0, #zName, 0, 0}
#define STR_FUNCTION(zName, nArg, pArg, bNC, xFunc) \
- {nArg, SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
+ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|(bNC*SQLITE_FUNC_NEEDCOLL), \
pArg, 0, xFunc, 0, 0, #zName, 0, 0}
#define LIKEFUNC(zName, nArg, arg, flags) \
- {nArg, SQLITE_UTF8|flags, (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
+ {nArg, SQLITE_FUNC_CONSTANT|SQLITE_UTF8|flags, \
+ (void *)arg, 0, likeFunc, 0, 0, #zName, 0, 0}
#define AGGREGATE(zName, nArg, arg, nc, xStep, xFinal) \
{nArg, SQLITE_UTF8|(nc*SQLITE_FUNC_NEEDCOLL), \
SQLITE_INT_TO_PTR(arg), 0, 0, xStep,xFinal,#zName,0,0}
@@ -1837,7 +1852,7 @@ struct Expr {
#define EP_DblQuoted 0x000040 /* token.z was originally in "..." */
#define EP_InfixFunc 0x000080 /* True for an infix function: LIKE, GLOB, etc */
#define EP_Collate 0x000100 /* Tree contains a TK_COLLATE opeartor */
-#define EP_FixedDest 0x000200 /* Result needed in a specific register */
+ /* unused 0x000200 */
#define EP_IntValue 0x000400 /* Integer value contained in u.iValue */
#define EP_xIsSelect 0x000800 /* x.pSelect is valid (otherwise x.pList is) */
#define EP_Skip 0x001000 /* COLLATE, AS, or UNLIKELY */
@@ -1847,6 +1862,7 @@ struct Expr {
#define EP_MemToken 0x010000 /* Need to sqlite3DbFree() Expr.zToken */
#define EP_NoReduce 0x020000 /* Cannot EXPRDUP_REDUCE this Expr */
#define EP_Unlikely 0x040000 /* unlikely() or likelihood() function */
+#define EP_Constant 0x080000 /* Node is a constant */
/*
** These macros can be used to test, set, or clear bits in the
@@ -1908,8 +1924,14 @@ struct ExprList {
u8 sortOrder; /* 1 for DESC or 0 for ASC */
unsigned done :1; /* A flag to indicate when processing is finished */
unsigned bSpanIsTab :1; /* zSpan holds DB.TABLE.COLUMN */
- u16 iOrderByCol; /* For ORDER BY, column number in result set */
- u16 iAlias; /* Index into Parse.aAlias[] for zName */
+ unsigned reusable :1; /* Constant expression is reusable */
+ union {
+ struct {
+ u16 iOrderByCol; /* For ORDER BY, column number in result set */
+ u16 iAlias; /* Index into Parse.aAlias[] for zName */
+ } x;
+ int iConstExprReg; /* Register in which Expr value is cached */
+ } u;
} *a; /* Alloc a power of two greater or equal to nExpr */
};
@@ -2286,6 +2308,7 @@ struct Parse {
int iReg; /* Reg with value of this column. 0 means none. */
int lru; /* Least recently used entry has the smallest value */
} aColCache[SQLITE_N_COLCACHE]; /* One for each column cache entry */
+ ExprList *pConstExpr;/* Constant expressions */
yDbMask writeMask; /* Start a write transaction on these databases */
yDbMask cookieMask; /* Bitmask of schema verified databases */
int cookieGoto; /* Address of OP_Goto to cookie verifier subroutine */
@@ -2900,11 +2923,13 @@ void sqlite3ExprCacheRemove(Parse*, int, int);
void sqlite3ExprCacheClear(Parse*);
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
int sqlite3ExprCode(Parse*, Expr*, int);
+void sqlite3ExprCodeAtInit(Parse*, Expr*, int, u8);
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
int sqlite3ExprCodeAndCache(Parse*, Expr*, int);
-void sqlite3ExprCodeConstants(Parse*, Expr*);
-int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int);
+int sqlite3ExprCodeExprList(Parse*, ExprList*, int, u8);
+#define SQLITE_ECEL_DUP 0x01 /* Deep, not shallow copies */
+#define SQLITE_ECEL_FACTOR 0x02 /* Factor out constant terms */
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
@@ -2949,7 +2974,7 @@ int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*);
void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int,
u8,u8,int,int*);
void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
-int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, int*, int*);
+int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, u8*, int*, int*);
void sqlite3BeginWriteOperation(Parse*, int, int);
void sqlite3MultiWrite(Parse*);
void sqlite3MayAbort(Parse*);
@@ -3271,6 +3296,7 @@ void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
+void sqlite3ParserReset(Parse*);
int sqlite3Reprepare(Vdbe*);
void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*);
CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *);
diff --git a/src/tclsqlite.c b/src/tclsqlite.c
index d9a1e5778..5efc113a6 100644
--- a/src/tclsqlite.c
+++ b/src/tclsqlite.c
@@ -425,13 +425,12 @@ static int safeToUseEvalObjv(Tcl_Interp *interp, Tcl_Obj *pCmd){
*/
static SqlFunc *findSqlFunc(SqliteDb *pDb, const char *zName){
SqlFunc *p, *pNew;
- int i;
- pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + strlen30(zName) + 1 );
+ int nName = strlen30(zName);
+ pNew = (SqlFunc*)Tcl_Alloc( sizeof(*pNew) + nName + 1 );
pNew->zName = (char*)&pNew[1];
- for(i=0; zName[i]; i++){ pNew->zName[i] = tolower(zName[i]); }
- pNew->zName[i] = 0;
+ memcpy(pNew->zName, zName, nName+1);
for(p=pDb->pFunc; p; p=p->pNext){
- if( strcmp(p->zName, pNew->zName)==0 ){
+ if( sqlite3_stricmp(p->zName, pNew->zName)==0 ){
Tcl_Free((char*)pNew);
return p;
}
@@ -1127,13 +1126,14 @@ static int dbPrepareAndBind(
int nSql; /* Length of zSql in bytes */
int nVar; /* Number of variables in statement */
int iParm = 0; /* Next free entry in apParm */
+ char c;
int i;
Tcl_Interp *interp = pDb->interp;
*ppPreStmt = 0;
/* Trim spaces from the start of zSql and calculate the remaining length. */
- while( isspace(zSql[0]) ){ zSql++; }
+ while( (c = zSql[0])==' ' || c=='\t' || c=='\r' || c=='\n' ){ zSql++; }
nSql = strlen30(zSql);
for(pPreStmt = pDb->stmtList; pPreStmt; pPreStmt=pPreStmt->pNext){
diff --git a/src/test_config.c b/src/test_config.c
index a624a43db..5fa43515e 100644
--- a/src/test_config.c
+++ b/src/test_config.c
@@ -63,6 +63,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "curdir", "0", TCL_GLOBAL_ONLY);
#endif
+#ifdef SQLITE_WIN32_MALLOC
+ Tcl_SetVar2(interp, "sqlite_options", "win32malloc", "1", TCL_GLOBAL_ONLY);
+#else
+ Tcl_SetVar2(interp, "sqlite_options", "win32malloc", "0", TCL_GLOBAL_ONLY);
+#endif
+
#ifdef SQLITE_DEBUG
Tcl_SetVar2(interp, "sqlite_options", "debug", "1", TCL_GLOBAL_ONLY);
#else
diff --git a/src/test_malloc.c b/src/test_malloc.c
index f513e24bf..e3cfcaa9f 100644
--- a/src/test_malloc.c
+++ b/src/test_malloc.c
@@ -1131,6 +1131,33 @@ static int test_config_heap(
}
/*
+** Usage: sqlite3_config_heap_size NBYTE
+*/
+static int test_config_heap_size(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ int nByte; /* Size to pass to sqlite3_config() */
+ int rc; /* Return code of sqlite3_config() */
+
+ Tcl_Obj * CONST *aArg = &objv[1];
+ int nArg = objc-1;
+
+ if( nArg!=1 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "NBYTE");
+ return TCL_ERROR;
+ }
+ if( Tcl_GetIntFromObj(interp, aArg[0], &nByte) ) return TCL_ERROR;
+
+ rc = sqlite3_config(SQLITE_CONFIG_WIN32_HEAPSIZE, nByte);
+
+ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE);
+ return TCL_OK;
+}
+
+/*
** Usage: sqlite3_config_error [DB]
**
** Invoke sqlite3_config() or sqlite3_db_config() with invalid
@@ -1473,6 +1500,7 @@ int Sqlitetest_malloc_Init(Tcl_Interp *interp){
{ "sqlite3_db_status", test_db_status ,0 },
{ "install_malloc_faultsim", test_install_malloc_faultsim ,0 },
{ "sqlite3_config_heap", test_config_heap ,0 },
+ { "sqlite3_config_heap_size", test_config_heap_size ,0 },
{ "sqlite3_config_memstatus", test_config_memstatus ,0 },
{ "sqlite3_config_lookaside", test_config_lookaside ,0 },
{ "sqlite3_config_error", test_config_error ,0 },
diff --git a/src/trigger.c b/src/trigger.c
index 607b83124..1c68a708d 100644
--- a/src/trigger.c
+++ b/src/trigger.c
@@ -924,6 +924,7 @@ static TriggerPrg *codeRowTrigger(
assert( !pSubParse->pAinc && !pSubParse->pZombieTab );
assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg );
+ sqlite3ParserReset(pSubParse);
sqlite3StackFree(db, pSubParse);
return pPrg;
diff --git a/src/update.c b/src/update.c
index d355d7153..3e42461cd 100644
--- a/src/update.c
+++ b/src/update.c
@@ -101,6 +101,7 @@ void sqlite3Update(
Index *pIdx; /* For looping over indices */
Index *pPk; /* The PRIMARY KEY index for WITHOUT ROWID tables */
int nIdx; /* Number of indices that need updating */
+ int iBaseCur; /* Base cursor number */
int iDataCur; /* Cursor for the canonical data btree */
int iIdxCur; /* Cursor for the first index */
sqlite3 *db; /* The database structure */
@@ -108,11 +109,11 @@ void sqlite3Update(
int *aXRef = 0; /* aXRef[i] is the index in pChanges->a[] of the
** an expression for the i-th column of the table.
** aXRef[i]==-1 if the i-th column is not changed. */
+ u8 *aToOpen; /* 1 for tables and indices to be opened */
u8 chngPk; /* PRIMARY KEY changed in a WITHOUT ROWID table */
u8 chngRowid; /* Rowid changed in a normal table */
u8 chngKey; /* Either chngPk or chngRowid */
Expr *pRowidExpr = 0; /* Expression defining the new record number */
- int openAll = 0; /* True if all indices need to be opened */
AuthContext sContext; /* The authorization context */
NameContext sNC; /* The name-context to resolve expressions in */
int iDb; /* Database containing the table being updated */
@@ -176,16 +177,13 @@ void sqlite3Update(
if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
goto update_cleanup;
}
- aXRef = sqlite3DbMallocRaw(db, sizeof(int) * pTab->nCol );
- if( aXRef==0 ) goto update_cleanup;
- for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
/* Allocate a cursors for the main database table and for all indices.
** The index cursors might not be used, but if they are used they
** need to occur right after the database cursor. So go ahead and
** allocate enough space, just in case.
*/
- pTabList->a[0].iCursor = iDataCur = pParse->nTab++;
+ pTabList->a[0].iCursor = iBaseCur = iDataCur = pParse->nTab++;
iIdxCur = iDataCur+1;
pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){
@@ -196,6 +194,17 @@ void sqlite3Update(
pParse->nTab++;
}
+ /* Allocate space for aXRef[], aRegIdx[], and aToOpen[].
+ ** Initialize aXRef[] and aToOpen[] to their default values.
+ */
+ aXRef = sqlite3DbMallocRaw(db, sizeof(int) * (pTab->nCol+nIdx) + nIdx+2 );
+ if( aXRef==0 ) goto update_cleanup;
+ aRegIdx = aXRef+pTab->nCol;
+ aToOpen = (u8*)(aRegIdx+nIdx);
+ memset(aToOpen, 1, nIdx+1);
+ aToOpen[nIdx+1] = 0;
+ for(i=0; i<pTab->nCol; i++) aXRef[i] = -1;
+
/* Initialize the name-context */
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pParse;
@@ -254,17 +263,17 @@ void sqlite3Update(
assert( chngPk==0 || chngPk==1 );
chngKey = chngRowid + chngPk;
+ /* The SET expressions are not actually used inside the WHERE loop.
+ ** So reset the colUsed mask
+ */
+ pTabList->a[0].colUsed = 0;
+
hasFK = sqlite3FkRequired(pParse, pTab, aXRef, chngKey);
- /* Allocate memory for the array aRegIdx[]. There is one entry in the
- ** array for each index associated with table being updated. Fill in
- ** the value with a register number for indices that are to be used
- ** and with zero for unused indices.
+ /* There is one entry in the aRegIdx[] array for each index on the table
+ ** being updated. Fill in aRegIdx[] with a register number that will hold
+ ** the key for accessing each index.
*/
- if( nIdx>0 ){
- aRegIdx = sqlite3DbMallocRaw(db, sizeof(Index*) * nIdx );
- if( aRegIdx==0 ) goto update_cleanup;
- }
for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
int reg;
if( chngKey || hasFK || pIdx->pPartIdxWhere || pIdx==pPk ){
@@ -278,6 +287,7 @@ void sqlite3Update(
}
}
}
+ if( reg==0 ) aToOpen[j+1] = 0;
aRegIdx[j] = reg;
}
@@ -401,42 +411,30 @@ void sqlite3Update(
** action, then we need to open all indices because we might need
** to be deleting some records.
*/
- if( !okOnePass && HasRowid(pTab) ){
- sqlite3OpenTable(pParse, iDataCur, iDb, pTab, OP_OpenWrite);
- }
- sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName);
if( onError==OE_Replace ){
- openAll = 1;
+ memset(aToOpen, 1, nIdx+1);
}else{
- openAll = 0;
for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->onError==OE_Replace ){
- openAll = 1;
+ memset(aToOpen, 1, nIdx+1);
break;
}
}
}
- for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
- int iThisCur = iIdxCur+i;
- assert( aRegIdx );
- if( (openAll || aRegIdx[i]>0)
- && iThisCur!=aiCurOnePass[1]
- ){
- assert( iThisCur!=aiCurOnePass[0] );
- sqlite3VdbeAddOp3(v, OP_OpenWrite, iThisCur, pIdx->tnum, iDb);
- sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
- assert( pParse->nTab>iThisCur );
- VdbeComment((v, "%s", pIdx->zName));
- if( okOnePass && pPk && iThisCur==iDataCur ){
- sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak,
- regKey, nKey);
- }
- }
+ if( okOnePass ){
+ if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0;
+ if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0;
}
+ sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iBaseCur, aToOpen,
+ 0, 0);
}
/* Top of the update loop */
if( okOnePass ){
+ if( aToOpen[iDataCur-iBaseCur] ){
+ assert( pPk!=0 );
+ sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelBreak, regKey, nKey);
+ }
labelContinue = labelBreak;
sqlite3VdbeAddOp2(v, OP_IsNull, pPk ? regKey : regOldRowid, labelBreak);
}else if( pPk ){
@@ -642,7 +640,7 @@ void sqlite3Update(
/* Close all tables */
for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
assert( aRegIdx );
- if( openAll || aRegIdx[i]>0 ){
+ if( aToOpen[i+1] ){
sqlite3VdbeAddOp2(v, OP_Close, iIdxCur+i, 0);
}
}
@@ -669,8 +667,7 @@ void sqlite3Update(
update_cleanup:
sqlite3AuthContextPop(&sContext);
- sqlite3DbFree(db, aRegIdx);
- sqlite3DbFree(db, aXRef);
+ sqlite3DbFree(db, aXRef); /* Also frees aRegIdx[] and aToOpen[] */
sqlite3SrcListDelete(db, pTabList);
sqlite3ExprListDelete(db, pChanges);
sqlite3ExprDelete(db, pWhere);
diff --git a/src/util.c b/src/util.c
index 50ffd9865..5aa8af68d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -512,7 +512,7 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
u = u*10 + c - '0';
}
if( u>LARGEST_INT64 ){
- *pNum = SMALLEST_INT64;
+ *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
}else if( neg ){
*pNum = -(i64)u;
}else{
@@ -543,7 +543,6 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
/* zNum is exactly 9223372036854775808. Fits if negative. The
** special case 2 overflow if positive */
assert( u-1==LARGEST_INT64 );
- assert( (*pNum)==SMALLEST_INT64 );
return neg ? 0 : 2;
}
}
diff --git a/src/vdbe.c b/src/vdbe.c
index b47e00b68..765d5eb22 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -222,9 +222,8 @@ static VdbeCursor *allocateCursor(
int nByte;
VdbeCursor *pCx = 0;
nByte =
- ROUND8(sizeof(VdbeCursor)) +
- (isBtreeCursor?sqlite3BtreeCursorSize():0) +
- 2*nField*sizeof(u32);
+ ROUND8(sizeof(VdbeCursor)) + 2*sizeof(u32)*nField +
+ (isBtreeCursor?sqlite3BtreeCursorSize():0);
assert( iCur<p->nCursor );
if( p->apCsr[iCur] ){
@@ -236,12 +235,9 @@ static VdbeCursor *allocateCursor(
memset(pCx, 0, sizeof(VdbeCursor));
pCx->iDb = iDb;
pCx->nField = nField;
- if( nField ){
- pCx->aType = (u32 *)&pMem->z[ROUND8(sizeof(VdbeCursor))];
- }
if( isBtreeCursor ){
pCx->pCursor = (BtCursor*)
- &pMem->z[ROUND8(sizeof(VdbeCursor))+2*nField*sizeof(u32)];
+ &pMem->z[ROUND8(sizeof(VdbeCursor))+2*sizeof(u32)*nField];
sqlite3BtreeCursorZero(pCx->pCursor);
}
}
@@ -1095,15 +1091,15 @@ case OP_Move: {
int p1; /* Register to copy from */
int p2; /* Register to copy to */
- n = pOp->p3 + 1;
+ n = pOp->p3;
p1 = pOp->p1;
p2 = pOp->p2;
- assert( n>0 && p1>0 && p2>0 );
+ assert( n>=0 && p1>0 && p2>0 );
assert( p1+n<=p2 || p2+n<=p1 );
pIn1 = &aMem[p1];
pOut = &aMem[p2];
- while( n-- ){
+ do{
assert( pOut<=&aMem[(p->nMem-p->nCursor)] );
assert( pIn1<=&aMem[(p->nMem-p->nCursor)] );
assert( memIsValid(pIn1) );
@@ -1120,7 +1116,7 @@ case OP_Move: {
REGISTER_TRACE(p2++, pOut);
pIn1++;
pOut++;
- }
+ }while( n-- );
break;
}
@@ -1332,7 +1328,7 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
** If either input is NULL, the result is NULL.
*/
/* Opcode: Divide P1 P2 P3 * *
-** Synopsis: r[P3]=r[P1]/r[P2]
+** Synopsis: r[P3]=r[P2]/r[P1]
**
** Divide the value in register P1 by the value in register P2
** and store the result in register P3 (P3=P2/P1). If the value in
@@ -1340,11 +1336,11 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */
** NULL, the result is NULL.
*/
/* Opcode: Remainder P1 P2 P3 * *
-** Synopsis: r[P3]=r[P1]%r[P2]
+** Synopsis: r[P3]=r[P2]%r[P1]
**
-** Compute the remainder after integer division of the value in
-** register P1 by the value in register P2 and store the result in P3.
-** If the value in register P2 is zero the result is NULL.
+** Compute the remainder after integer register P2 is divided by
+** register P1 and store the result in register P3.
+** If the value in register P1 is zero the result is NULL.
** If either operand is NULL, the result is NULL.
*/
case OP_Add: /* same as TK_PLUS, in1, in2, out3 */
@@ -1501,10 +1497,6 @@ case OP_Function: {
assert( pOp->p4type==P4_FUNCDEF );
ctx.pFunc = pOp->p4.pFunc;
- ctx.s.flags = MEM_Null;
- ctx.s.db = db;
- ctx.s.xDel = 0;
- ctx.s.zMalloc = 0;
ctx.iOp = pc;
ctx.pVdbe = p;
@@ -1512,7 +1504,10 @@ case OP_Function: {
** the pointer to ctx.s so in case the user-function can use
** the already allocated buffer instead of allocating a new one.
*/
- sqlite3VdbeMemMove(&ctx.s, pOut);
+ memcpy(&ctx.s, pOut, sizeof(Mem));
+ pOut->flags = MEM_Null;
+ pOut->xDel = 0;
+ pOut->zMalloc = 0;
MemSetTypeFlag(&ctx.s, MEM_Null);
ctx.fErrorOrAux = 0;
@@ -1547,7 +1542,8 @@ case OP_Function: {
/* Copy the result of the function into register P3 */
sqlite3VdbeChangeEncoding(&ctx.s, encoding);
- sqlite3VdbeMemMove(pOut, &ctx.s);
+ assert( pOut->flags==MEM_Null );
+ memcpy(pOut, &ctx.s, sizeof(Mem));
if( sqlite3VdbeMemTooBig(pOut) ){
goto too_big;
}
@@ -1672,17 +1668,19 @@ case OP_AddImm: { /* in1 */
*/
case OP_MustBeInt: { /* jump, in1 */
pIn1 = &aMem[pOp->p1];
- applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
if( (pIn1->flags & MEM_Int)==0 ){
- if( pOp->p2==0 ){
- rc = SQLITE_MISMATCH;
- goto abort_due_to_error;
- }else{
- pc = pOp->p2 - 1;
+ applyAffinity(pIn1, SQLITE_AFF_NUMERIC, encoding);
+ if( (pIn1->flags & MEM_Int)==0 ){
+ if( pOp->p2==0 ){
+ rc = SQLITE_MISMATCH;
+ goto abort_due_to_error;
+ }else{
+ pc = pOp->p2 - 1;
+ break;
+ }
}
- }else{
- MemSetTypeFlag(pIn1, MEM_Int);
}
+ MemSetTypeFlag(pIn1, MEM_Int);
break;
}
@@ -1807,7 +1805,7 @@ case OP_ToReal: { /* same as TK_TO_REAL, in1 */
#endif /* !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_FLOATING_POINT) */
/* Opcode: Lt P1 P2 P3 P4 P5
-** Synopsis: if r[P1]<r[P3] goto P3
+** Synopsis: if r[P1]<r[P3] goto P2
**
** Compare the values in register P1 and P3. If reg(P3)<reg(P1) then
** jump to address P2.
@@ -2261,151 +2259,103 @@ case OP_NotNull: { /* same as TK_NOTNULL, jump, in1 */
** skipped for length() and all content loading can be skipped for typeof().
*/
case OP_Column: {
- u32 payloadSize; /* Number of bytes in the record */
i64 payloadSize64; /* Number of bytes in the record */
- int p1; /* P1 value of the opcode */
int p2; /* column number to retrieve */
VdbeCursor *pC; /* The VDBE cursor */
- char *zRec; /* Pointer to complete record-data */
BtCursor *pCrsr; /* The BTree cursor */
u32 *aType; /* aType[i] holds the numeric type of the i-th column */
u32 *aOffset; /* aOffset[i] is offset to start of data for i-th column */
- int nField; /* number of fields in the record */
int len; /* The length of the serialized data for the column */
int i; /* Loop counter */
- char *zData; /* Part of the record being decoded */
Mem *pDest; /* Where to write the extracted value */
Mem sMem; /* For storing the record being decoded */
- u8 *zIdx; /* Index into header */
- u8 *zEndHdr; /* Pointer to first byte after the header */
+ const u8 *zData; /* Part of the record being decoded */
+ const u8 *zHdr; /* Next unparsed byte of the header */
+ const u8 *zEndHdr; /* Pointer to first byte after the header */
u32 offset; /* Offset into the data */
u32 szField; /* Number of bytes in the content of a field */
- int szHdr; /* Size of the header size field at start of record */
- int avail; /* Number of bytes of available data */
+ u32 avail; /* Number of bytes of available data */
u32 t; /* A type code from the record header */
Mem *pReg; /* PseudoTable input register */
-
- p1 = pOp->p1;
p2 = pOp->p2;
- pC = 0;
- memset(&sMem, 0, sizeof(sMem));
- assert( p1<p->nCursor );
assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) );
pDest = &aMem[pOp->p3];
memAboutToChange(p, pDest);
- zRec = 0;
-
- /* This block sets the variable payloadSize to be the total number of
- ** bytes in the record.
- **
- ** zRec is set to be the complete text of the record if it is available.
- ** The complete record text is always available for pseudo-tables
- ** If the record is stored in a cursor, the complete record text
- ** might be available in the pC->aRow cache. Or it might not be.
- ** If the data is unavailable, zRec is set to NULL.
- **
- ** We also compute the number of columns in the record. For cursors,
- ** the number of columns is stored in the VdbeCursor.nField element.
- */
- pC = p->apCsr[p1];
+ assert( pOp->p1>=0 && pOp->p1<p->nCursor );
+ pC = p->apCsr[pOp->p1];
assert( pC!=0 );
+ assert( p2<pC->nField );
+ aType = pC->aType;
+ aOffset = aType + pC->nField;
#ifndef SQLITE_OMIT_VIRTUALTABLE
- assert( pC->pVtabCursor==0 );
+ assert( pC->pVtabCursor==0 ); /* OP_Column never called on virtual table */
#endif
pCrsr = pC->pCursor;
- if( pCrsr!=0 ){
- /* The record is stored in a B-Tree */
- rc = sqlite3VdbeCursorMoveto(pC);
- if( rc ) goto abort_due_to_error;
- if( pC->nullRow ){
- payloadSize = 0;
- }else if( pC->cacheStatus==p->cacheCtr ){
- payloadSize = pC->payloadSize;
- zRec = (char*)pC->aRow;
- }else if( pC->isIndex ){
- assert( sqlite3BtreeCursorIsValid(pCrsr) );
- VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
- assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
- /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
- ** payload size, so it is impossible for payloadSize64 to be
- ** larger than 32 bits. */
- assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
- payloadSize = (u32)payloadSize64;
- }else{
- assert( sqlite3BtreeCursorIsValid(pCrsr) );
- VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &payloadSize);
- assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
- }
- }else{
- assert( pC->pseudoTableReg>0 );
- pReg = &aMem[pC->pseudoTableReg];
- if( pC->multiPseudo ){
- sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
- Deephemeralize(pDest);
- goto op_column_out;
- }
- assert( pReg->flags & MEM_Blob );
- assert( memIsValid(pReg) );
- payloadSize = pReg->n;
- zRec = pReg->z;
- pC->cacheStatus = (pOp->p5&OPFLAG_CLEARCACHE) ? CACHE_STALE : p->cacheCtr;
- assert( payloadSize==0 || zRec!=0 );
- }
-
- /* If payloadSize is 0, then just store a NULL. This can happen because of
- ** nullRow or because of a corrupt database. */
- if( payloadSize==0 ){
- MemSetTypeFlag(pDest, MEM_Null);
- goto op_column_out;
- }
- assert( db->aLimit[SQLITE_LIMIT_LENGTH]>=0 );
- if( payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
- goto too_big;
- }
+ assert( pCrsr!=0 || pC->pseudoTableReg>0 ); /* pCrsr NULL on PseudoTables */
+ assert( pCrsr!=0 || pC->nullRow ); /* pC->nullRow on PseudoTables */
- nField = pC->nField;
- assert( p2<nField );
-
- /* Read and parse the table header. Store the results of the parse
- ** into the record header cache fields of the cursor.
- */
- aType = pC->aType;
- if( pC->cacheStatus==p->cacheCtr ){
- aOffset = pC->aOffset;
- }else{
- assert(aType);
- avail = 0;
- pC->aOffset = aOffset = &aType[nField];
- pC->payloadSize = payloadSize;
- pC->cacheStatus = p->cacheCtr;
-
- /* Figure out how many bytes are in the header */
- if( zRec ){
- zData = zRec;
+ /* If the cursor cache is stale, bring it up-to-date */
+ rc = sqlite3VdbeCursorMoveto(pC);
+ if( rc ) goto abort_due_to_error;
+ if( pC->cacheStatus!=p->cacheCtr || (pOp->p5&OPFLAG_CLEARCACHE)!=0 ){
+ if( pC->nullRow ){
+ if( pCrsr==0 ){
+ assert( pC->pseudoTableReg>0 );
+ pReg = &aMem[pC->pseudoTableReg];
+ if( pC->multiPseudo ){
+ sqlite3VdbeMemShallowCopy(pDest, pReg+p2, MEM_Ephem);
+ Deephemeralize(pDest);
+ goto op_column_out;
+ }
+ assert( pReg->flags & MEM_Blob );
+ assert( memIsValid(pReg) );
+ pC->payloadSize = pC->szRow = avail = pReg->n;
+ pC->aRow = (u8*)pReg->z;
+ }else{
+ MemSetTypeFlag(pDest, MEM_Null);
+ goto op_column_out;
+ }
}else{
- if( pC->isIndex ){
- zData = (char*)sqlite3BtreeKeyFetch(pCrsr, &avail);
+ assert( pCrsr );
+ if( pC->isTable==0 ){
+ assert( sqlite3BtreeCursorIsValid(pCrsr) );
+ VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &payloadSize64);
+ assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
+ /* sqlite3BtreeParseCellPtr() uses getVarint32() to extract the
+ ** payload size, so it is impossible for payloadSize64 to be
+ ** larger than 32 bits. */
+ assert( (payloadSize64 & SQLITE_MAX_U32)==(u64)payloadSize64 );
+ pC->aRow = sqlite3BtreeKeyFetch(pCrsr, &avail);
+ pC->payloadSize = (u32)payloadSize64;
}else{
- zData = (char*)sqlite3BtreeDataFetch(pCrsr, &avail);
+ assert( sqlite3BtreeCursorIsValid(pCrsr) );
+ VVA_ONLY(rc =) sqlite3BtreeDataSize(pCrsr, &pC->payloadSize);
+ assert( rc==SQLITE_OK ); /* DataSize() cannot fail */
+ pC->aRow = sqlite3BtreeDataFetch(pCrsr, &avail);
}
- /* If KeyFetch()/DataFetch() managed to get the entire payload,
- ** save the payload in the pC->aRow cache. That will save us from
- ** having to make additional calls to fetch the content portion of
- ** the record.
- */
- assert( avail>=0 );
- if( payloadSize <= (u32)avail ){
- zRec = zData;
- pC->aRow = (u8*)zData;
+ assert( avail<=65536 ); /* Maximum page size is 64KiB */
+ if( pC->payloadSize <= (u32)avail ){
+ pC->szRow = pC->payloadSize;
}else{
- pC->aRow = 0;
+ pC->szRow = avail;
}
+ if( pC->payloadSize > (u32)db->aLimit[SQLITE_LIMIT_LENGTH] ){
+ goto too_big;
+ }
+ }
+ pC->cacheStatus = p->cacheCtr;
+ pC->iHdrOffset = getVarint32(pC->aRow, offset);
+ pC->nHdrParsed = 0;
+ aOffset[0] = offset;
+ if( avail<offset ){
+ /* pC->aRow does not have to hold the entire row, but it does at least
+ ** need to cover the header of the record. If pC->aRow does not contain
+ ** the complete header, then set it to zero, forcing the header to be
+ ** dynamically allocated. */
+ pC->aRow = 0;
+ pC->szRow = 0;
}
- /* The following assert is true in all cases except when
- ** the database file has been corrupted externally.
- ** assert( zRec!=0 || avail>=payloadSize || avail>=9 ); */
- szHdr = getVarint32((u8*)zData, offset);
/* Make sure a corrupt database has not given us an oversize header.
** Do this now to avoid an oversize memory allocation.
@@ -2416,155 +2366,148 @@ case OP_Column: {
** 3-byte type for each of the maximum of 32768 columns plus three
** extra bytes for the header length itself. 32768*3 + 3 = 98307.
*/
- if( offset > 98307 ){
+ if( offset > 98307 || offset > pC->payloadSize ){
rc = SQLITE_CORRUPT_BKPT;
- goto op_column_out;
+ goto op_column_error;
}
+ }
- /* Compute in len the number of bytes of data we need to read in order
- ** to get nField type values. offset is an upper bound on this. But
- ** nField might be significantly less than the true number of columns
- ** in the table, and in that case, 5*nField+3 might be smaller than offset.
- ** We want to minimize len in order to limit the size of the memory
- ** allocation, especially if a corrupt database file has caused offset
- ** to be oversized. Offset is limited to 98307 above. But 98307 might
- ** still exceed Robson memory allocation limits on some configurations.
- ** On systems that cannot tolerate large memory allocations, nField*5+3
- ** will likely be much smaller since nField will likely be less than
- ** 20 or so. This insures that Robson memory allocation limits are
- ** not exceeded even for corrupt database files.
- */
- len = nField*5 + 3;
- if( len > (int)offset ) len = (int)offset;
-
- /* The KeyFetch() or DataFetch() above are fast and will get the entire
- ** record header in most cases. But they will fail to get the complete
- ** record header if the record header does not fit on a single page
- ** in the B-Tree. When that happens, use sqlite3VdbeMemFromBtree() to
- ** acquire the complete header text.
+ /* Make sure at least the first p2+1 entries of the header have been
+ ** parsed and valid information is in aOffset[] and aType[].
+ */
+ if( pC->nHdrParsed<=p2 ){
+ /* If there is more header available for parsing in the record, try
+ ** to extract additional fields up through the p2+1-th field
*/
- if( !zRec && avail<len ){
- sMem.flags = 0;
- sMem.db = 0;
- rc = sqlite3VdbeMemFromBtree(pCrsr, 0, len, pC->isIndex, &sMem);
- if( rc!=SQLITE_OK ){
- goto op_column_out;
+ if( pC->iHdrOffset<aOffset[0] ){
+ /* Make sure zData points to enough of the record to cover the header. */
+ if( pC->aRow==0 ){
+ memset(&sMem, 0, sizeof(sMem));
+ rc = sqlite3VdbeMemFromBtree(pCrsr, 0, aOffset[0],
+ !pC->isTable, &sMem);
+ if( rc!=SQLITE_OK ){
+ goto op_column_error;
+ }
+ zData = (u8*)sMem.z;
+ }else{
+ zData = pC->aRow;
}
- zData = sMem.z;
- }
- zEndHdr = (u8 *)&zData[len];
- zIdx = (u8 *)&zData[szHdr];
-
- /* Scan the header and use it to fill in the aType[] and aOffset[]
- ** arrays. aType[i] will contain the type integer for the i-th
- ** column and aOffset[i] will contain the offset from the beginning
- ** of the record to the start of the data for the i-th column
- */
- for(i=0; i<nField; i++){
- if( zIdx<zEndHdr ){
- aOffset[i] = offset;
- if( zIdx[0]<0x80 ){
- t = zIdx[0];
- zIdx++;
+
+ /* Fill in aType[i] and aOffset[i] values through the p2-th field. */
+ i = pC->nHdrParsed;
+ offset = aOffset[i];
+ zHdr = zData + pC->iHdrOffset;
+ zEndHdr = zData + aOffset[0];
+ assert( i<=p2 && zHdr<zEndHdr );
+ do{
+ if( zHdr[0]<0x80 ){
+ t = zHdr[0];
+ zHdr++;
}else{
- zIdx += sqlite3GetVarint32(zIdx, &t);
+ zHdr += sqlite3GetVarint32(zHdr, &t);
}
aType[i] = t;
szField = sqlite3VdbeSerialTypeLen(t);
offset += szField;
if( offset<szField ){ /* True if offset overflows */
- zIdx = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
+ zHdr = &zEndHdr[1]; /* Forces SQLITE_CORRUPT return below */
break;
}
- }else{
- /* If i is less that nField, then there are fewer fields in this
- ** record than SetNumColumns indicated there are columns in the
- ** table. Set the offset for any extra columns not present in
- ** the record to 0. This tells code below to store the default value
- ** for the column instead of deserializing a value from the record.
- */
- aOffset[i] = 0;
+ i++;
+ aOffset[i] = offset;
+ }while( i<=p2 && zHdr<zEndHdr );
+ pC->nHdrParsed = i;
+ pC->iHdrOffset = (u32)(zHdr - zData);
+ if( pC->aRow==0 ){
+ sqlite3VdbeMemRelease(&sMem);
+ sMem.flags = MEM_Null;
+ }
+
+ /* If we have read more header data than was contained in the header,
+ ** or if the end of the last field appears to be past the end of the
+ ** record, or if the end of the last field appears to be before the end
+ ** of the record (when all fields present), then we must be dealing
+ ** with a corrupt database.
+ */
+ if( (zHdr > zEndHdr)
+ || (offset > pC->payloadSize)
+ || (zHdr==zEndHdr && offset!=pC->payloadSize)
+ ){
+ rc = SQLITE_CORRUPT_BKPT;
+ goto op_column_error;
}
}
- sqlite3VdbeMemRelease(&sMem);
- sMem.flags = MEM_Null;
-
- /* If we have read more header data than was contained in the header,
- ** or if the end of the last field appears to be past the end of the
- ** record, or if the end of the last field appears to be before the end
- ** of the record (when all fields present), then we must be dealing
- ** with a corrupt database.
+
+ /* If after trying to extra new entries from the header, nHdrParsed is
+ ** still not up to p2, that means that the record has fewer than p2
+ ** columns. So the result will be either the default value or a NULL.
*/
- if( (zIdx > zEndHdr) || (offset > payloadSize)
- || (zIdx==zEndHdr && offset!=payloadSize) ){
- rc = SQLITE_CORRUPT_BKPT;
+ if( pC->nHdrParsed<=p2 ){
+ if( pOp->p4type==P4_MEM ){
+ sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
+ }else{
+ MemSetTypeFlag(pDest, MEM_Null);
+ }
goto op_column_out;
}
}
- /* Get the column information. If aOffset[p2] is non-zero, then
- ** deserialize the value from the record. If aOffset[p2] is zero,
- ** then there are not enough fields in the record to satisfy the
- ** request. In this case, set the value NULL or to P4 if P4 is
- ** a pointer to a Mem object.
+ /* Extract the content for the p2+1-th column. Control can only
+ ** reach this point if aOffset[p2], aOffset[p2+1], and aType[p2] are
+ ** all valid.
*/
- if( aOffset[p2] ){
- assert( rc==SQLITE_OK );
- if( zRec ){
- /* This is the common case where the whole row fits on a single page */
- VdbeMemRelease(pDest);
- sqlite3VdbeSerialGet((u8 *)&zRec[aOffset[p2]], aType[p2], pDest);
+ assert( p2<pC->nHdrParsed );
+ assert( rc==SQLITE_OK );
+ if( pC->szRow>=aOffset[p2+1] ){
+ /* This is the common case where the desired content fits on the original
+ ** page - where the content is not on an overflow page */
+ VdbeMemRelease(pDest);
+ sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], aType[p2], pDest);
+ }else{
+ /* This branch happens only when content is on overflow pages */
+ t = aType[p2];
+ if( ((pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
+ && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0))
+ || (len = sqlite3VdbeSerialTypeLen(t))==0
+ ){
+ /* Content is irrelevant for the typeof() function and for
+ ** the length(X) function if X is a blob. So we might as well use
+ ** bogus content rather than reading content from disk. NULL works
+ ** for text and blob and whatever is in the payloadSize64 variable
+ ** will work for everything else. Content is also irrelevant if
+ ** the content length is 0. */
+ zData = t<=13 ? (u8*)&payloadSize64 : 0;
+ sMem.zMalloc = 0;
}else{
- /* This branch happens only when the row overflows onto multiple pages */
- t = aType[p2];
- if( (pOp->p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0
- && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)
- ){
- /* Content is irrelevant for the typeof() function and for
- ** the length(X) function if X is a blob. So we might as well use
- ** bogus content rather than reading content from disk. NULL works
- ** for text and blob and whatever is in the payloadSize64 variable
- ** will work for everything else. */
- zData = t<12 ? (char*)&payloadSize64 : 0;
- }else{
- len = sqlite3VdbeSerialTypeLen(t);
- sqlite3VdbeMemMove(&sMem, pDest);
- rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, pC->isIndex,
- &sMem);
- if( rc!=SQLITE_OK ){
- goto op_column_out;
- }
- zData = sMem.z;
+ memset(&sMem, 0, sizeof(sMem));
+ sqlite3VdbeMemMove(&sMem, pDest);
+ rc = sqlite3VdbeMemFromBtree(pCrsr, aOffset[p2], len, !pC->isTable,
+ &sMem);
+ if( rc!=SQLITE_OK ){
+ goto op_column_error;
}
- sqlite3VdbeSerialGet((u8*)zData, t, pDest);
+ zData = (u8*)sMem.z;
}
- pDest->enc = encoding;
- }else{
- if( pOp->p4type==P4_MEM ){
- sqlite3VdbeMemShallowCopy(pDest, pOp->p4.pMem, MEM_Static);
- }else{
- MemSetTypeFlag(pDest, MEM_Null);
+ sqlite3VdbeSerialGet(zData, t, pDest);
+ /* If we dynamically allocated space to hold the data (in the
+ ** sqlite3VdbeMemFromBtree() call above) then transfer control of that
+ ** dynamically allocated space over to the pDest structure.
+ ** This prevents a memory copy. */
+ if( sMem.zMalloc ){
+ assert( sMem.z==sMem.zMalloc );
+ assert( !(pDest->flags & MEM_Dyn) );
+ assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z );
+ pDest->flags &= ~(MEM_Ephem|MEM_Static);
+ pDest->flags |= MEM_Term;
+ pDest->z = sMem.z;
+ pDest->zMalloc = sMem.zMalloc;
}
}
-
- /* If we dynamically allocated space to hold the data (in the
- ** sqlite3VdbeMemFromBtree() call above) then transfer control of that
- ** dynamically allocated space over to the pDest structure.
- ** This prevents a memory copy.
- */
- if( sMem.zMalloc ){
- assert( sMem.z==sMem.zMalloc );
- assert( !(pDest->flags & MEM_Dyn) );
- assert( !(pDest->flags & (MEM_Blob|MEM_Str)) || pDest->z==sMem.z );
- pDest->flags &= ~(MEM_Ephem|MEM_Static);
- pDest->flags |= MEM_Term;
- pDest->z = sMem.z;
- pDest->zMalloc = sMem.zMalloc;
- }
-
- rc = sqlite3VdbeMemMakeWriteable(pDest);
+ pDest->enc = encoding;
op_column_out:
+ rc = sqlite3VdbeMemMakeWriteable(pDest);
+op_column_error:
UPDATE_MAX_BLOBSIZE(pDest);
REGISTER_TRACE(pOp->p3, pDest);
break;
@@ -3320,6 +3263,8 @@ case OP_OpenWrite: {
nField = pOp->p4.i;
}
assert( pOp->p1>=0 );
+ assert( nField>=0 );
+ testcase( nField==0 ); /* Table with INTEGER PRIMARY KEY and nothing else */
pCur = allocateCursor(p, pOp->p1, nField, iDb, 1);
if( pCur==0 ) goto no_mem;
pCur->nullRow = 1;
@@ -3333,12 +3278,11 @@ case OP_OpenWrite: {
** sqlite3BtreeCursor() may return is SQLITE_OK. */
assert( rc==SQLITE_OK );
- /* Set the VdbeCursor.isTable and isIndex variables. Previous versions of
+ /* Set the VdbeCursor.isTable variable. Previous versions of
** SQLite used to check if the root-page flags were sane at this point
** and report database corruption if they were not, but this check has
** since moved into the btree layer. */
pCur->isTable = pOp->p4type!=P4_KEYINFO;
- pCur->isIndex = !pCur->isTable;
break;
}
@@ -3380,6 +3324,7 @@ case OP_OpenEphemeral: {
SQLITE_OPEN_DELETEONCLOSE |
SQLITE_OPEN_TRANSIENT_DB;
assert( pOp->p1>=0 );
+ assert( pOp->p2>=0 );
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
@@ -3412,7 +3357,6 @@ case OP_OpenEphemeral: {
}
}
pCx->isOrdered = (pOp->p5!=BTREE_UNORDERED);
- pCx->isIndex = !pCx->isTable;
break;
}
@@ -3425,12 +3369,13 @@ case OP_OpenEphemeral: {
case OP_SorterOpen: {
VdbeCursor *pCx;
+ assert( pOp->p1>=0 );
+ assert( pOp->p2>=0 );
pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1);
if( pCx==0 ) goto no_mem;
pCx->pKeyInfo = pOp->p4.pKeyInfo;
assert( pCx->pKeyInfo->db==db );
assert( pCx->pKeyInfo->enc==ENC(db) );
- pCx->isSorter = 1;
rc = sqlite3VdbeSorterInit(db, pCx);
break;
}
@@ -3456,12 +3401,12 @@ case OP_OpenPseudo: {
VdbeCursor *pCx;
assert( pOp->p1>=0 );
+ assert( pOp->p3>=0 );
pCx = allocateCursor(p, pOp->p1, pOp->p3, -1, 0);
if( pCx==0 ) goto no_mem;
pCx->nullRow = 1;
pCx->pseudoTableReg = pOp->p2;
pCx->isTable = 1;
- pCx->isIndex = 0;
pCx->multiPseudo = pOp->p5;
break;
}
@@ -3579,7 +3524,9 @@ case OP_SeekGt: { /* jump, in3 */
** point number. */
assert( (pIn3->flags & MEM_Real)!=0 );
- if( iKey==SMALLEST_INT64 && (pIn3->r<(double)iKey || pIn3->r>0) ){
+ if( (iKey==SMALLEST_INT64 && pIn3->r<(double)iKey)
+ || (iKey==LARGEST_INT64 && pIn3->r>(double)iKey)
+ ){
/* The P3 value is too large in magnitude to be expressed as an
** integer. */
res = 1;
@@ -4159,7 +4106,7 @@ case OP_InsertInt: {
sqlite3BtreeSetCachedRowid(pC->pCursor, 0);
rc = sqlite3BtreeInsert(pC->pCursor, 0, iKey,
pData->z, pData->n, nZero,
- pOp->p5 & OPFLAG_APPEND, seekResult
+ (pOp->p5 & OPFLAG_APPEND)!=0, seekResult
);
pC->rowidIsValid = 0;
pC->deferredMoveto = 0;
@@ -4319,7 +4266,7 @@ case OP_SorterData: {
pOut = &aMem[pOp->p2];
pC = p->apCsr[pOp->p1];
- assert( pC->isSorter );
+ assert( isSorter(pC) );
rc = sqlite3VdbeSorterRowkey(pC, pOut);
break;
}
@@ -4359,9 +4306,9 @@ case OP_RowData: {
/* Note that RowKey and RowData are really exactly the same instruction */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
- assert( pC->isSorter==0 );
+ assert( isSorter(pC)==0 );
assert( pC->isTable || pOp->opcode!=OP_RowData );
- assert( pC->isIndex || pOp->opcode==OP_RowData );
+ assert( pC->isTable==0 || pOp->opcode==OP_RowData );
assert( pC!=0 );
assert( pC->nullRow==0 );
assert( pC->pseudoTableReg==0 );
@@ -4378,7 +4325,7 @@ case OP_RowData: {
rc = sqlite3VdbeCursorMoveto(pC);
if( NEVER(rc!=SQLITE_OK) ) goto abort_due_to_error;
- if( pC->isIndex ){
+ if( pC->isTable==0 ){
assert( !pC->isTable );
VVA_ONLY(rc =) sqlite3BtreeKeySize(pCrsr, &n64);
assert( rc==SQLITE_OK ); /* True because of CursorMoveto() call above */
@@ -4398,7 +4345,7 @@ case OP_RowData: {
}
pOut->n = n;
MemSetTypeFlag(pOut, MEM_Blob);
- if( pC->isIndex ){
+ if( pC->isTable==0 ){
rc = sqlite3BtreeKey(pCrsr, 0, n, pOut->z);
}else{
rc = sqlite3BtreeData(pCrsr, 0, n, pOut->z);
@@ -4471,6 +4418,7 @@ case OP_NullRow: {
assert( pC!=0 );
pC->nullRow = 1;
pC->rowidIsValid = 0;
+ pC->cacheStatus = CACHE_STALE;
assert( pC->pCursor || pC->pVtabCursor );
if( pC->pCursor ){
sqlite3BtreeClearCursor(pC->pCursor);
@@ -4546,7 +4494,7 @@ case OP_Rewind: { /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pC->isSorter==(pOp->opcode==OP_SorterSort) );
+ assert( isSorter(pC)==(pOp->opcode==OP_SorterSort) );
res = 1;
if( isSorter(pC) ){
rc = sqlite3VdbeSorterRewind(db, pC, &res);
@@ -4554,7 +4502,6 @@ case OP_Rewind: { /* jump */
pCrsr = pC->pCursor;
assert( pCrsr );
rc = sqlite3BtreeFirst(pCrsr, &res);
- pC->atFirst = res==0 ?1:0;
pC->deferredMoveto = 0;
pC->cacheStatus = CACHE_STALE;
pC->rowidIsValid = 0;
@@ -4574,7 +4521,8 @@ case OP_Rewind: { /* jump */
** to the following instruction. But if the cursor advance was successful,
** jump immediately to P2.
**
-** The P1 cursor must be for a real table, not a pseudo-table.
+** The P1 cursor must be for a real table, not a pseudo-table. P1 must have
+** been opened prior to this opcode or the program will segfault.
**
** P4 is always of type P4_ADVANCE. The function pointer points to
** sqlite3BtreeNext().
@@ -4582,7 +4530,12 @@ case OP_Rewind: { /* jump */
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
**
-** See also: Prev
+** See also: Prev, NextIfOpen
+*/
+/* Opcode: NextIfOpen P1 P2 * * P5
+**
+** This opcode works just like OP_Next except that if cursor P1 is not
+** open it behaves a no-op.
*/
/* Opcode: Prev P1 P2 * * P5
**
@@ -4591,7 +4544,8 @@ case OP_Rewind: { /* jump */
** to the following instruction. But if the cursor backup was successful,
** jump immediately to P2.
**
-** The P1 cursor must be for a real table, not a pseudo-table.
+** The P1 cursor must be for a real table, not a pseudo-table. If P1 is
+** not open then the behavior is undefined.
**
** P4 is always of type P4_ADVANCE. The function pointer points to
** sqlite3BtreePrevious().
@@ -4599,38 +4553,47 @@ case OP_Rewind: { /* jump */
** If P5 is positive and the jump is taken, then event counter
** number P5-1 in the prepared statement is incremented.
*/
-case OP_SorterNext: /* jump */
-case OP_Prev: /* jump */
-case OP_Next: { /* jump */
+/* Opcode: PrevIfOpen P1 P2 * * P5
+**
+** This opcode works just like OP_Prev except that if cursor P1 is not
+** open it behaves a no-op.
+*/
+case OP_SorterNext: { /* jump */
VdbeCursor *pC;
int res;
+ pC = p->apCsr[pOp->p1];
+ assert( isSorter(pC) );
+ rc = sqlite3VdbeSorterNext(db, pC, &res);
+ goto next_tail;
+case OP_PrevIfOpen: /* jump */
+case OP_NextIfOpen: /* jump */
+ if( p->apCsr[pOp->p1]==0 ) break;
+ /* Fall through */
+case OP_Prev: /* jump */
+case OP_Next: /* jump */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
assert( pOp->p5<ArraySize(p->aCounter) );
pC = p->apCsr[pOp->p1];
- if( pC==0 ){
- break; /* See ticket #2273 */
- }
- assert( pC->isSorter==(pOp->opcode==OP_SorterNext) );
- if( isSorter(pC) ){
- assert( pOp->opcode==OP_SorterNext );
- rc = sqlite3VdbeSorterNext(db, pC, &res);
- }else{
- /* res = 1; // Always initialized by the xAdvance() call */
- assert( pC->deferredMoveto==0 );
- assert( pC->pCursor );
- assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
- assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
- rc = pOp->p4.xAdvance(pC->pCursor, &res);
- }
- pC->nullRow = (u8)res;
+ assert( pC!=0 );
+ assert( pC->deferredMoveto==0 );
+ assert( pC->pCursor );
+ assert( pOp->opcode!=OP_Next || pOp->p4.xAdvance==sqlite3BtreeNext );
+ assert( pOp->opcode!=OP_Prev || pOp->p4.xAdvance==sqlite3BtreePrevious );
+ assert( pOp->opcode!=OP_NextIfOpen || pOp->p4.xAdvance==sqlite3BtreeNext );
+ assert( pOp->opcode!=OP_PrevIfOpen || pOp->p4.xAdvance==sqlite3BtreePrevious);
+ rc = pOp->p4.xAdvance(pC->pCursor, &res);
+next_tail:
pC->cacheStatus = CACHE_STALE;
if( res==0 ){
+ pC->nullRow = 0;
pc = pOp->p2 - 1;
p->aCounter[pOp->p5]++;
#ifdef SQLITE_TEST
sqlite3_search_count++;
#endif
+ }else{
+ pC->nullRow = 1;
}
pC->rowidIsValid = 0;
goto check_for_interrupt;
@@ -4659,7 +4622,7 @@ case OP_IdxInsert: { /* in2 */
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
assert( pC!=0 );
- assert( pC->isSorter==(pOp->opcode==OP_SorterInsert) );
+ assert( isSorter(pC)==(pOp->opcode==OP_SorterInsert) );
pIn2 = &aMem[pOp->p2];
assert( pIn2->flags & MEM_Blob );
pCrsr = pC->pCursor;
@@ -5910,7 +5873,6 @@ case OP_VOpen: {
pCur = allocateCursor(p, pOp->p1, 0, -1, 0);
if( pCur ){
pCur->pVtabCursor = pVtabCursor;
- pCur->pModule = pVtabCursor->pVtab->pModule;
}else{
db->mallocFailed = 1;
pModule->xClose(pVtabCursor);
diff --git a/src/vdbeInt.h b/src/vdbeInt.h
index bcd04e9d4..cf1041887 100644
--- a/src/vdbeInt.h
+++ b/src/vdbeInt.h
@@ -36,7 +36,7 @@ typedef struct VdbeOp Op;
/*
** Boolean values
*/
-typedef unsigned char Bool;
+typedef unsigned Bool;
/* Opaque type used by code in vdbesort.c */
typedef struct VdbeSorter VdbeSorter;
@@ -53,6 +53,9 @@ typedef struct AuxData AuxData;
** loop over all entries of the Btree. You can also insert new BTree
** entries or retrieve the key or data from the entry that the cursor
** is currently pointing to.
+**
+** Cursors can also point to virtual tables, sorters, or "pseudo-tables".
+** A pseudo-table is a single-row table implemented by registers.
**
** Every cursor that the virtual machine has open is represented by an
** instance of the following structure.
@@ -61,30 +64,24 @@ struct VdbeCursor {
BtCursor *pCursor; /* The cursor structure of the backend */
Btree *pBt; /* Separate file holding temporary table */
KeyInfo *pKeyInfo; /* Info about index keys needed by index cursors */
- int iDb; /* Index of cursor database in db->aDb[] (or -1) */
+ int seekResult; /* Result of previous sqlite3BtreeMoveto() */
int pseudoTableReg; /* Register holding pseudotable content. */
- int nField; /* Number of fields in the header */
- Bool zeroed; /* True if zeroed out and ready for reuse */
- Bool rowidIsValid; /* True if lastRowid is valid */
- Bool atFirst; /* True if pointing to first entry */
- Bool useRandomRowid; /* Generate new record numbers semi-randomly */
- Bool nullRow; /* True if pointing to a row with no data */
- Bool deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
- Bool isTable; /* True if a table requiring integer keys */
- Bool isIndex; /* True if an index containing keys only - no data */
- Bool isOrdered; /* True if the underlying table is BTREE_UNORDERED */
- Bool isSorter; /* True if a new-style sorter */
- Bool multiPseudo; /* Multi-register pseudo-cursor */
+ i16 nField; /* Number of fields in the header */
+ u16 nHdrParsed; /* Number of header fields parsed so far */
+ i8 iDb; /* Index of cursor database in db->aDb[] (or -1) */
+ u8 nullRow; /* True if pointing to a row with no data */
+ u8 rowidIsValid; /* True if lastRowid is valid */
+ u8 deferredMoveto; /* A call to sqlite3BtreeMoveto() is needed */
+ Bool useRandomRowid:1;/* Generate new record numbers semi-randomly */
+ Bool isTable:1; /* True if a table requiring integer keys */
+ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */
+ Bool multiPseudo:1; /* Multi-register pseudo-cursor */
sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */
- const sqlite3_module *pModule; /* Module for cursor pVtabCursor */
i64 seqCount; /* Sequence counter */
i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */
- i64 lastRowid; /* Last rowid from a Next or NextIdx operation */
+ i64 lastRowid; /* Rowid being deleted by OP_Delete */
VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */
- /* Result of last sqlite3BtreeMoveto() done by an OP_NotExists */
- int seekResult;
-
/* Cached information about the header for the data record that the
** cursor is currently pointing to. Only valid if cacheStatus matches
** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of
@@ -95,10 +92,14 @@ struct VdbeCursor {
** be NULL.
*/
u32 cacheStatus; /* Cache is valid if this matches Vdbe.cacheCtr */
- int payloadSize; /* Total number of bytes in the record */
- u32 *aType; /* Type values for all entries in the record */
- u32 *aOffset; /* Cached offsets to the start of each columns data */
- u8 *aRow; /* Data for the current row, if all on one page */
+ u32 payloadSize; /* Total number of bytes in the record */
+ u32 szRow; /* Byte available in aRow */
+ u32 iHdrOffset; /* Offset to next unparsed byte of the header */
+ const u8 *aRow; /* Data for the current row, if all on one page */
+ u32 aType[1]; /* Type values for all entries in the record */
+ /* 2*nField extra array elements allocated for aType[], beyond the one
+ ** static element declared in the structure. nField total array slots for
+ ** aType[] and nField+1 array slots for aOffset[] */
};
typedef struct VdbeCursor VdbeCursor;
@@ -442,7 +443,7 @@ double sqlite3VdbeRealValue(Mem*);
void sqlite3VdbeIntegerAffinity(Mem*);
int sqlite3VdbeMemRealify(Mem*);
int sqlite3VdbeMemNumerify(Mem*);
-int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*);
+int sqlite3VdbeMemFromBtree(BtCursor*,u32,u32,int,Mem*);
void sqlite3VdbeMemRelease(Mem *p);
void sqlite3VdbeMemReleaseExternal(Mem *p);
#define VdbeMemRelease(X) \
diff --git a/src/vdbeaux.c b/src/vdbeaux.c
index 14c74dd0c..65aacf7e3 100644
--- a/src/vdbeaux.c
+++ b/src/vdbeaux.c
@@ -454,12 +454,14 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
}
#endif
case OP_Next:
+ case OP_NextIfOpen:
case OP_SorterNext: {
pOp->p4.xAdvance = sqlite3BtreeNext;
pOp->p4type = P4_ADVANCE;
break;
}
- case OP_Prev: {
+ case OP_Prev:
+ case OP_PrevIfOpen: {
pOp->p4.xAdvance = sqlite3BtreePrevious;
pOp->p4type = P4_ADVANCE;
break;
@@ -1675,7 +1677,7 @@ void sqlite3VdbeFreeCursor(Vdbe *p, VdbeCursor *pCx){
#ifndef SQLITE_OMIT_VIRTUALTABLE
if( pCx->pVtabCursor ){
sqlite3_vtab_cursor *pVtabCursor = pCx->pVtabCursor;
- const sqlite3_module *pModule = pCx->pModule;
+ const sqlite3_module *pModule = pVtabCursor->pVtab->pModule;
p->inVtabMethod = 1;
pModule->xClose(pVtabCursor);
p->inVtabMethod = 0;
@@ -2659,7 +2661,7 @@ int sqlite3VdbeCursorMoveto(VdbeCursor *p){
#endif
p->deferredMoveto = 0;
p->cacheStatus = CACHE_STALE;
- }else if( ALWAYS(p->pCursor) ){
+ }else if( p->pCursor ){
int hasMoved;
int rc = sqlite3BtreeCursorHasMoved(p->pCursor, &hasMoved);
if( rc ) return rc;
@@ -2967,15 +2969,12 @@ u32 sqlite3VdbeSerialGet(
return 0;
}
default: {
+ static const u16 aFlag[] = { MEM_Blob|MEM_Ephem, MEM_Str|MEM_Ephem };
u32 len = (serial_type-12)/2;
pMem->z = (char *)buf;
pMem->n = len;
pMem->xDel = 0;
- if( serial_type&0x01 ){
- pMem->flags = MEM_Str | MEM_Ephem;
- }else{
- pMem->flags = MEM_Blob | MEM_Ephem;
- }
+ pMem->flags = aFlag[serial_type&1];
return len;
}
}
@@ -3117,7 +3116,8 @@ int sqlite3VdbeRecordCompare(
d1 = szHdr1;
assert( pKeyInfo->nField+pKeyInfo->nXField>=pPKey2->nField );
assert( pKeyInfo->aSortOrder!=0 );
- while( idx1<szHdr1 && i<pPKey2->nField ){
+ assert( idx1<szHdr1 && i<pPKey2->nField );
+ do{
u32 serial_type1;
/* Read the serial types for the next element in each key. */
@@ -3150,7 +3150,7 @@ int sqlite3VdbeRecordCompare(
return rc;
}
i++;
- }
+ }while( idx1<szHdr1 && i<pPKey2->nField );
/* No memory allocation is ever used on mem1. Prove this using
** the following assert(). If the assert() fails, it indicates a
@@ -3208,7 +3208,7 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){
/* Read in the complete content of the index entry */
memset(&m, 0, sizeof(m));
- rc = sqlite3VdbeMemFromBtree(pCur, 0, (int)nCellKey, 1, &m);
+ rc = sqlite3VdbeMemFromBtree(pCur, 0, (u32)nCellKey, 1, &m);
if( rc ){
return rc;
}
@@ -3286,7 +3286,7 @@ int sqlite3VdbeIdxKeyCompare(
return SQLITE_CORRUPT_BKPT;
}
memset(&m, 0, sizeof(m));
- rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (int)nCellKey, 1, &m);
+ rc = sqlite3VdbeMemFromBtree(pC->pCursor, 0, (u32)nCellKey, 1, &m);
if( rc ){
return rc;
}
diff --git a/src/vdbeblob.c b/src/vdbeblob.c
index ee660603e..a1c44ebf3 100644
--- a/src/vdbeblob.c
+++ b/src/vdbeblob.c
@@ -66,7 +66,8 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
rc = sqlite3_step(p->pStmt);
if( rc==SQLITE_ROW ){
- u32 type = v->apCsr[0]->aType[p->iCol];
+ VdbeCursor *pC = v->apCsr[0];
+ u32 type = pC->aType[p->iCol];
if( type<12 ){
zErr = sqlite3MPrintf(p->db, "cannot open value of type %s",
type==0?"null": type==7?"real": "integer"
@@ -75,9 +76,9 @@ static int blobSeekToRow(Incrblob *p, sqlite3_int64 iRow, char **pzErr){
sqlite3_finalize(p->pStmt);
p->pStmt = 0;
}else{
- p->iOffset = v->apCsr[0]->aOffset[p->iCol];
+ p->iOffset = pC->aType[p->iCol + pC->nField];
p->nByte = sqlite3VdbeSerialTypeLen(type);
- p->pCsr = v->apCsr[0]->pCursor;
+ p->pCsr = pC->pCursor;
sqlite3BtreeEnterCursor(p->pCsr);
sqlite3BtreeCacheOverflow(p->pCsr);
sqlite3BtreeLeaveCursor(p->pCsr);
@@ -332,6 +333,7 @@ blob_open_out:
}
sqlite3Error(db, rc, (zErr ? "%s" : 0), zErr);
sqlite3DbFree(db, zErr);
+ sqlite3ParserReset(pParse);
sqlite3StackFree(db, pParse);
rc = sqlite3ApiExit(db, rc);
sqlite3_mutex_leave(db->mutex);
diff --git a/src/vdbemem.c b/src/vdbemem.c
index c4bae54fd..0fe7a3bcb 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -303,15 +303,8 @@ void sqlite3VdbeMemRelease(Mem *p){
/*
** Convert a 64-bit IEEE double into a 64-bit signed integer.
-** If the double is too large, return 0x8000000000000000.
-**
-** Most systems appear to do this simply by assigning
-** variables and without the extra range tests. But
-** there are reports that windows throws an expection
-** if the floating point value is out of range. (See ticket #2880.)
-** Because we do not completely understand the problem, we will
-** take the conservative approach and always do range tests
-** before attempting the conversion.
+** If the double is out of range of a 64-bit signed integer then
+** return the closest available 64-bit signed integer.
*/
static i64 doubleToInt64(double r){
#ifdef SQLITE_OMIT_FLOATING_POINT
@@ -328,14 +321,10 @@ static i64 doubleToInt64(double r){
static const i64 maxInt = LARGEST_INT64;
static const i64 minInt = SMALLEST_INT64;
- if( r<(double)minInt ){
- return minInt;
- }else if( r>(double)maxInt ){
- /* minInt is correct here - not maxInt. It turns out that assigning
- ** a very large positive number to an integer results in a very large
- ** negative integer. This makes no sense, but it is what x86 hardware
- ** does so for compatibility we will do the same in software. */
+ if( r<=(double)minInt ){
return minInt;
+ }else if( r>=(double)maxInt ){
+ return maxInt;
}else{
return (i64)r;
}
@@ -417,17 +406,11 @@ void sqlite3VdbeIntegerAffinity(Mem *pMem){
**
** The second and third terms in the following conditional enforces
** the second condition under the assumption that addition overflow causes
- ** values to wrap around. On x86 hardware, the third term is always
- ** true and could be omitted. But we leave it in because other
- ** architectures might behave differently.
+ ** values to wrap around.
*/
if( pMem->r==(double)pMem->u.i
&& pMem->u.i>SMALLEST_INT64
-#if defined(__i486__) || defined(__x86_64__)
- && ALWAYS(pMem->u.i<LARGEST_INT64)
-#else
&& pMem->u.i<LARGEST_INT64
-#endif
){
pMem->flags |= MEM_Int;
}
@@ -896,13 +879,13 @@ int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){
*/
int sqlite3VdbeMemFromBtree(
BtCursor *pCur, /* Cursor pointing at record to retrieve. */
- int offset, /* Offset from the start of data to return bytes from. */
- int amt, /* Number of bytes to return. */
+ u32 offset, /* Offset from the start of data to return bytes from. */
+ u32 amt, /* Number of bytes to return. */
int key, /* If true, retrieve from the btree key, not data. */
Mem *pMem /* OUT: Return data in this Mem structure. */
){
char *zData; /* Data from the btree layer */
- int available = 0; /* Number of bytes available on the local btree page */
+ u32 available = 0; /* Number of bytes available on the local btree page */
int rc = SQLITE_OK; /* Return code */
assert( sqlite3BtreeCursorIsValid(pCur) );
@@ -917,7 +900,7 @@ int sqlite3VdbeMemFromBtree(
}
assert( zData!=0 );
- if( offset+amt<=available && (pMem->flags&MEM_Dyn)==0 ){
+ if( offset+amt<=available ){
sqlite3VdbeMemRelease(pMem);
pMem->z = &zData[offset];
pMem->flags = MEM_Blob|MEM_Ephem;
@@ -936,7 +919,7 @@ int sqlite3VdbeMemFromBtree(
sqlite3VdbeMemRelease(pMem);
}
}
- pMem->n = amt;
+ pMem->n = (int)amt;
return rc;
}
diff --git a/src/vtab.c b/src/vtab.c
index 195aa68b2..ca0db214c 100644
--- a/src/vtab.c
+++ b/src/vtab.c
@@ -738,6 +738,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){
sqlite3VdbeFinalize(pParse->pVdbe);
}
sqlite3DeleteTable(db, pParse->pNewTable);
+ sqlite3ParserReset(pParse);
sqlite3StackFree(db, pParse);
}
diff --git a/src/where.c b/src/where.c
index c4f25675c..101ca1a7c 100644
--- a/src/where.c
+++ b/src/where.c
@@ -669,9 +669,6 @@ static int isLikeOrGlob(
pRight = pList->a[0].pExpr;
op = pRight->op;
- if( op==TK_REGISTER ){
- op = pRight->op2;
- }
if( op==TK_VARIABLE ){
Vdbe *pReprepare = pParse->pReprepare;
int iCol = pRight->iColumn;
@@ -2409,7 +2406,7 @@ static int codeEqualityTerm(
}else{
pIn->addrInTop = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg);
}
- pIn->eEndLoopOp = bRev ? OP_Prev : OP_Next;
+ pIn->eEndLoopOp = bRev ? OP_PrevIfOpen : OP_NextIfOpen;
sqlite3VdbeAddOp1(v, OP_IsNull, iReg);
}else{
pLevel->u.in.nIn = 0;
@@ -2759,7 +2756,7 @@ static Bitmask codeOneLoopStart(
bRev = (pWInfo->revMask>>iLevel)&1;
omitTable = (pLoop->wsFlags & WHERE_IDX_ONLY)!=0
&& (pWInfo->wctrlFlags & WHERE_FORCE_TABLE)==0;
- VdbeNoopComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
+ VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName));
/* Create labels for the "break" and "continue" instructions
** for the current loop. Jump to addrBrk to break out of a loop.
@@ -2987,7 +2984,6 @@ static Bitmask codeOneLoopStart(
OP_IdxLT /* 2: (end_constraints && bRev) */
};
u16 nEq = pLoop->u.btree.nEq; /* Number of == or IN terms */
- u16 nSkip = pLoop->u.btree.nSkip; /* Number of left index terms to skip */
int isMinQuery = 0; /* If this is an optimized SELECT min(x).. */
int regBase; /* Base register holding constraint values */
int r1; /* Temp register */
@@ -3002,11 +2998,11 @@ static Bitmask codeOneLoopStart(
int nExtraReg = 0; /* Number of extra registers needed */
int op; /* Instruction opcode */
char *zStartAff; /* Affinity for start of range constraint */
- char *zEndAff; /* Affinity for end of range constraint */
+ char cEndAff = 0; /* Affinity for end of range constraint */
pIdx = pLoop->u.btree.pIndex;
iIdxCur = pLevel->iIdxCur;
- assert( nEq>=nSkip );
+ assert( nEq>=pLoop->u.btree.nSkip );
/* If this loop satisfies a sort order (pOrderBy) request that
** was passed to this function to implement a "SELECT min(x) ..."
@@ -3020,7 +3016,7 @@ static Bitmask codeOneLoopStart(
&& (pWInfo->bOBSat!=0)
&& (pIdx->nKeyCol>nEq)
){
- assert( nSkip==0 );
+ assert( pLoop->u.btree.nSkip==0 );
isMinQuery = 1;
nExtraReg = 1;
}
@@ -3043,7 +3039,8 @@ static Bitmask codeOneLoopStart(
** starting at regBase.
*/
regBase = codeAllEqualityTerms(pParse,pLevel,bRev,nExtraReg,&zStartAff);
- zEndAff = sqlite3DbStrDup(db, zStartAff);
+ assert( zStartAff==0 || sqlite3Strlen30(zStartAff)>=nEq );
+ if( zStartAff ) cEndAff = zStartAff[nEq];
addrNxt = pLevel->addrNxt;
/* If we are doing a reverse order scan on an ascending index, or
@@ -3113,23 +3110,15 @@ static Bitmask codeOneLoopStart(
if( (pRangeEnd->wtFlags & TERM_VNULL)==0 ){
sqlite3ExprCodeIsNullJump(v, pRight, regBase+nEq, addrNxt);
}
- if( zEndAff ){
- if( sqlite3CompareAffinity(pRight, zEndAff[nEq])==SQLITE_AFF_NONE){
- /* Since the comparison is to be performed with no conversions
- ** applied to the operands, set the affinity to apply to pRight to
- ** SQLITE_AFF_NONE. */
- zEndAff[nEq] = SQLITE_AFF_NONE;
- }
- if( sqlite3ExprNeedsNoAffinityChange(pRight, zEndAff[nEq]) ){
- zEndAff[nEq] = SQLITE_AFF_NONE;
- }
- }
- codeApplyAffinity(pParse, regBase, nEq+1, zEndAff);
+ if( sqlite3CompareAffinity(pRight, cEndAff)!=SQLITE_AFF_NONE
+ && !sqlite3ExprNeedsNoAffinityChange(pRight, cEndAff)
+ ){
+ codeApplyAffinity(pParse, regBase+nEq, 1, &cEndAff);
+ }
nConstraint++;
testcase( pRangeEnd->wtFlags & TERM_VIRTUAL );
}
sqlite3DbFree(db, zStartAff);
- sqlite3DbFree(db, zEndAff);
/* Top of the loop body */
pLevel->p2 = sqlite3VdbeCurrentAddr(v);
@@ -3154,6 +3143,7 @@ static Bitmask codeOneLoopStart(
if( (pLoop->wsFlags & (WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0
&& (j = pIdx->aiColumn[nEq])>=0
&& pIdx->pTable->aCol[j].notNull==0
+ && (nEq || (pLoop->wsFlags & WHERE_BTM_LIMIT)==0)
){
sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1);
VdbeComment((v, "%s", pIdx->pTable->aCol[j].zName));
@@ -3471,7 +3461,7 @@ static Bitmask codeOneLoopStart(
if( pAlt->wtFlags & (TERM_CODED) ) continue;
testcase( pAlt->eOperator & WO_EQ );
testcase( pAlt->eOperator & WO_IN );
- VdbeNoopComment((v, "begin transitive constraint"));
+ VdbeModuleComment((v, "begin transitive constraint"));
pEAlt = sqlite3StackAllocRaw(db, sizeof(*pEAlt));
if( pEAlt ){
*pEAlt = *pAlt->pExpr;
@@ -3928,10 +3918,15 @@ static int whereLoopAddBtreeIndex(
saved_nOut = pNew->nOut;
pNew->rSetup = 0;
rLogSize = estLog(sqlite3LogEst(pProbe->aiRowEst[0]));
+
+ /* Consider using a skip-scan if there are no WHERE clause constraints
+ ** available for the left-most terms of the index, and if the average
+ ** number of repeats in the left-most terms is at least 50.
+ */
if( pTerm==0
&& saved_nEq==saved_nSkip
&& saved_nEq+1<pProbe->nKeyCol
- && pProbe->aiRowEst[saved_nEq+1]>50
+ && pProbe->aiRowEst[saved_nEq+1]>50 /* TUNING: Minimum for skip-scan */
){
LogEst nIter;
pNew->u.btree.nEq++;
@@ -5427,7 +5422,6 @@ WhereInfo *sqlite3WhereBegin(
*/
initMaskSet(pMaskSet);
whereClauseInit(&pWInfo->sWC, pWInfo);
- sqlite3ExprCodeConstants(pParse, pWhere);
whereSplit(&pWInfo->sWC, pWhere, TK_AND);
sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */
@@ -5742,7 +5736,7 @@ WhereInfo *sqlite3WhereBegin(
}
/* Done. */
- VdbeNoopComment((v, "Begin WHERE-core"));
+ VdbeModuleComment((v, "Begin WHERE-core"));
return pWInfo;
/* Jump here if malloc fails */
@@ -5769,7 +5763,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
/* Generate loop termination code.
*/
- VdbeNoopComment((v, "End WHERE-core"));
+ VdbeModuleComment((v, "End WHERE-core"));
sqlite3ExprCacheClear(pParse);
for(i=pWInfo->nLevel-1; i>=0; i--){
int addr;
@@ -5815,7 +5809,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){
}
sqlite3VdbeJumpHere(v, addr);
}
- VdbeNoopComment((v, "End WHERE-loop%d: %s", i,
+ VdbeModuleComment((v, "End WHERE-loop%d: %s", i,
pWInfo->pTabList->a[pLevel->iFrom].pTab->zName));
}