Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Registerification of the WHERE clause logic. (CVS 4716) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
b3a141b2b0c09bf3c7704deeade290d7 |
User & Date: | drh 2008-01-17 02:36:27.000 |
Original User & Date: | drh 2008-01-17 02:36:28.000 |
Context
2008-01-17
| ||
02:36 | Registerification of the WHERE clause logic. (CVS 4717) (check-in: 5581160f43 user: drh tags: trunk) | |
02:36 | Registerification of the WHERE clause logic. (CVS 4716) (check-in: b3a141b2b0 user: drh tags: trunk) | |
2008-01-16
| ||
18:20 | Use 1<<$x instead of pow(2,$x) in the test suite code. (CVS 4715) (check-in: 3a289b6d28 user: danielk1977 tags: trunk) | |
Changes
Changes to src/analyze.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2005 July 8 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code associated with the ANALYZE command. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2005 July 8 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code associated with the ANALYZE command. ** ** @(#) $Id: analyze.c,v 1.39 2008/01/17 02:36:28 drh Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" /* ** This routine generates code that opens the sqlite_stat1 table on cursor ** iStatCur. |
︙ | ︙ | |||
212 213 214 215 216 217 218 | sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2); sqlite3VdbeAddOp3(v, OP_Add, iMem, iMem+i+1, regTemp); sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1); sqlite3VdbeAddOp3(v, OP_Divide, iMem+i+1, regTemp, regTemp); sqlite3VdbeAddOp1(v, OP_ToInt, regTemp); sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2); } | | | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2); sqlite3VdbeAddOp3(v, OP_Add, iMem, iMem+i+1, regTemp); sqlite3VdbeAddOp2(v, OP_AddImm, regTemp, -1); sqlite3VdbeAddOp3(v, OP_Divide, iMem+i+1, regTemp, regTemp); sqlite3VdbeAddOp1(v, OP_ToInt, regTemp); sqlite3VdbeAddOp3(v, OP_Concat, regTemp, regF2, regF2); } sqlite3VdbeAddOp4(v, OP_MakeRecord, regFields, 3, regRec, "aaa", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeJumpHere(v, addr); } } |
︙ | ︙ |
Changes to src/build.c.
︙ | ︙ | |||
18 19 20 21 22 23 24 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** | | | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | ** CREATE INDEX ** DROP INDEX ** creating ID lists ** BEGIN TRANSACTION ** COMMIT ** ROLLBACK ** ** $Id: build.c,v 1.466 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** This routine is called when a new SQL statement is beginning to ** be parsed. Initialize the pParse structure as needed. |
︙ | ︙ | |||
2211 2212 2213 2214 2215 2216 2217 | /* ** Generate code that will erase and refill index *pIdx. This is ** used to initialize a newly created index or to recompute the ** content of an index in response to a REINDEX command. ** ** if memRootPage is not negative, it means that the index is newly | | | 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 | /* ** Generate code that will erase and refill index *pIdx. This is ** used to initialize a newly created index or to recompute the ** content of an index in response to a REINDEX command. ** ** if memRootPage is not negative, it means that the index is newly ** created. The register specified by memRootPage contains the ** root page number of the index. If memRootPage is negative, then ** the index already exists and must be cleared before being refilled and ** the root page number of the index is taken from pIndex->tnum. */ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ Table *pTab = pIndex->pTable; /* The table that is indexed */ int iTab = pParse->nTab; /* Btree cursor used for pTab */ |
︙ | ︙ | |||
2242 2243 2244 2245 2246 2247 2248 | /* Require a write-lock on the table to perform this operation */ sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); v = sqlite3GetVdbe(pParse); if( v==0 ) return; if( memRootPage>=0 ){ | < | | 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 | /* Require a write-lock on the table to perform this operation */ sqlite3TableLock(pParse, iDb, pTab->tnum, 1, pTab->zName); v = sqlite3GetVdbe(pParse); if( v==0 ) return; if( memRootPage>=0 ){ tnum = memRootPage; }else{ tnum = pIndex->tnum; sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); } pKey = sqlite3IndexKeyinfo(pParse, pIndex); sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, (char *)pKey, P4_KEYINFO_HANDOFF); |
︙ | ︙ | |||
2732 2733 2734 2735 2736 2737 2738 | ** Generate code to make sure the file format number is at least minFormat. ** The generated code will increase the file format number if necessary. */ void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){ Vdbe *v; v = sqlite3GetVdbe(pParse); if( v ){ | > > > | | | | | > > | 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 | ** Generate code to make sure the file format number is at least minFormat. ** The generated code will increase the file format number if necessary. */ void sqlite3MinimumFileFormat(Parse *pParse, int iDb, int minFormat){ Vdbe *v; v = sqlite3GetVdbe(pParse); if( v ){ int r1 = sqlite3GetTempReg(pParse); int r2 = sqlite3GetTempReg(pParse); int j1; sqlite3VdbeAddOp3(v, OP_ReadCookie, iDb, r1, 1); sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeAddOp2(v, OP_Integer, minFormat, r2); j1 = sqlite3VdbeAddOp3(v, OP_Ge, r2, 0, r1); sqlite3VdbeAddOp3(v, OP_SetCookie, iDb, 1, r2); sqlite3VdbeJumpHere(v, j1); sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } } /* ** Fill the Index.aiRowEst[] array with default information - information ** to be used when we have not run the ANALYZE command. ** |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** in order to generate code for DELETE FROM statements. ** ** $Id: delete.c,v 1.158 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" /* ** Look up every table that is named in pSrc. If any table is not found, ** add an error message to pParse->zErrMsg and return NULL. If all tables ** are found, return a pointer to the last table. |
︙ | ︙ | |||
56 57 58 59 60 61 62 | sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); return 1; } #endif return 0; } | < < < < < < < < < < < < < < < < < < | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName); return 1; } #endif return 0; } /* ** Generate code that will open a table for reading. */ void sqlite3OpenTable( Parse *p, /* Generate code into this VDBE */ int iCur, /* The cursor number of the table */ int iDb, /* The database index in sqlite3.aDb[] */ |
︙ | ︙ | |||
515 516 517 518 519 520 521 | if( idx==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_SCopy, regBase+nCol, regBase+j); }else{ sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j); sqlite3ColumnDefault(v, pTab, idx); } } | | | 497 498 499 500 501 502 503 504 505 506 507 508 | if( idx==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_SCopy, regBase+nCol, regBase+j); }else{ sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j); sqlite3ColumnDefault(v, pTab, idx); } } sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol+1, regOut); sqlite3IndexAffinityStr(v, pIdx); sqlite3ReleaseTempRange(pParse, regBase, nCol+1); return regBase; } |
Changes to src/expr.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** ** $Id: expr.c,v 1.346 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** Return the 'affinity' of the expression pExpr if any. ** |
︙ | ︙ | |||
1782 1783 1784 1785 1786 1787 1788 | if( testAddr && !sqlite3ExprIsConstant(pE2) ){ sqlite3VdbeChangeToNoop(v, testAddr-1, 2); testAddr = 0; } /* Evaluate the expression and insert it into the temp table */ sqlite3ExprCode(pParse, pE2, r1); | | | 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 | if( testAddr && !sqlite3ExprIsConstant(pE2) ){ sqlite3VdbeChangeToNoop(v, testAddr-1, 2); testAddr = 0; } /* Evaluate the expression and insert it into the temp table */ sqlite3ExprCode(pParse, pE2, r1); sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2); } sqlite3ReleaseTempReg(pParse, r1); sqlite3ReleaseTempReg(pParse, r2); } sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO); break; |
︙ | ︙ | |||
2242 2243 2244 2245 2246 2247 2248 | j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, r1, 0, 1); j4 = sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, 0, r1); j5 = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, j3); sqlite3VdbeJumpHere(v, j4); }else{ r2 = regFree2 = sqlite3GetTempReg(pParse); | | | 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 | j3 = sqlite3VdbeAddOp3(v, OP_MustBeInt, r1, 0, 1); j4 = sqlite3VdbeAddOp3(v, OP_NotExists, pExpr->iTable, 0, r1); j5 = sqlite3VdbeAddOp0(v, OP_Goto); sqlite3VdbeJumpHere(v, j3); sqlite3VdbeJumpHere(v, j4); }else{ r2 = regFree2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, r1, 1, r2, &affinity, 1); j5 = sqlite3VdbeAddOp3(v, OP_Found, pExpr->iTable, 0, r2); } sqlite3VdbeAddOp2(v, OP_AddImm, target, -1); sqlite3VdbeJumpHere(v, j2); sqlite3VdbeJumpHere(v, j5); break; } |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** ** $Id: insert.c,v 1.224 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" /* ** Set P4 of the most recently inserted opcode to a column affinity ** string for index pIdx. A column affinity string has one character ** for each column in the table, according to the affinity of the column: |
︙ | ︙ | |||
170 171 172 173 174 175 176 177 | int addr; /* Address of the top of the loop */ assert( v ); pParse->nMem++; /* Holds name of table */ memId = ++pParse->nMem; pParse->nMem++; sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead); addr = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addr+8); | > | < | | | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | int addr; /* Address of the top of the loop */ assert( v ); pParse->nMem++; /* Holds name of table */ memId = ++pParse->nMem; pParse->nMem++; sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead); addr = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp4(v, OP_String8, 0, memId-1, 0, pTab->zName, 0); sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addr+8); sqlite3VdbeAddOp3(v, OP_Column, iCur, 0, memId); sqlite3VdbeAddOp3(v, OP_Ne, memId-1, addr+7, memId); sqlite3VdbeChangeP5(v, SQLITE_JUMPIFNULL); sqlite3VdbeAddOp2(v, OP_Rowid, iCur, memId+1); sqlite3VdbeAddOp3(v, OP_Column, iCur, 1, memId); sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+8); sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+2); sqlite3VdbeAddOp2(v, OP_Close, iCur, 0); } return memId; } /* ** Update the maximum rowid for an autoincrement calculation. |
︙ | ︙ | |||
220 221 222 223 224 225 226 | int j1; assert( v ); sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); sqlite3VdbeAddOp2(v, OP_NewRowid, iCur, memId+1); sqlite3VdbeJumpHere(v, j1); | < | | 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | int j1; assert( v ); sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); j1 = sqlite3VdbeAddOp1(v, OP_NotNull, memId+1); sqlite3VdbeAddOp2(v, OP_NewRowid, iCur, memId+1); sqlite3VdbeJumpHere(v, j1); sqlite3VdbeAddOp3(v, OP_MakeRecord, memId-1, 2, memId-1); sqlite3VdbeAddOp3(v, OP_Insert, iCur, memId-1, memId+1); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3VdbeAddOp1(v, OP_Close, iCur); } } #else /* |
︙ | ︙ | |||
521 522 523 524 525 526 527 | */ int regRec, regRowid; srcTab = pParse->nTab++; regRec = sqlite3GetTempReg(pParse); regRowid = sqlite3GetTempReg(pParse); sqlite3VdbeResolveLabel(v, iInsertBlock); | | | 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 | */ int regRec, regRowid; srcTab = pParse->nTab++; regRec = sqlite3GetTempReg(pParse); regRowid = sqlite3GetTempReg(pParse); sqlite3VdbeResolveLabel(v, iInsertBlock); sqlite3VdbeAddOp3(v, OP_MakeRecord, regFromSelect, nColumn, regRec); sqlite3VdbeAddOp2(v, OP_NewRowid, srcTab, regRowid); sqlite3VdbeAddOp3(v, OP_Insert, srcTab, regRec, regRowid); sqlite3VdbeAddOp2(v, OP_Return, 0, 0); sqlite3ReleaseTempReg(pParse, regRec); sqlite3ReleaseTempReg(pParse, regRowid); /* The following code runs first because the GOTO at the very top |
︙ | ︙ | |||
734 735 736 737 738 739 740 | sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i); }else{ assert( pSelect==0 ); /* Otherwise useTempTable is true */ sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i); } } regRec = sqlite3GetTempReg(pParse); | | | 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i); }else{ assert( pSelect==0 ); /* Otherwise useTempTable is true */ sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i); } } regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regCols, pTab->nCol, regRec); /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger, ** do not attempt any conversions before assembling the record. ** If this is a real table, attempt conversions as required by the ** table column affinities. */ if( !isView ){ |
︙ | ︙ | |||
773 774 775 776 777 778 779 | if( keyColumn>=0 ){ if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid); }else if( pSelect ){ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+keyColumn, regRowid); }else{ VdbeOp *pOp; | | < < < | | > | 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 | if( keyColumn>=0 ){ if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid); }else if( pSelect ){ sqlite3VdbeAddOp2(v, OP_SCopy, regFromSelect+keyColumn, regRowid); }else{ VdbeOp *pOp; sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid); pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1); if( pOp && pOp->opcode==OP_Null ){ appendFlag = 1; pOp->opcode = OP_NewRowid; pOp->p1 = baseCur; pOp->p2 = regRowid; pOp->p3 = regAutoinc; } } /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid ** to generate a unique primary key value. */ if( !appendFlag ){ int j1; j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid); sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc); sqlite3VdbeJumpHere(v, j1); sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid); } }else if( IsVirtual(pTab) ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid); }else{ sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc); appendFlag = 1; |
︙ | ︙ | |||
1174 1175 1176 1177 1178 1179 1180 | if( idx==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); }else{ sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i); } } sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); | | | 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 | if( idx==pTab->iPKey ){ sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); }else{ sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i); } } sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i); sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn+1, aRegIdx[iCur]); sqlite3IndexAffinityStr(v, pIdx); sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1); /* Find out what action to take in case there is an indexing conflict */ onError = pIdx->onError; if( onError==OE_None ) continue; /* pIdx is not a UNIQUE index */ if( overrideError!=OE_Default ){ |
︙ | ︙ | |||
1290 1291 1292 1293 1294 1295 1296 | for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} for(i=nIdx-1; i>=0; i--){ if( aRegIdx[i]==0 ) continue; sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]); } regData = regRowid + 1; regRec = sqlite3GetTempReg(pParse); | | | 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 | for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){} for(i=nIdx-1; i>=0; i--){ if( aRegIdx[i]==0 ) continue; sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]); } regData = regRowid + 1; regRec = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regData, pTab->nCol, regRec); sqlite3TableAffinityStr(v, pTab); #ifndef SQLITE_OMIT_TRIGGER if( newIdx>=0 ){ sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRec, regRowid); } #endif if( pParse->nested ){ |
︙ | ︙ |
Changes to src/pragma.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2003 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2003 April 6 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** ** $Id: pragma.c,v 1.167 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* Ignore this whole file if pragmas are disabled */ #if !defined(SQLITE_OMIT_PRAGMA) && !defined(SQLITE_OMIT_PARSER) |
︙ | ︙ | |||
455 456 457 458 459 460 461 | /* When setting the auto_vacuum mode to either "full" or ** "incremental", write the value of meta[6] in the database ** file. Before writing to meta[6], check that meta[3] indicates ** that this really is an auto-vacuum capable database. */ static const VdbeOpList setMeta6[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ | | | | | | 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 | /* When setting the auto_vacuum mode to either "full" or ** "incremental", write the value of meta[6] in the database ** file. Before writing to meta[6], check that meta[3] indicates ** that this really is an auto-vacuum capable database. */ static const VdbeOpList setMeta6[] = { { OP_Transaction, 0, 1, 0}, /* 0 */ { OP_ReadCookie, 0, 1, 3}, /* 1 */ { OP_If, 1, 0, 0}, /* 2 */ { OP_Halt, SQLITE_OK, OE_Abort, 0}, /* 3 */ { OP_Integer, 0, 1, 0}, /* 4 */ { OP_SetCookie, 0, 6, 1}, /* 5 */ }; int iAddr; iAddr = sqlite3VdbeAddOpList(v, ArraySize(setMeta6), setMeta6); sqlite3VdbeChangeP1(v, iAddr, iDb); sqlite3VdbeChangeP1(v, iAddr+1, iDb); sqlite3VdbeChangeP2(v, iAddr+2, iAddr+4); sqlite3VdbeChangeP1(v, iAddr+4, eAuto-1); |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.403 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" /* ** Delete all the content of a Select structure but do not deallocate ** the select structure itself. |
︙ | ︙ | |||
400 401 402 403 404 405 406 | Vdbe *v = pParse->pVdbe; int nExpr = pOrderBy->nExpr; int regBase = sqlite3GetTempRange(pParse, nExpr+2); int regRecord = sqlite3GetTempReg(pParse); sqlite3ExprCodeExprList(pParse, pOrderBy, regBase); sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr); sqlite3VdbeAddOp2(v, OP_Move, regData, regBase+nExpr+1); | | | 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 | Vdbe *v = pParse->pVdbe; int nExpr = pOrderBy->nExpr; int regBase = sqlite3GetTempRange(pParse, nExpr+2); int regRecord = sqlite3GetTempReg(pParse); sqlite3ExprCodeExprList(pParse, pOrderBy, regBase); sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr); sqlite3VdbeAddOp2(v, OP_Move, regData, regBase+nExpr+1); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord); sqlite3VdbeAddOp2(v, OP_IdxInsert, pOrderBy->iECursor, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nExpr+2); if( pSelect->iLimit>=0 ){ int addr1, addr2; int iLimit; if( pSelect->pOffset ){ |
︙ | ︙ | |||
462 463 464 465 466 467 468 | int iMem /* First element */ ){ Vdbe *v; int r1; v = pParse->pVdbe; r1 = sqlite3GetTempReg(pParse); | | | 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 | int iMem /* First element */ ){ Vdbe *v; int r1; v = pParse->pVdbe; r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, N, r1); sqlite3VdbeAddOp3(v, OP_Found, iTab, addrRepeat, r1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iTab, r1); sqlite3ReleaseTempReg(pParse, r1); } /* ** Generate an error message when a SELECT is used within a subexpression |
︙ | ︙ | |||
579 580 581 582 583 584 585 | switch( eDest ){ /* In this mode, write each query result to the key of the temporary ** table iParm. */ #ifndef SQLITE_OMIT_COMPOUND_SELECT case SRT_Union: { | | | | | 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 | switch( eDest ){ /* In this mode, write each query result to the key of the temporary ** table iParm. */ #ifndef SQLITE_OMIT_COMPOUND_SELECT case SRT_Union: { sqlite3VdbeAddOp2(v, OP_MakeRecord, iMem, nColumn); if( aff ){ sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC); } sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0); break; } /* Construct a record from the query result, but instead of ** saving that record, use it as a key to delete elements from ** the temporary table iParm. */ case SRT_Except: { int addr; addr = sqlite3VdbeAddOp2(v, OP_MakeRecord, iMem, nColumn); sqlite3VdbeChangeP4(v, -1, aff, P4_STATIC); sqlite3VdbeAddOp2(v, OP_NotFound, iParm, addr+3); sqlite3VdbeAddOp2(v, OP_Delete, iParm, 0); break; } #endif /* Store the result as data using a unique key. */ case SRT_Table: case SRT_EphemTab: { int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, nColumn, r1); if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p, r1); }else{ int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, r2); sqlite3VdbeAddOp3(v, OP_Insert, iParm, r1, r2); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); |
︙ | ︙ | |||
639 640 641 642 643 644 645 | /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ pushOntoSorter(pParse, pOrderBy, p, iMem); }else{ int r1 = sqlite3GetTempReg(pParse); | | | 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 | /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ pushOntoSorter(pParse, pOrderBy, p, iMem); }else{ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, iMem, 1, r1, &p->affinity, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, r1); sqlite3ReleaseTempReg(pParse, r1); } sqlite3VdbeJumpHere(v, addr2); break; } |
︙ | ︙ | |||
679 680 681 682 683 684 685 | ** case of a subroutine, the subroutine itself is responsible for ** popping the data from the stack. */ case SRT_Subroutine: case SRT_Callback: { if( pOrderBy ){ int r1 = sqlite3GetTempReg(pParse); | | | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | ** case of a subroutine, the subroutine itself is responsible for ** popping the data from the stack. */ case SRT_Subroutine: case SRT_Callback: { if( pOrderBy ){ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, iMem, nColumn, r1); pushOntoSorter(pParse, pOrderBy, p, r1); sqlite3ReleaseTempReg(pParse, r1); }else if( eDest==SRT_Subroutine ){ sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, iMem, nColumn); } |
︙ | ︙ | |||
804 805 806 807 808 809 810 | break; } #ifndef SQLITE_OMIT_SUBQUERY case SRT_Set: { int j1; assert( nColumn==1 ); j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regRow); | | | 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 | break; } #ifndef SQLITE_OMIT_SUBQUERY case SRT_Set: { int j1; assert( nColumn==1 ); j1 = sqlite3VdbeAddOp1(v, OP_IsNull, regRow); sqlite3VdbeAddOp4(v, OP_MakeRecord, regRow, 1, regRow, &p->affinity, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, regRow); sqlite3VdbeJumpHere(v, j1); break; } case SRT_Mem: { assert( nColumn==1 ); sqlite3VdbeAddOp2(v, OP_Move, regRow, iParm); |
︙ | ︙ | |||
3426 3427 3428 3429 3430 3431 3432 | if( pCol->iSorterColumn>=j ){ sqlite3ExprCodeGetColumn(v, pCol->pTab, pCol->iColumn, pCol->iTable, j + regBase); j++; } } regRecord = sqlite3GetTempReg(pParse); | | | 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 | if( pCol->iSorterColumn>=j ){ sqlite3ExprCodeGetColumn(v, pCol->pTab, pCol->iColumn, pCol->iTable, j + regBase); j++; } } regRecord = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nCol, regRecord); sqlite3VdbeAddOp2(v, OP_IdxInsert, sAggInfo.sortingIdx, regRecord); sqlite3ReleaseTempReg(pParse, regRecord); sqlite3ReleaseTempRange(pParse, regBase, nCol); sqlite3WhereEnd(pWInfo); sqlite3VdbeAddOp2(v, OP_Sort, sAggInfo.sortingIdx, addrEnd); VdbeComment((v, "GROUP BY sort")); sAggInfo.useSortingIdx = 1; |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.650 2008/01/17 02:36:28 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** The macro unlikely() is a hint that surrounds a boolean ** expression that is usually false. Macro likely() surrounds |
︙ | ︙ | |||
1945 1946 1947 1948 1949 1950 1951 | void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*)); int sqlite3ApiExit(sqlite3 *db, int); int sqlite3OpenTempDatabase(Parse *); void sqlite3StrAccumAppend(StrAccum*,const char*,int); char *sqlite3StrAccumFinish(StrAccum*); void sqlite3StrAccumReset(StrAccum*); | < | 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 | void (*)(sqlite3_context*,int,sqlite3_value **), void (*)(sqlite3_context*)); int sqlite3ApiExit(sqlite3 *db, int); int sqlite3OpenTempDatabase(Parse *); void sqlite3StrAccumAppend(StrAccum*,const char*,int); char *sqlite3StrAccumFinish(StrAccum*); void sqlite3StrAccumReset(StrAccum*); void sqlite3SelectDestInit(SelectDest*,int,int); /* ** The interface to the LEMON-generated parser */ void *sqlite3ParserAlloc(void*(*)(size_t)); void sqlite3ParserFree(void*, void(*)(void*)); |
︙ | ︙ |
Changes to src/trigger.c.
︙ | ︙ | |||
519 520 521 522 523 524 525 | /* Generate code to destroy the database record of the trigger. */ assert( pTable!=0 ); if( (v = sqlite3GetVdbe(pParse))!=0 ){ int base; static const VdbeOpList dropTrigger[] = { { OP_Rewind, 0, ADDR(9), 0}, | | | | | | | | 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 | /* Generate code to destroy the database record of the trigger. */ assert( pTable!=0 ); if( (v = sqlite3GetVdbe(pParse))!=0 ){ int base; static const VdbeOpList dropTrigger[] = { { OP_Rewind, 0, ADDR(9), 0}, { OP_String8, 0, 1, 0}, /* 1 */ { OP_Column, 0, 1, 2}, { OP_Ne, 2, ADDR(8), 1}, { OP_String8, 0, 1, 0}, /* 4: "trigger" */ { OP_Column, 0, 0, 2}, { OP_Ne, 2, ADDR(8), 1}, { OP_Delete, 0, 0, 0}, { OP_Next, 0, ADDR(1), 0}, /* 8 */ }; sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3OpenMasterTable(pParse, iDb); base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** ** $Id: update.c,v 1.168 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_VIRTUALTABLE /* Forward declaration */ static void updateVirtualTable( Parse *pParse, /* The parsing context */ |
︙ | ︙ | |||
445 446 447 448 449 450 451 | }else{ sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr, regCols+i); } }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i); } } | | | 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 | }else{ sqlite3ExprCodeAndCache(pParse, pChanges->a[j].pExpr, regCols+i); } }else{ sqlite3VdbeAddOp2(v, OP_Null, 0, regCols+i); } } sqlite3VdbeAddOp3(v, OP_MakeRecord, regCols, pTab->nCol, regRow); if( !isView ){ sqlite3TableAffinityStr(v, pTab); } sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol); if( pParse->nErr ) goto update_cleanup; sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRow, regRowid); sqlite3ReleaseTempReg(pParse, regRowid); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** ** $Id: vdbe.c,v 1.697 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor |
︙ | ︙ | |||
1980 1981 1982 1983 1984 1985 1986 | } if( c ){ pc = pOp->p2-1; } break; } | < < < < < < < < < < < < < < < < < < < < < | 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 | } if( c ){ pc = pOp->p2-1; } break; } /* Opcode: IsNull P1 P2 P3 * * ** ** Jump to P2 if the value in register P1 is NULL. If P3 is greater ** than zero, then check all values reg(P1), reg(P1+1), ** reg(P1+2), ..., reg(P1+P3-1). ** ** If P1 is 0 then use the top of the stack instead of a register |
︙ | ︙ | |||
2315 2316 2317 2318 2319 2320 2321 | op_column_out: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); break; } | | | < < < < < < < < < < < < < < < < < | | 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 | op_column_out: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); break; } /* Opcode: MakeRecord P1 P2 P3 P4 * ** ** Convert P2 registers beginning with P1 into a single entry ** suitable for use as a data record in a database table or as a key ** in an index. The details of the format are irrelavant as long as ** the OP_Column opcode can decode the record later and as long as the ** sqlite3VdbeRecordCompare function will correctly compare two encoded ** records. Refer to source code comments for the details of the record ** format. ** ** P4 may be a string that is P1 characters long. The nth character of the ** string indicates the column affinity that should be used for the nth ** field of the index key (i.e. the first character of P4 corresponds to the ** lowest element on the stack). ** ** The mapping from character to affinity is given by the SQLITE_AFF_ ** macros defined in sqliteInt.h. ** ** If P4 is NULL then all index fields have the affinity NONE. */ case OP_MakeRecord: { /* Assuming the record contains N fields, the record format looks ** like this: ** ** ------------------------------------------------------------------------ ** | hdr-size | type 0 | type 1 | ... | type N-1 | data0 | ... | data N-1 | ** ------------------------------------------------------------------------ ** |
︙ | ︙ | |||
2376 2377 2378 2379 2380 2381 2382 | Mem *pRec; /* The new record */ u64 nData = 0; /* Number of bytes of data space */ int nHdr = 0; /* Number of bytes of header space */ u64 nByte = 0; /* Data space required for this record */ int nZero = 0; /* Number of zero bytes at the end of the record */ int nVarint; /* Number of bytes in a varint */ u32 serial_type; /* Type field */ | < | | < < < < < < < < | < < < | | | < < | < < < < < < < < < < | 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 | Mem *pRec; /* The new record */ u64 nData = 0; /* Number of bytes of data space */ int nHdr = 0; /* Number of bytes of header space */ u64 nByte = 0; /* Data space required for this record */ int nZero = 0; /* Number of zero bytes at the end of the record */ int nVarint; /* Number of bytes in a varint */ u32 serial_type; /* Type field */ Mem *pData0; /* First field to be combined into the record */ Mem *pLast; /* Last field of the record */ int nField; /* Number of fields in the record */ char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ int i; /* Space used in zNewRecord[] */ char zTemp[NBFS]; /* Space to hold small records */ nField = pOp->p1; zAffinity = pOp->p4.z; assert( nField>0 && pOp->p2>0 && pOp->p2+nField<=p->nMem ); pData0 = &p->aMem[nField]; nField = pOp->p2; pLast = &pData0[nField-1]; file_format = p->minWriteFileFormat; /* Loop through the elements that will make up the record to figure ** out how much space is required for the new record. */ for(pRec=pData0; pRec<=pLast; pRec++){ int len; if( zAffinity ){ applyAffinity(pRec, zAffinity[pRec-pData0], encoding); } if( pRec->flags&MEM_Zero && pRec->n>0 ){ ExpandBlob(pRec); } serial_type = sqlite3VdbeSerialType(pRec, file_format); len = sqlite3VdbeSerialTypeLen(serial_type); nData += len; nHdr += sqlite3VarintLen(serial_type); |
︙ | ︙ | |||
2471 2472 2473 2474 2475 2476 2477 | i += sqlite3PutVarint(&zNewRecord[i], serial_type); /* serial type */ } for(pRec=pData0; pRec<=pLast; pRec++){ /* serial data */ i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format); } assert( i==nByte ); | < < < < | 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 | i += sqlite3PutVarint(&zNewRecord[i], serial_type); /* serial type */ } for(pRec=pData0; pRec<=pLast; pRec++){ /* serial data */ i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format); } assert( i==nByte ); if( pOp->p3==0 ){ pOut = ++pTos; }else{ pOut = &p->aMem[pOp->p3]; Release(pOut); } pOut->n = nByte; |
︙ | ︙ | |||
2500 2501 2502 2503 2504 2505 2506 | if( nZero ){ pOut->u.i = nZero; pOut->flags |= MEM_Zero; } pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ REGISTER_TRACE(pOp->p3, pOut); UPDATE_MAX_BLOBSIZE(pOut); | < < < < < | 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 | if( nZero ){ pOut->u.i = nZero; pOut->flags |= MEM_Zero; } pOut->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ REGISTER_TRACE(pOp->p3, pOut); UPDATE_MAX_BLOBSIZE(pOut); break; } /* Opcode: Statement P1 * * * * ** ** Begin an individual statement transaction which is part of a larger ** BEGIN..COMMIT transaction. This is needed so that the statement |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
713 714 715 716 717 718 719 | #if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) /* ** Print a single opcode. This routine is used for debugging only. */ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ char *zP4; char zPtr[50]; | | | > > > > > > | 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 | #if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) /* ** Print a single opcode. This routine is used for debugging only. */ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){ char *zP4; char zPtr[50]; static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-4s %.2X %s\n"; if( pOut==0 ) pOut = stdout; zP4 = displayP4(pOp, zPtr, sizeof(zPtr)); fprintf(pOut, zFormat1, pc, sqlite3OpcodeName(pOp->opcode), pOp->p1, pOp->p2, pOp->p3, zP4, pOp->p5, #ifdef SQLITE_DEBUG pOp->zComment ? pOp->zComment : "" #else "" #endif ); fflush(pOut); } #endif /* ** Release an array of N Mem elements */ |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. This module is reponsible for ** generating the code that loops through a table looking for applicable ** rows. Indices are selected and used to speed the search when doing ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. This module is reponsible for ** generating the code that loops through a table looking for applicable ** rows. Indices are selected and used to speed the search when doing ** so is applicable. Because this module is responsible for selecting ** indices, you might also think of this module as the "query optimizer". ** ** $Id: where.c,v 1.282 2008/01/17 02:36:28 drh Exp $ */ #include "sqliteInt.h" /* ** The number of bits in a Bitmask. "BMS" means "BitMask Size". */ #define BMS (sizeof(Bitmask)*8) |
︙ | ︙ | |||
1701 1702 1703 1704 1705 1706 1707 | ** to be probed is pIdx. Pop the values from the stack and ** replace them all with a single record that is the index ** problem. */ static void buildIndexProbe( Vdbe *v, /* Generate code into this VM */ int nColumn, /* The number of columns to check for NULL */ | | > > > > | | | > > > | | < > | > > > | | 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 | ** to be probed is pIdx. Pop the values from the stack and ** replace them all with a single record that is the index ** problem. */ static void buildIndexProbe( Vdbe *v, /* Generate code into this VM */ int nColumn, /* The number of columns to check for NULL */ Index *pIdx, /* Index that we will be searching */ int regSrc, /* Take values from this register */ int regDest /* Write the result into this register */ ){ assert( regSrc>0 ); assert( regDest>0 ); sqlite3VdbeAddOp3(v, OP_MakeRecord, regSrc, nColumn, regDest); sqlite3IndexAffinityStr(v, pIdx); } /* ** Generate code for a single equality term of the WHERE clause. An equality ** term can be either X=expr or X IN (...). pTerm is the term to be ** coded. ** ** The current value for the constraint is left in register iReg. ** ** For a constraint of the form X=expr, the expression is evaluated and its ** result is left on the stack. For constraints of the form X IN (...) ** this routine sets up a loop that will iterate over all values of X. */ static void codeEqualityTerm( Parse *pParse, /* The parsing context */ WhereTerm *pTerm, /* The term of the WHERE clause to be coded */ WhereLevel *pLevel, /* When level of the FROM clause we are working on */ int iReg /* Leave results in this register */ ){ Expr *pX = pTerm->pExpr; Vdbe *v = pParse->pVdbe; assert( iReg>0 && iReg<=pParse->nMem ); if( pX->op==TK_EQ ){ sqlite3ExprCode(pParse, pX->pRight, iReg); }else if( pX->op==TK_ISNULL ){ sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); #ifndef SQLITE_OMIT_SUBQUERY }else{ int eType; int iTab; struct InLoop *pIn; assert( pX->op==TK_IN ); eType = sqlite3FindInIndex(pParse, pX, 1); iTab = pX->iTable; sqlite3VdbeAddOp2(v, OP_Rewind, iTab, 0); VdbeComment((v, "%.*s", pX->span.n, pX->span.z)); if( pLevel->nIn==0 ){ pLevel->nxt = sqlite3VdbeMakeLabel(v); } pLevel->nIn++; pLevel->aInLoop = sqlite3DbReallocOrFree(pParse->db, pLevel->aInLoop, sizeof(pLevel->aInLoop[0])*pLevel->nIn); pIn = pLevel->aInLoop; if( pIn ){ pIn += pLevel->nIn - 1; pIn->iCur = iTab; if( eType==IN_INDEX_ROWID ){ pIn->topAddr = sqlite3VdbeAddOp2(v, OP_Rowid, iTab, iReg); }else{ pIn->topAddr = sqlite3VdbeAddOp3(v, OP_Column, iTab, 0, iReg); } sqlite3VdbeAddOp1(v, OP_IsNull, iReg); }else{ pLevel->nIn = 0; } #endif } disableTerm(pLevel, pTerm); } |
︙ | ︙ | |||
1785 1786 1787 1788 1789 1790 1791 | ** This routine always allocates at least one memory cell and puts ** the address of that memory cell in pLevel->iMem. The code that ** calls this routine will use pLevel->iMem to store the termination ** key value of the loop. If one or more IN operators appear, then ** this routine allocates an additional nEq memory cells for internal ** use. */ | | | > < > | | | < < | < < < | | < < < < < < < | 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 | ** This routine always allocates at least one memory cell and puts ** the address of that memory cell in pLevel->iMem. The code that ** calls this routine will use pLevel->iMem to store the termination ** key value of the loop. If one or more IN operators appear, then ** this routine allocates an additional nEq memory cells for internal ** use. */ static int codeAllEqualityTerms( Parse *pParse, /* Parsing context */ WhereLevel *pLevel, /* Which nested loop of the FROM we are coding */ WhereClause *pWC, /* The WHERE clause */ Bitmask notReady, /* Which parts of FROM have not yet been coded */ int nExtraReg /* Number of extra registers to allocate */ ){ int nEq = pLevel->nEq; /* The number of == or IN constraints to code */ Vdbe *v = pParse->pVdbe; /* The virtual machine under construction */ Index *pIdx = pLevel->pIdx; /* The index being used for this loop */ int iCur = pLevel->iTabCur; /* The cursor of the table */ WhereTerm *pTerm; /* A single constraint term */ int j; /* Loop counter */ int regBase; /* Base register */ /* Figure out how many memory cells we will need then allocate them. ** We always need at least one used to store the loop terminator ** value. If there are IN operators we'll need one for each == or ** IN constraint. */ pLevel->iMem = pParse->nMem + 1; regBase = pParse->nMem + 2; pParse->nMem += pLevel->nEq + 2 + nExtraReg; /* Evaluate the equality constraints */ assert( pIdx->nColumn>=nEq ); for(j=0; j<nEq; j++){ int k = pIdx->aiColumn[j]; pTerm = findTerm(pWC, iCur, k, notReady, pLevel->flags, pIdx); if( pTerm==0 ) break; assert( (pTerm->flags & TERM_CODED)==0 ); codeEqualityTerm(pParse, pTerm, pLevel, regBase+j); if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->brk); } } return regBase; } #if defined(SQLITE_TEST) /* ** The following variable holds a text description of query plan generated ** by the most recent call to sqlite3WhereBegin(). Each call to WhereBegin ** overwrites the previous. This information is used for testing and |
︙ | ︙ | |||
2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 | sqlite3_index_info *pBestIdx = pLevel->pBestIdx; int nConstraint = pBestIdx->nConstraint; struct sqlite3_index_constraint_usage *aUsage = pBestIdx->aConstraintUsage; const struct sqlite3_index_constraint *aConstraint = pBestIdx->aConstraint; for(j=1; j<=nConstraint; j++){ int k; for(k=0; k<nConstraint; k++){ if( aUsage[k].argvIndex==j ){ int iTerm = aConstraint[k].iTermOffset; | > | < < < > > > | | | > > | | | > < | > | | | > | 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 | sqlite3_index_info *pBestIdx = pLevel->pBestIdx; int nConstraint = pBestIdx->nConstraint; struct sqlite3_index_constraint_usage *aUsage = pBestIdx->aConstraintUsage; const struct sqlite3_index_constraint *aConstraint = pBestIdx->aConstraint; iReg = sqlite3GetTempRange(pParse, nConstraint+2); for(j=1; j<=nConstraint; j++){ int k; for(k=0; k<nConstraint; k++){ if( aUsage[k].argvIndex==j ){ int iTerm = aConstraint[k].iTermOffset; sqlite3ExprCode(pParse, wc.a[iTerm].pExpr->pRight, iReg+j+1); break; } } if( k==nConstraint ) break; } sqlite3VdbeAddOp2(v, OP_Integer, pBestIdx->idxNum, iReg); sqlite3VdbeAddOp2(v, OP_Integer, j-1, iReg+1); sqlite3VdbeAddOp4(v, OP_VFilter, iCur, brk, iReg, pBestIdx->idxStr, pBestIdx->needToFreeIdxStr ? P4_MPRINTF : P4_STATIC); sqlite3ReleaseTempRange(pParse, iReg, nConstraint+2); pBestIdx->needToFreeIdxStr = 0; for(j=0; j<pBestIdx->nConstraint; j++){ if( aUsage[j].omit ){ int iTerm = aConstraint[j].iTermOffset; disableTerm(pLevel, &wc.a[iTerm]); } } pLevel->op = OP_VNext; pLevel->p1 = iCur; pLevel->p2 = sqlite3VdbeCurrentAddr(v); }else #endif /* SQLITE_OMIT_VIRTUALTABLE */ if( pLevel->flags & WHERE_ROWID_EQ ){ /* Case 1: We can directly reference a single row using an ** equality comparison against the ROWID field. Or ** we reference multiple rows using a "rowid IN (...)" ** construct. */ int r1; pTerm = findTerm(&wc, iCur, -1, notReady, WO_EQ|WO_IN, 0); assert( pTerm!=0 ); assert( pTerm->pExpr!=0 ); assert( pTerm->leftCursor==iCur ); assert( omitTable==0 ); r1 = sqlite3GetTempReg(pParse); codeEqualityTerm(pParse, pTerm, pLevel, r1); nxt = pLevel->nxt; sqlite3VdbeAddOp3(v, OP_MustBeInt, r1, nxt, 1); sqlite3VdbeAddOp3(v, OP_NotExists, iCur, nxt, r1); VdbeComment((v, "pk")); sqlite3ReleaseTempReg(pParse, r1); pLevel->op = OP_Noop; }else if( pLevel->flags & WHERE_ROWID_RANGE ){ /* Case 2: We have an inequality comparison against the ROWID field. */ int testOp = OP_Noop; int start; WhereTerm *pStart, *pEnd; assert( omitTable==0 ); pStart = findTerm(&wc, iCur, -1, notReady, WO_GT|WO_GE, 0); pEnd = findTerm(&wc, iCur, -1, notReady, WO_LT|WO_LE, 0); if( bRev ){ pTerm = pStart; pStart = pEnd; pEnd = pTerm; } if( pStart ){ Expr *pX; int r1, regFree1; pX = pStart->pExpr; assert( pX!=0 ); assert( pStart->leftCursor==iCur ); r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, ®Free1); sqlite3VdbeAddOp3(v, OP_ForceInt, r1, brk, pX->op==TK_LE || pX->op==TK_GT); sqlite3VdbeAddOp3(v, bRev ? OP_MoveLt : OP_MoveGe, iCur, brk, r1); VdbeComment((v, "pk")); sqlite3ReleaseTempReg(pParse, regFree1); disableTerm(pLevel, pStart); }else{ sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iCur, brk); } if( pEnd ){ Expr *pX; pX = pEnd->pExpr; assert( pX!=0 ); assert( pEnd->leftCursor==iCur ); pLevel->iMem = ++pParse->nMem; sqlite3ExprCode(pParse, pX->pRight, pLevel->iMem); if( pX->op==TK_LT || pX->op==TK_GT ){ testOp = bRev ? OP_Le : OP_Ge; }else{ testOp = bRev ? OP_Lt : OP_Gt; } disableTerm(pLevel, pEnd); } start = sqlite3VdbeCurrentAddr(v); pLevel->op = bRev ? OP_Prev : OP_Next; pLevel->p1 = iCur; pLevel->p2 = start; if( testOp!=OP_Noop ){ int r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_Rowid, iCur, r1); /* sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); */ sqlite3VdbeAddOp3(v, testOp, pLevel->iMem, brk, r1); sqlite3VdbeChangeP5(v, SQLITE_AFF_NUMERIC | SQLITE_JUMPIFNULL); sqlite3ReleaseTempReg(pParse, r1); } }else if( pLevel->flags & WHERE_COLUMN_RANGE ){ /* Case 3: The WHERE clause term that refers to the right-most ** column of the index is an inequality. For example, if ** the index is on (x,y,z) and the WHERE clause is of the ** form "x=5 AND y<10" then this case is used. Only the ** right-most column can be an inequality - the rest must |
︙ | ︙ | |||
2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 | int topEq=0; /* True if top limit uses ==. False is strictly < */ int btmEq=0; /* True if btm limit uses ==. False if strictly > */ int topOp, btmOp; /* Operators for the top and bottom search bounds */ int testOp; int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0; int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0; int isMinQuery = 0; /* If this is an optimized SELECT min(x) ... */ /* Generate code to evaluate all constraint terms using == or IN ** and level the values of those terms on the stack. */ | > > | < < < < < < < < | 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 | int topEq=0; /* True if top limit uses ==. False is strictly < */ int btmEq=0; /* True if btm limit uses ==. False if strictly > */ int topOp, btmOp; /* Operators for the top and bottom search bounds */ int testOp; int topLimit = (pLevel->flags & WHERE_TOP_LIMIT)!=0; int btmLimit = (pLevel->flags & WHERE_BTM_LIMIT)!=0; int isMinQuery = 0; /* If this is an optimized SELECT min(x) ... */ int regBase; /* Base register holding constraint values */ int r1; /* Temp register */ /* Generate code to evaluate all constraint terms using == or IN ** and level the values of those terms on the stack. */ regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 2); /* Figure out what comparison operators to use for top and bottom ** search bounds. For an ascending index, the bottom bound is a > or >= ** operator and the top bound is a < or <= operator. For a descending ** index the operators are reversed. */ if( pIdx->aSortOrder[nEq]==SQLITE_SO_ASC ){ |
︙ | ︙ | |||
2458 2459 2460 2461 2462 2463 2464 | ** ** 2002-Dec-04: On a reverse-order scan, the so-called "termination" ** key computed here really ends up being the start key. */ nxt = pLevel->nxt; if( topLimit ){ Expr *pX; | | | | < > < | | < < | | | > < < | < > > > > | > < | > | | | | > > > | < < < < | < | > | > | < > | > > > > | | > | > > > > | | > | | > | 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 | ** ** 2002-Dec-04: On a reverse-order scan, the so-called "termination" ** key computed here really ends up being the start key. */ nxt = pLevel->nxt; if( topLimit ){ Expr *pX; int k = pIdx->aiColumn[nEq]; pTerm = findTerm(&wc, iCur, k, notReady, topOp, pIdx); assert( pTerm!=0 ); pX = pTerm->pExpr; assert( (pTerm->flags & TERM_CODED)==0 ); sqlite3ExprCode(pParse, pX->pRight, regBase+nEq); sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt); topEq = pTerm->eOperator & (WO_LE|WO_GE); disableTerm(pLevel, pTerm); testOp = OP_IdxGE; }else{ testOp = nEq>0 ? OP_IdxGE : OP_Noop; topEq = 1; } if( testOp!=OP_Noop || (isMinQuery&&bRev) ){ int nCol = nEq + topLimit; if( isMinQuery && !topLimit ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nCol); nCol++; topEq = 0; } buildIndexProbe(v, nCol, pIdx, regBase, pLevel->iMem); if( bRev ){ int op = topEq ? OP_MoveLe : OP_MoveLt; sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, pLevel->iMem); } }else if( bRev ){ sqlite3VdbeAddOp2(v, OP_Last, iIdxCur, brk); } /* Generate the start key. This is the key that defines the lower ** bound on the search. There is no start key if there are no ** equality terms and if there is no "X>..." term. In ** that case, generate a "Rewind" instruction in place of the ** start key search. ** ** 2002-Dec-04: In the case of a reverse-order search, the so-called ** "start" key really ends up being used as the termination key. */ if( btmLimit ){ Expr *pX; int k = pIdx->aiColumn[nEq]; pTerm = findTerm(&wc, iCur, k, notReady, btmOp, pIdx); assert( pTerm!=0 ); pX = pTerm->pExpr; assert( (pTerm->flags & TERM_CODED)==0 ); sqlite3ExprCode(pParse, pX->pRight, regBase+nEq); sqlite3VdbeAddOp2(v, OP_IsNull, regBase+nEq, nxt); btmEq = pTerm->eOperator & (WO_LE|WO_GE); disableTerm(pLevel, pTerm); }else{ btmEq = 1; } if( nEq>0 || btmLimit || (isMinQuery&&!bRev) ){ int nCol = nEq + btmLimit; if( isMinQuery && !btmLimit ){ sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nCol); nCol++; btmEq = 0; } if( bRev ){ r1 = pLevel->iMem; testOp = OP_IdxLT; }else{ r1 = sqlite3GetTempReg(pParse); } buildIndexProbe(v, nCol, pIdx, regBase, r1); if( !bRev ){ int op = btmEq ? OP_MoveGe : OP_MoveGt; sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1); sqlite3ReleaseTempReg(pParse, r1); } }else if( bRev ){ testOp = OP_Noop; }else{ sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, brk); } /* Generate the the top of the loop. If there is a termination ** key we have to test for that key and abort at the top of the ** loop. */ start = sqlite3VdbeCurrentAddr(v); if( testOp!=OP_Noop ){ sqlite3VdbeAddOp3(v, testOp, iIdxCur, nxt, pLevel->iMem); if( (topEq && !bRev) || (!btmEq && bRev) ){ sqlite3VdbeChangeP5(v, 1); } } r1 = sqlite3GetTempReg(pParse); if( topLimit | btmLimit ){ sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, nEq, r1); sqlite3VdbeAddOp2(v, OP_IsNull, r1, cont); } if( !omitTable ){ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1); sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); } sqlite3ReleaseTempReg(pParse, r1); /* Record the instruction used to terminate the loop. */ pLevel->op = bRev ? OP_Prev : OP_Next; pLevel->p1 = iIdxCur; pLevel->p2 = start; }else if( pLevel->flags & WHERE_COLUMN_EQ ){ /* Case 4: There is an index and all terms of the WHERE clause that ** refer to the index using the "==" or "IN" operators. */ int start; int nEq = pLevel->nEq; int isMinQuery = 0; /* If this is an optimized SELECT min(x) ... */ int regBase; /* Base register of array holding constraints */ int r1; /* Generate code to evaluate all constraint terms using == or IN ** and leave the values of those terms on the stack. */ regBase = codeAllEqualityTerms(pParse, pLevel, &wc, notReady, 1); nxt = pLevel->nxt; if( (obflag==ORDERBY_MIN) && (pLevel->flags&WHERE_ORDERBY) && (pIdx->nColumn>nEq) && (pOrderBy->a[0].pExpr->iColumn==pIdx->aiColumn[nEq]) ){ isMinQuery = 1; buildIndexProbe(v, nEq, pIdx, regBase, pLevel->iMem); sqlite3VdbeAddOp2(v, OP_Null, 0, regBase+nEq); r1 = ++pParse->nMem; buildIndexProbe(v, nEq+1, pIdx, regBase, r1); }else{ /* Generate a single key that will be used to both start and ** terminate the search */ r1 = pLevel->iMem; buildIndexProbe(v, nEq, pIdx, regBase, r1); } /* Generate code (1) to move to the first matching element of the table. ** Then generate code (2) that jumps to "nxt" after the cursor is past ** the last matching element of the table. The code (1) is executed ** once to initialize the search, the code (2) is executed before each ** iteration of the scan to see if the scan has finished. */ if( bRev ){ /* Scan in reverse order */ int op; if( isMinQuery ){ op = OP_MoveLt; }else{ op = OP_MoveLe; } sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1); start = sqlite3VdbeAddOp3(v, OP_IdxLT, iIdxCur, nxt, pLevel->iMem); pLevel->op = OP_Prev; }else{ /* Scan in the forward order */ int op; if( isMinQuery ){ op = OP_MoveGt; }else{ op = OP_MoveGe; } sqlite3VdbeAddOp3(v, op, iIdxCur, nxt, r1); start = sqlite3VdbeAddOp3(v, OP_IdxGE, iIdxCur, nxt, pLevel->iMem); sqlite3VdbeChangeP5(v, 1); pLevel->op = OP_Next; } if( !omitTable ){ r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, r1); sqlite3VdbeAddOp3(v, OP_MoveGe, iCur, 0, r1); sqlite3ReleaseTempReg(pParse, r1); } pLevel->p1 = iIdxCur; pLevel->p2 = start; }else{ /* Case 5: There is no usable index. We must do a complete ** scan of the entire table. */ |
︙ | ︙ |
Changes to test/tester.tcl.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements some common TCL routines used for regression # testing the SQLite library # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements some common TCL routines used for regression # testing the SQLite library # # $Id: tester.tcl,v 1.101 2008/01/17 02:36:28 drh Exp $ set tcl_precision 15 set sqlite_pending_byte 0x0010000 # # Check the command-line arguments for a default soft-heap-limit. |
︙ | ︙ | |||
599 600 601 602 603 604 605 | return $cksum } # Generate a checksum based on the contents of the main and temp tables # database $db. If the checksum of two databases is the same, and the # integrity-check passes for both, the two databases are identical. # | | | 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 | return $cksum } # Generate a checksum based on the contents of the main and temp tables # database $db. If the checksum of two databases is the same, and the # integrity-check passes for both, the two databases are identical. # proc allcksum {{db db}} { set ret [list] ifcapable tempdb { set sql { SELECT name FROM sqlite_master WHERE type = 'table' UNION SELECT name FROM sqlite_temp_master WHERE type = 'table' UNION SELECT 'sqlite_master' UNION SELECT 'sqlite_temp_master' ORDER BY 1 |
︙ | ︙ |
Changes to test/vacuum.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the VACUUM statement. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2001 September 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the VACUUM statement. # # $Id: vacuum.test,v 1.40 2008/01/17 02:36:28 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # If the VACUUM statement is disabled in the current build, skip all # the tests in this file. # |
︙ | ︙ | |||
45 46 47 48 49 50 51 | CREATE INDEX i1 ON t1(b,c); CREATE UNIQUE INDEX i2 ON t1(c,a); CREATE TABLE t2 AS SELECT * FROM t1; COMMIT; DROP TABLE t2; } set ::size1 [file size test.db] | | | | 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | CREATE INDEX i1 ON t1(b,c); CREATE UNIQUE INDEX i2 ON t1(c,a); CREATE TABLE t2 AS SELECT * FROM t1; COMMIT; DROP TABLE t2; } set ::size1 [file size test.db] set ::cksum [cksum] expr {$::cksum!=""} } {1} do_test vacuum-1.2 { execsql { VACUUM; } cksum } $cksum ifcapable vacuum { do_test vacuum-1.3 { expr {[file size test.db]<$::size1} } {1} } do_test vacuum-1.4 { |
︙ | ︙ | |||
80 81 82 83 84 85 86 | regsub {CREATE VIEW} $sql_script {-- CREATE VIEW} sql_script } ifcapable !trigger { regsub {CREATE TRIGGER} $sql_script {-- CREATE TRIGGER} sql_script } execsql $sql_script set ::size1 [file size test.db] | | | | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | regsub {CREATE VIEW} $sql_script {-- CREATE VIEW} sql_script } ifcapable !trigger { regsub {CREATE TRIGGER} $sql_script {-- CREATE TRIGGER} sql_script } execsql $sql_script set ::size1 [file size test.db] set ::cksum [cksum] expr {$::cksum!=""} } {1} do_test vacuum-1.5 { execsql { VACUUM; } cksum } $cksum ifcapable vacuum { do_test vacuum-1.6 { expr {[file size test.db]<$::size1} } {1} } |
︙ | ︙ | |||
115 116 117 118 119 120 121 | BEGIN; CREATE TABLE t4 AS SELECT * FROM t1; CREATE TABLE t5 AS SELECT * FROM t1; COMMIT; DROP TABLE t4; DROP TABLE t5; } db2 | | | | | 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | BEGIN; CREATE TABLE t4 AS SELECT * FROM t1; CREATE TABLE t5 AS SELECT * FROM t1; COMMIT; DROP TABLE t4; DROP TABLE t5; } db2 set ::cksum [cksum db2] catchsql { VACUUM } } {0 {}} do_test vacuum-2.3 { cksum } $cksum do_test vacuum-2.4 { catch {db2 eval {SELECT count(*) FROM sqlite_master}} cksum db2 } $cksum # Make sure the schema cookie is incremented by vacuum. # do_test vacuum-2.5 { execsql { BEGIN; |
︙ | ︙ | |||
304 305 306 307 308 309 310 | execsql { DROP TABLE 'abc abc'; CREATE TABLE autoinc(a INTEGER PRIMARY KEY AUTOINCREMENT, b); INSERT INTO autoinc(b) VALUES('hi'); INSERT INTO autoinc(b) VALUES('there'); DELETE FROM autoinc; } | | | | | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 | execsql { DROP TABLE 'abc abc'; CREATE TABLE autoinc(a INTEGER PRIMARY KEY AUTOINCREMENT, b); INSERT INTO autoinc(b) VALUES('hi'); INSERT INTO autoinc(b) VALUES('there'); DELETE FROM autoinc; } set ::cksum [cksum] expr {$::cksum!=""} } {1} do_test vacuum-9.2 { execsql { VACUUM; } cksum } $::cksum do_test vacuum-9.3 { execsql { INSERT INTO autoinc(b) VALUES('one'); INSERT INTO autoinc(b) VALUES('two'); } set ::cksum [cksum] expr {$::cksum!=""} } {1} do_test vacuum-9.4 { execsql { VACUUM; } cksum } $::cksum } file delete -force {a'z.db} finish_test |
Changes to test/vacuum2.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2005 February 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the VACUUM statement. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2005 February 15 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing the VACUUM statement. # # $Id: vacuum2.test,v 1.7 2008/01/17 02:36:28 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # If the VACUUM statement is disabled in the current build, skip all # the tests in this file. # |
︙ | ︙ | |||
72 73 74 75 76 77 78 | do_test vacuum2-3.1 { execsql { INSERT INTO t1 VALUES('hello'); INSERT INTO t2 VALUES('out there'); } expr {[file size test.db]/$pageSize} } {3} | | | | | | | | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | do_test vacuum2-3.1 { execsql { INSERT INTO t1 VALUES('hello'); INSERT INTO t2 VALUES('out there'); } expr {[file size test.db]/$pageSize} } {3} set cksum [cksum] do_test vacuum2-3.2 { cksum db2 } $cksum # Convert the database to an autovacuumed database. do_test vacuum2-3.3 { execsql { PRAGMA auto_vacuum=FULL; VACUUM; } expr {[file size test.db]/$pageSize} } {4} do_test vacuum2-3.4 { cksum db2 } $cksum do_test vacuum2-3.5 { cksum } $cksum do_test vacuum2-3.6 { execsql {PRAGMA integrity_check} db2 } {ok} do_test vacuum2-3.7 { execsql {PRAGMA integrity_check} db } {ok} # Convert the database back to a non-autovacuumed database. do_test vacuum2-3.13 { execsql { PRAGMA auto_vacuum=NONE; VACUUM; } expr {[file size test.db]/$pageSize} } {3} do_test vacuum2-3.14 { cksum db2 } $cksum do_test vacuum2-3.15 { cksum } $cksum do_test vacuum2-3.16 { execsql {PRAGMA integrity_check} db2 } {ok} do_test vacuum2-3.17 { execsql {PRAGMA integrity_check} db } {ok} db2 close finish_test |