Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Get rid of OP_Dup, OP_MemStore, OP_MemLoad, and OP_MemMove. Replace with OP_Copy, OP_SCopy, and OP_Move. Add the infrastructure for operation properties in1, in2, in3, out2, and out3 but do not yet use any of these. (CVS 4682) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
cc149eb9ca3c672cc6fea3528353234a |
User & Date: | drh 2008-01-05 04:06:04.000 |
Context
2008-01-05
| ||
05:20 | Register-ify the OP_AddImm and all casting opcodes. Omit the OP_MemIncr opcode. (CVS 4683) (check-in: 3e8a07dd3c user: drh tags: trunk) | |
04:06 | Get rid of OP_Dup, OP_MemStore, OP_MemLoad, and OP_MemMove. Replace with OP_Copy, OP_SCopy, and OP_Move. Add the infrastructure for operation properties in1, in2, in3, out2, and out3 but do not yet use any of these. (CVS 4682) (check-in: cc149eb9ca user: drh tags: trunk) | |
2008-01-04
| ||
22:01 | Implement the out2-prerelease opcode design pattern. (CVS 4681) (check-in: fe057a88d0 user: drh tags: trunk) | |
Changes
Changes to mkopcodeh.awk.
︙ | ︙ | |||
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | name = $2 sub(/:/,"",name) sub("\r","",name) op[name] = -1 jump[name] = 0 nopush[name] = 0 out2_prerelease[name] = 0 for(i=3; i<NF; i++){ if($i=="same" && $(i+1)=="as"){ sym = $(i+2) sub(/,/,"",sym) op[name] = tk[sym] used[op[name]] = 1 sameas[op[name]] = sym } x = $i sub(",","",x) if(x=="no-push"){ nopush[name] = 1 }else if(x=="jump"){ jump[name] = 1 }else if(x=="out2-prerelease"){ out2_prerelease[name] = 1 } } } # Assign numbers to all opcodes and output the result. END { cnt = 0 | > > > > > > > > > > > > > > > | 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | name = $2 sub(/:/,"",name) sub("\r","",name) op[name] = -1 jump[name] = 0 nopush[name] = 0 out2_prerelease[name] = 0 in1[name] = 0 in2[name] = 0 in3[name] = 0 out2[name] = 0 out3[name] = 0 for(i=3; i<NF; i++){ if($i=="same" && $(i+1)=="as"){ sym = $(i+2) sub(/,/,"",sym) op[name] = tk[sym] used[op[name]] = 1 sameas[op[name]] = sym } x = $i sub(",","",x) if(x=="no-push"){ nopush[name] = 1 }else if(x=="jump"){ jump[name] = 1 }else if(x=="out2-prerelease"){ out2_prerelease[name] = 1 }else if(x=="in1"){ in1[name] = 1 }else if(x=="in2"){ in2[name] = 1 }else if(x=="in3"){ in3[name] = 1 }else if(x=="out2"){ out2[name] = 1 }else if(x=="out3"){ out3[name] = 1 } } } # Assign numbers to all opcodes and output the result. END { cnt = 0 |
︙ | ︙ | |||
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | for(i=0; i<=max; i++) bv[i] = 0; for(name in op){ x = op[name] a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = 0 if( jump[name] ) a0 = 1; if( nopush[name]==0 ) a1 = 2; if( out2_prerelease[name] ) a2 = 4; bv[x] = a0+a1+a2+a3+a4+a5+a6+a7; } print "\n" print "/* Properties such as \"out2\" or \"jump\" that are specified in" print "** comments following the "case" for each opcode in the vdbe.c" print "** are encoded into bitvectors as follows:" print "*/" print "#define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */" print "#define OPFLG_PUSH 0x02 /* ~no-push: Does not push */" print "#define OPFLG_OUT2_PRERELEASE 0x04 /* out2-prerelease: */" print "#define OPFLG_INITIALIZER {\\" for(i=0; i<=max; i++){ printf " 0x%02x,", bv[i] if( i%8==7 ) printf("\\\n"); } print "}" } | > > > > > > > > > > | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | for(i=0; i<=max; i++) bv[i] = 0; for(name in op){ x = op[name] a0 = a1 = a2 = a3 = a4 = a5 = a6 = a7 = 0 if( jump[name] ) a0 = 1; if( nopush[name]==0 ) a1 = 2; if( out2_prerelease[name] ) a2 = 4; if( in1[name] ) a3 = 8; if( in2[name] ) a4 = 16; if( in3[name] ) a5 = 32; if( out2[name] ) a6 = 64; if( out3[name] ) a7 = 128; bv[x] = a0+a1+a2+a3+a4+a5+a6+a7; } print "\n" print "/* Properties such as \"out2\" or \"jump\" that are specified in" print "** comments following the "case" for each opcode in the vdbe.c" print "** are encoded into bitvectors as follows:" print "*/" print "#define OPFLG_JUMP 0x01 /* jump: P2 holds jmp target */" print "#define OPFLG_PUSH 0x02 /* ~no-push: Does not push */" print "#define OPFLG_OUT2_PRERELEASE 0x04 /* out2-prerelease: */" print "#define OPFLG_IN1 0x08 /* in1: P1 is an input */" print "#define OPFLG_IN2 0x10 /* in2: P2 is an input */" print "#define OPFLG_IN3 0x20 /* in3: P3 is an input */" print "#define OPFLG_OUT2 0x40 /* out2: P2 is an output */" print "#define OPFLG_OUT3 0x80 /* out3: P3 is an output */" print "#define OPFLG_INITIALIZER {\\" for(i=0; i<=max; i++){ printf " 0x%02x,", bv[i] if( i%8==7 ) printf("\\\n"); } print "}" } |
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.32 2008/01/05 04:06:04 drh Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" /* ** This routine generates code that opens the sqlite_stat1 table on cursor ** iStatCur. |
︙ | ︙ | |||
154 155 156 157 158 159 160 | */ endOfLoop = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, endOfLoop); topOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_MemIncr, 1, iMem); for(i=0; i<nCol; i++){ sqlite3VdbeAddOp2(v, OP_Column, iIdxCur, i); | | | < | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | */ endOfLoop = sqlite3VdbeMakeLabel(v); sqlite3VdbeAddOp2(v, OP_Rewind, iIdxCur, endOfLoop); topOfLoop = sqlite3VdbeCurrentAddr(v); sqlite3VdbeAddOp2(v, OP_MemIncr, 1, iMem); for(i=0; i<nCol; i++){ sqlite3VdbeAddOp2(v, OP_Column, iIdxCur, i); sqlite3VdbeAddOp1(v, OP_SCopy, iMem+nCol+i+1); sqlite3VdbeAddOp1(v, OP_Ne, 0x100); } sqlite3VdbeAddOp2(v, OP_Goto, 0, endOfLoop); for(i=0; i<nCol; i++){ addr = sqlite3VdbeAddOp2(v, OP_MemIncr, 1, iMem+i+1); sqlite3VdbeChangeP2(v, topOfLoop + 3*i + 3, addr); sqlite3VdbeAddOp3(v, OP_Column, iIdxCur, i, iMem+nCol+i+1); } sqlite3VdbeResolveLabel(v, endOfLoop); sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, topOfLoop); sqlite3VdbeAddOp1(v, OP_Close, iIdxCur); /* Store the results. ** |
︙ | ︙ | |||
186 187 188 189 190 191 192 | ** ** I = (K+D-1)/D ** ** If K==0 then no entry is made into the sqlite_stat1 table. ** If K>0 then it is always the case the D>0 so division by zero ** is never possible. */ | | | | | | | | 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | ** ** I = (K+D-1)/D ** ** If K==0 then no entry is made into the sqlite_stat1 table. ** If K>0 then it is always the case the D>0 so division by zero ** is never possible. */ sqlite3VdbeAddOp1(v, OP_SCopy, iMem); addr = sqlite3VdbeAddOp0(v, OP_IfNot); sqlite3VdbeAddOp1(v, OP_NewRowid, iStatCur); sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->zName, 0); sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pIdx->zName, 0); sqlite3VdbeAddOp1(v, OP_SCopy, iMem); sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, " ", 0); for(i=0; i<nCol; i++){ sqlite3VdbeAddOp1(v, OP_SCopy, iMem); sqlite3VdbeAddOp1(v, OP_SCopy, iMem+i+1); sqlite3VdbeAddOp0(v, OP_Add); sqlite3VdbeAddOp1(v, OP_AddImm, -1); sqlite3VdbeAddOp1(v, OP_SCopy, iMem+i+1); sqlite3VdbeAddOp0(v, OP_Divide); sqlite3VdbeAddOp0(v, OP_ToInt); if( i==nCol-1 ){ sqlite3VdbeAddOp1(v, OP_Concat, nCol*2-1); }else{ sqlite3VdbeAddOp1(v, OP_Copy, -1); } } sqlite3VdbeAddOp4(v, OP_MakeRecord, 3, 0, 0, "aaa", 0); sqlite3CodeInsert(pParse, iStatCur, 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.458 2008/01/05 04:06:04 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. |
︙ | ︙ | |||
877 878 879 880 881 882 883 | }else #endif { sqlite3VdbeAddOp1(v, OP_CreateTable, iDb); } sqlite3OpenMasterTable(pParse, iDb); sqlite3VdbeAddOp0(v, OP_NewRowid); | | | 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 | }else #endif { sqlite3VdbeAddOp1(v, OP_CreateTable, iDb); } sqlite3OpenMasterTable(pParse, iDb); sqlite3VdbeAddOp0(v, OP_NewRowid); sqlite3VdbeAddOp0(v, OP_Copy); sqlite3VdbeAddOp0(v, OP_Null); sqlite3CodeInsert(pParse, 0, OPFLAG_APPEND); sqlite3VdbeAddOp0(v, OP_Close); sqlite3VdbeAddOp1(v, OP_Pull, 1); } /* Normal (non-error) return. */ |
︙ | ︙ | |||
1489 1490 1491 1492 1493 1494 1495 | ** as a schema-lock must have already been obtained to create it. Since ** a schema-lock excludes all other database users, the write-lock would ** be redundant. */ if( pSelect ){ SelectDest dest = {SRT_Table, 1, 0}; Table *pSelTab; | | | 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 | ** as a schema-lock must have already been obtained to create it. Since ** a schema-lock excludes all other database users, the write-lock would ** be redundant. */ if( pSelect ){ SelectDest dest = {SRT_Table, 1, 0}; Table *pSelTab; sqlite3VdbeAddOp0(v, OP_Copy); sqlite3VdbeAddOp3(v, OP_OpenWrite, 1, 0, iDb); pParse->nTab = 2; sqlite3Select(pParse, pSelect, &dest, 0, 0, 0, 0); sqlite3VdbeAddOp1(v, OP_Close, 1); if( pParse->nErr==0 ){ pSelTab = sqlite3ResultSetOfSelect(pParse, 0, pSelect); if( pSelTab==0 ) return; |
︙ | ︙ | |||
2231 2232 2233 2234 2235 2236 2237 | /* 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 ){ | | | 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 | /* 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 ){ sqlite3VdbeAddOp1(v, OP_SCopy, memRootPage); tnum = 0; }else{ tnum = pIndex->tnum; sqlite3VdbeAddOp2(v, OP_Clear, tnum, iDb); } pKey = sqlite3IndexKeyinfo(pParse, pIndex); sqlite3VdbeAddOp4(v, OP_OpenWrite, iIdx, tnum, iDb, |
︙ | ︙ | |||
2634 2635 2636 2637 2638 2639 2640 | if( v==0 ) goto exit_create_index; /* Create the rootpage for the index */ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3VdbeAddOp1(v, OP_CreateIndex, iDb); | | | 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 | if( v==0 ) goto exit_create_index; /* Create the rootpage for the index */ sqlite3BeginWriteOperation(pParse, 1, iDb); sqlite3VdbeAddOp1(v, OP_CreateIndex, iDb); sqlite3VdbeAddOp2(v, OP_Copy, 0, iMem); /* Gather the complete text of the CREATE INDEX statement into ** the zStmt variable */ if( pStart && pEnd ){ /* A named index with an explicit CREATE INDEX statement */ zStmt = sqlite3MPrintf(db, "CREATE%s INDEX %.*s", |
︙ | ︙ |
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.149 2008/01/05 04:06:04 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. |
︙ | ︙ | |||
64 65 66 67 68 69 70 | ** This function is a temporary measure required because OP_Insert now ** reads the key and data to insert from memory cells. */ void sqlite3CodeInsert(Parse *p, int iCur, u8 flags){ int iData = ++p->nMem; int iKey = ++p->nMem; Vdbe *v = sqlite3GetVdbe(p); | | | | | | 64 65 66 67 68 69 70 71 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 | ** This function is a temporary measure required because OP_Insert now ** reads the key and data to insert from memory cells. */ void sqlite3CodeInsert(Parse *p, int iCur, u8 flags){ int iData = ++p->nMem; int iKey = ++p->nMem; Vdbe *v = sqlite3GetVdbe(p); sqlite3VdbeAddOp2(v, OP_Move, 0, iData); sqlite3VdbeAddOp2(v, OP_Move, 0, iKey); sqlite3VdbeAddOp3(v, OP_Insert, iCur, iData, iKey); sqlite3VdbeChangeP5(v, sqlite3VdbeCurrentAddr(v)-1, flags); } /* ** Allocate nVal contiguous memory cells and return the index of the ** first. Also pop nVal elements from the stack and store them in the ** registers. The element on the top of the stack is stored in the ** register with the largest index. */ int sqlite3StackToReg(Parse *p, int nVal){ int i; int iRet = p->nMem+1; Vdbe *v = sqlite3GetVdbe(p); assert(v); p->nMem += nVal; for(i=nVal-1; i>=0; i--){ sqlite3VdbeAddOp2(v, OP_Move, 0, iRet+i); } return iRet; } void sqlite3RegToStack(Parse *p, int iReg, int nVal){ int i; Vdbe *v = sqlite3GetVdbe(p); assert(v); for(i=0; i<nVal; i++){ sqlite3VdbeAddOp2(v, OP_SCopy, iReg+i, 0); } } /* ** Generate code that will open a table for reading. */ void sqlite3OpenTable( |
︙ | ︙ | |||
516 517 518 519 520 521 522 | int j; Table *pTab = pIdx->pTable; sqlite3VdbeAddOp1(v, OP_Rowid, iCur); for(j=0; j<pIdx->nColumn; j++){ int idx = pIdx->aiColumn[j]; if( idx==pTab->iPKey ){ | | | 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 | int j; Table *pTab = pIdx->pTable; sqlite3VdbeAddOp1(v, OP_Rowid, iCur); for(j=0; j<pIdx->nColumn; j++){ int idx = pIdx->aiColumn[j]; if( idx==pTab->iPKey ){ sqlite3VdbeAddOp1(v, OP_Copy, -j); }else{ sqlite3VdbeAddOp2(v, OP_Column, iCur, idx); sqlite3ColumnDefault(v, pTab, idx); } } sqlite3VdbeAddOp1(v, OP_MakeIdxRec, pIdx->nColumn); sqlite3IndexAffinityStr(v, pIdx); } |
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.331 2008/01/05 04:06:04 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** Return the 'affinity' of the expression pExpr if any. ** |
︙ | ︙ | |||
304 305 306 307 308 309 310 | if( v==0 ) return 0; p = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, pToken); if( p==0 ){ return 0; /* Malloc failed */ } depth = atoi((char*)&pToken->z[1]); p->iTable = ++pParse->nMem; | < | | 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 | if( v==0 ) return 0; p = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, pToken); if( p==0 ){ return 0; /* Malloc failed */ } depth = atoi((char*)&pToken->z[1]); p->iTable = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Copy, -depth, p->iTable); return p; } /* ** Join two expressions using an AND operator. If either expression is ** NULL, then just return the other expression. */ |
︙ | ︙ | |||
1602 1603 1604 1605 1606 1607 1608 | if( iCol<0 ){ int iMem = ++pParse->nMem; int iAddr; Table *pTab = p->pSrc->a[0].pTab; int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3VdbeUsesBtree(v, iDb); | | | 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 | if( iCol<0 ){ int iMem = ++pParse->nMem; int iAddr; Table *pTab = p->pSrc->a[0].pTab; int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeAddOp1(v, OP_SCopy, iMem); iAddr = sqlite3VdbeAddOp2(v, OP_If, 0, iMem); sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem); sqlite3OpenTable(pParse, iTab, iDb, pTab, OP_OpenRead); eType = IN_INDEX_ROWID; sqlite3VdbeJumpHere(v, iAddr); |
︙ | ︙ | |||
1639 1640 1641 1642 1643 1644 1645 | int iAddr; char *pKey; pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx); iDb = sqlite3SchemaToIndex(db, pIdx->pSchema); sqlite3VdbeUsesBtree(v, iDb); | | | 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 | int iAddr; char *pKey; pKey = (char *)sqlite3IndexKeyinfo(pParse, pIdx); iDb = sqlite3SchemaToIndex(db, pIdx->pSchema); sqlite3VdbeUsesBtree(v, iDb); sqlite3VdbeAddOp1(v, OP_SCopy, iMem); iAddr = sqlite3VdbeAddOp2(v, OP_If, 0, iMem); sqlite3VdbeAddOp2(v, OP_Integer, 1, iMem); sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb, pKey,P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); eType = IN_INDEX_INDEX; |
︙ | ︙ | |||
1696 1697 1698 1699 1700 1701 1702 | ** * We are inside a trigger ** ** If all of the above are false, then we can run this code just once ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){ int mem = ++pParse->nMem; | | | 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 | ** * We are inside a trigger ** ** If all of the above are false, then we can run this code just once ** save the results, and reuse the same result on subsequent invocations. */ if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){ int mem = ++pParse->nMem; sqlite3VdbeAddOp1(v, OP_SCopy, mem); testAddr = sqlite3VdbeAddOp0(v, OP_If); assert( testAddr>0 || pParse->db->mallocFailed ); sqlite3VdbeAddOp2(v, OP_Integer, 1, mem); } switch( pExpr->op ){ case TK_IN: { |
︙ | ︙ | |||
1962 1963 1964 1965 1966 1967 1968 | op = pExpr->op; } switch( op ){ case TK_AGG_COLUMN: { AggInfo *pAggInfo = pExpr->pAggInfo; struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; if( !pAggInfo->directMode ){ | | | | 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 | op = pExpr->op; } switch( op ){ case TK_AGG_COLUMN: { AggInfo *pAggInfo = pExpr->pAggInfo; struct AggInfo_col *pCol = &pAggInfo->aCol[pExpr->iAgg]; if( !pAggInfo->directMode ){ sqlite3VdbeAddOp1(v, OP_SCopy, pCol->iMem); break; }else if( pAggInfo->useSortingIdx ){ sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdx, pCol->iSorterColumn, target); inReg = 1; break; } /* Otherwise, fall thru into the TK_COLUMN case */ } case TK_COLUMN: { if( pExpr->iTable<0 ){ /* This only happens when coding check constraints */ assert( pParse->ckOffset>0 ); sqlite3VdbeAddOp1(v, OP_SCopy, -(pParse->ckOffset-pExpr->iColumn-1)); }else{ sqlite3ExprCodeGetColumn(v, pExpr->pTab, pExpr->iColumn, pExpr->iTable, target); inReg = 1; } break; } |
︙ | ︙ | |||
2025 2026 2027 2028 2029 2030 2031 | sqlite3VdbeAddOp1(v, OP_Variable, pExpr->iTable); if( pExpr->token.n>1 ){ sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n); } break; } case TK_REGISTER: { | | | 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 | sqlite3VdbeAddOp1(v, OP_Variable, pExpr->iTable); if( pExpr->token.n>1 ){ sqlite3VdbeChangeP4(v, -1, (char*)pExpr->token.z, pExpr->token.n); } break; } case TK_REGISTER: { sqlite3VdbeAddOp1(v, OP_SCopy, pExpr->iTable); break; } #ifndef SQLITE_OMIT_CAST case TK_CAST: { /* Expressions of the form: CAST(pLeft AS token) */ int aff, to_op; sqlite3ExprCode(pParse, pExpr->pLeft, 0); |
︙ | ︙ | |||
2134 2135 2136 2137 2138 2139 2140 | } case TK_AGG_FUNCTION: { AggInfo *pInfo = pExpr->pAggInfo; if( pInfo==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate: %T", &pExpr->span); }else{ | | | 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 | } case TK_AGG_FUNCTION: { AggInfo *pInfo = pExpr->pAggInfo; if( pInfo==0 ){ sqlite3ErrorMsg(pParse, "misuse of aggregate: %T", &pExpr->span); }else{ sqlite3VdbeAddOp1(v, OP_SCopy, pInfo->aFunc[pExpr->iAgg].iMem); } break; } case TK_CONST_FUNC: case TK_FUNCTION: { ExprList *pList = pExpr->pList; int nExpr = pList ? pList->nExpr : 0; |
︙ | ︙ | |||
2198 2199 2200 2201 2202 2203 2204 | } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { if( pExpr->iColumn==0 ){ sqlite3CodeSubselect(pParse, pExpr); } | | | 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 | } #ifndef SQLITE_OMIT_SUBQUERY case TK_EXISTS: case TK_SELECT: { if( pExpr->iColumn==0 ){ sqlite3CodeSubselect(pParse, pExpr); } sqlite3VdbeAddOp1(v, OP_SCopy, pExpr->iColumn); VdbeComment((v, "load subquery result")); break; } case TK_IN: { int addr; char affinity; int ckOffset = pParse->ckOffset; |
︙ | ︙ | |||
2250 2251 2252 2253 2254 2255 2256 | } #endif case TK_BETWEEN: { Expr *pLeft = pExpr->pLeft; struct ExprList_item *pLItem = pExpr->pList->a; Expr *pRight = pLItem->pExpr; sqlite3ExprCode(pParse, pLeft, 0); | | | 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 | } #endif case TK_BETWEEN: { Expr *pLeft = pExpr->pLeft; struct ExprList_item *pLItem = pExpr->pList->a; Expr *pRight = pLItem->pExpr; sqlite3ExprCode(pParse, pLeft, 0); sqlite3VdbeAddOp0(v, OP_Copy); sqlite3ExprCode(pParse, pRight, 0); codeCompare(pParse, pLeft, pRight, OP_Ge, 0, 0); sqlite3VdbeAddOp1(v, OP_Pull, 1); pLItem++; pRight = pLItem->pExpr; sqlite3ExprCode(pParse, pRight, 0); codeCompare(pParse, pLeft, pRight, OP_Le, 0, 0); |
︙ | ︙ | |||
2287 2288 2289 2290 2291 2292 2293 | expr_end_label = sqlite3VdbeMakeLabel(v); if( pExpr->pLeft ){ sqlite3ExprCode(pParse, pExpr->pLeft, 0); } for(i=0; i<nExpr; i=i+2){ sqlite3ExprCode(pParse, aListelem[i].pExpr, 0); if( pExpr->pLeft ){ | | | 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 | expr_end_label = sqlite3VdbeMakeLabel(v); if( pExpr->pLeft ){ sqlite3ExprCode(pParse, pExpr->pLeft, 0); } for(i=0; i<nExpr; i=i+2){ sqlite3ExprCode(pParse, aListelem[i].pExpr, 0); if( pExpr->pLeft ){ sqlite3VdbeAddOp1(v, OP_SCopy, -1); jumpInst = codeCompare(pParse, pExpr->pLeft, aListelem[i].pExpr, OP_Ne, 0, 1); sqlite3VdbeAddOp1(v, OP_Pop, 1); }else{ jumpInst = sqlite3VdbeAddOp2(v, OP_IfNot, 1, 0); } sqlite3ExprCode(pParse, aListelem[i+1].pExpr, 0); |
︙ | ︙ | |||
2335 2336 2337 2338 2339 2340 2341 | } stackChng = 0; break; } #endif } if( target && !inReg ){ | | | 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 | } stackChng = 0; break; } #endif } if( target && !inReg ){ sqlite3VdbeAddOp2(v, OP_Move, 0, target); stackChng = 0; } if( pParse->ckOffset ){ pParse->ckOffset += stackChng; assert( pParse->ckOffset ); } return target; |
︙ | ︙ | |||
2368 2369 2370 2371 2372 2373 2374 | if( v==0 ) return; addr1 = sqlite3VdbeCurrentAddr(v); sqlite3ExprCode(pParse, pExpr, 0); addr2 = sqlite3VdbeCurrentAddr(v); if( addr2>addr1+1 || ((pOp = sqlite3VdbeGetOp(v, addr1))!=0 && pOp->opcode==OP_Function) ){ iMem = pExpr->iTable = ++pParse->nMem; | | | 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 | if( v==0 ) return; addr1 = sqlite3VdbeCurrentAddr(v); sqlite3ExprCode(pParse, pExpr, 0); addr2 = sqlite3VdbeCurrentAddr(v); if( addr2>addr1+1 || ((pOp = sqlite3VdbeGetOp(v, addr1))!=0 && pOp->opcode==OP_Function) ){ iMem = pExpr->iTable = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Copy, 0, iMem); pExpr->op = TK_REGISTER; } } #endif /* ** Generate code that pushes the value of every element of the given |
︙ | ︙ | |||
2475 2476 2477 2478 2479 2480 2481 | ** 2 IF (x <= z) GOTO <dest> ** 3 ... */ int addr; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pList->a[0].pExpr; sqlite3ExprCode(pParse, pLeft, 0); | | | 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 | ** 2 IF (x <= z) GOTO <dest> ** 3 ... */ int addr; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pList->a[0].pExpr; sqlite3ExprCode(pParse, pLeft, 0); sqlite3VdbeAddOp0(v, OP_Copy); sqlite3ExprCode(pParse, pRight, 0); addr = codeCompare(pParse, pLeft, pRight, OP_Lt, 0, !jumpIfNull); pRight = pExpr->pList->a[1].pExpr; sqlite3ExprCode(pParse, pRight, 0); codeCompare(pParse, pLeft, pRight, OP_Le, dest, jumpIfNull); |
︙ | ︙ | |||
2587 2588 2589 2590 2591 2592 2593 | ** 2 GOTO <dest> ** 3 IF (x > z) GOTO <dest> */ int addr; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pList->a[0].pExpr; sqlite3ExprCode(pParse, pLeft, 0); | | | 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 | ** 2 GOTO <dest> ** 3 IF (x > z) GOTO <dest> */ int addr; Expr *pLeft = pExpr->pLeft; Expr *pRight = pExpr->pList->a[0].pExpr; sqlite3ExprCode(pParse, pLeft, 0); sqlite3VdbeAddOp0(v, OP_Copy); sqlite3ExprCode(pParse, pRight, 0); addr = sqlite3VdbeCurrentAddr(v); codeCompare(pParse, pLeft, pRight, OP_Ge, addr+3, !jumpIfNull); sqlite3VdbeAddOp2(v, OP_Pop, 1, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, dest); pRight = pExpr->pList->a[1].pExpr; |
︙ | ︙ |
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.212 2008/01/05 04:06:04 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: |
︙ | ︙ | |||
167 168 169 170 171 172 173 | memId = pParse->nMem; sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead); sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addr+12); sqlite3VdbeAddOp2(v, OP_Column, iCur, 0); sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->zName, 0); sqlite3VdbeAddOp2(v, OP_Ne, 0x100, addr+11); sqlite3VdbeAddOp2(v, OP_Rowid, iCur, 0); | | | | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | memId = pParse->nMem; sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenRead); sqlite3VdbeAddOp2(v, OP_Rewind, iCur, addr+12); sqlite3VdbeAddOp2(v, OP_Column, iCur, 0); sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->zName, 0); sqlite3VdbeAddOp2(v, OP_Ne, 0x100, addr+11); sqlite3VdbeAddOp2(v, OP_Rowid, iCur, 0); sqlite3VdbeAddOp2(v, OP_Move, 0, memId-1); sqlite3VdbeAddOp2(v, OP_Column, iCur, 1); sqlite3VdbeAddOp2(v, OP_Move, 0, memId); sqlite3VdbeAddOp2(v, OP_Goto, 0, addr+12); sqlite3VdbeAddOp2(v, OP_Next, iCur, addr+3); sqlite3VdbeAddOp2(v, OP_Close, iCur, 0); } return memId; } |
︙ | ︙ | |||
210 211 212 213 214 215 216 | int iCur = pParse->nTab; Vdbe *v = pParse->pVdbe; Db *pDb = &pParse->db->aDb[iDb]; int addr; assert( v ); addr = sqlite3VdbeCurrentAddr(v); sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); | | | | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | int iCur = pParse->nTab; Vdbe *v = pParse->pVdbe; Db *pDb = &pParse->db->aDb[iDb]; int addr; assert( v ); addr = sqlite3VdbeCurrentAddr(v); sqlite3OpenTable(pParse, iCur, iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); sqlite3VdbeAddOp2(v, OP_SCopy, memId-1, 0); sqlite3VdbeAddOp2(v, OP_NotNull, -1, addr+6); sqlite3VdbeAddOp2(v, OP_Pop, 1, 0); sqlite3VdbeAddOp1(v, OP_NewRowid, iCur); sqlite3VdbeAddOp4(v, OP_String8, 0, 0, 0, pTab->zName, 0); sqlite3VdbeAddOp2(v, OP_SCopy, memId, 0); sqlite3VdbeAddOp2(v, OP_MakeRecord, 2, 0); sqlite3CodeInsert(pParse, iCur, OPFLAG_APPEND); sqlite3VdbeAddOp2(v, OP_Close, iCur, 0); } } #else /* |
︙ | ︙ | |||
724 725 726 727 728 729 730 | /* The row that the VUpdate opcode will delete: none */ sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); } if( keyColumn>=0 ){ if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, iRowid); }else if( pSelect ){ | < < | | | < | 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 | /* The row that the VUpdate opcode will delete: none */ sqlite3VdbeAddOp2(v, OP_Null, 0, iReg); } if( keyColumn>=0 ){ if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, iRowid); }else if( pSelect ){ sqlite3VdbeAddOp2(v, OP_SCopy, -(nColumn - keyColumn - 1), iRowid); }else{ VdbeOp *pOp; sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0); pOp = sqlite3VdbeGetOp(v, sqlite3VdbeCurrentAddr(v) - 1); if( pOp && pOp->opcode==OP_Null ){ appendFlag = 1; pOp->opcode = OP_NewRowid; pOp->p1 = base; pOp->p2 = iRowid; pOp->p3 = counterMem; }else{ /* TODO: Avoid this use of the stack. */ sqlite3VdbeAddOp2(v, OP_Move, 0, iRowid); } } /* If the PRIMARY KEY expression is NULL, then use OP_NewRowid ** to generate a unique primary key value. */ if( !appendFlag ){ sqlite3VdbeAddOp2(v, OP_IfMemNull, iRowid, sqlite3VdbeCurrentAddr(v)+2); sqlite3VdbeAddOp2(v, OP_Goto, -1, sqlite3VdbeCurrentAddr(v)+2); sqlite3VdbeAddOp3(v, OP_NewRowid, base, iRowid, counterMem); sqlite3VdbeAddOp3(v, OP_MustBeInt, 0, 0, iRowid); } }else if( IsVirtual(pTab) ){ sqlite3VdbeAddOp2(v, OP_Null, 0, iRowid); }else{ sqlite3VdbeAddOp3(v, OP_NewRowid, base, iRowid, counterMem); appendFlag = 1; } autoIncStep(pParse, counterMem, iRowid); /* Push onto the stack, data for all columns of the new entry, beginning ** with the first column. */ |
︙ | ︙ | |||
792 793 794 795 796 797 798 | } } if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){ sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore); }else if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore); }else if( pSelect ){ | | < < | 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 | } } if( j<0 || nColumn==0 || (pColumn && j>=pColumn->nId) ){ sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, iRegStore); }else if( useTempTable ){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, iRegStore); }else if( pSelect ){ sqlite3VdbeAddOp2(v, OP_SCopy, -(nColumn-j-1), iRegStore); }else{ sqlite3ExprCode(pParse, pList->a[j].pExpr, iRegStore); } } /* Generate code to check constraints and generate index keys and ** do the insertion. |
︙ | ︙ | |||
1001 1002 1003 1004 1005 1006 1007 | onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){ onError = OE_Abort; } | | | 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 | onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( onError==OE_Replace && pTab->aCol[i].pDflt==0 ){ onError = OE_Abort; } sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol-1-i)); addr = sqlite3VdbeAddOp2(v, OP_NotNull, 1, 0); assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); switch( onError ){ case OE_Rollback: case OE_Abort: case OE_Fail: { |
︙ | ︙ | |||
1023 1024 1025 1026 1027 1028 1029 | case OE_Ignore: { sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0); | | | 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 | case OE_Ignore: { sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0); sqlite3VdbeAddOp1(v, OP_Push, nCol-i); break; } } sqlite3VdbeJumpHere(v, addr); } /* Test all CHECK constraints |
︙ | ︙ | |||
1064 1065 1066 1067 1068 1069 1070 | if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( isUpdate ){ | | | | | | | | | | | 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 | if( overrideError!=OE_Default ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( isUpdate ){ sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+1)); sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+1)); jumpInst1 = sqlite3VdbeAddOp2(v, OP_Eq, 0, 0); } sqlite3VdbeAddOp1(v, OP_SCopy, -nCol); jumpInst2 = sqlite3VdbeAddOp2(v, OP_NotExists, base, 0); switch( onError ){ default: { onError = OE_Abort; /* Fall thru into the next case */ } case OE_Rollback: case OE_Abort: case OE_Fail: { sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, "PRIMARY KEY must be unique", P4_STATIC); break; } case OE_Replace: { sqlite3GenerateRowIndexDelete(v, pTab, base, 0); if( isUpdate ){ sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+hasTwoRowids)); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); } seenReplace = 1; break; } case OE_Ignore: { assert( seenReplace==0 ); sqlite3VdbeAddOp2(v, OP_Pop, nCol+1+hasTwoRowids, 0); sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } } sqlite3VdbeJumpHere(v, jumpInst2); if( isUpdate ){ sqlite3VdbeJumpHere(v, jumpInst1); sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+1)); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); } } /* Test all UNIQUE constraints by creating entries for each UNIQUE ** index and making sure that duplicate entries do not already exist. ** Add the new records to the indices as we go. */ extra = -1; for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){ if( aIdxUsed && aIdxUsed[iCur]==0 ) continue; /* Skip unused indices */ extra++; /* Create a key for accessing the index entry */ sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+extra)); for(i=0; i<pIdx->nColumn; i++){ int idx = pIdx->aiColumn[i]; if( idx==pTab->iPKey ){ sqlite3VdbeAddOp1(v, OP_SCopy, -(i+extra+nCol+1)); }else{ sqlite3VdbeAddOp1(v, OP_SCopy, -(i+extra+nCol-idx)); } } jumpInst1 = sqlite3VdbeAddOp2(v, OP_MakeIdxRec, pIdx->nColumn, 0); sqlite3IndexAffinityStr(v, pIdx); /* 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 ){ onError = overrideError; }else if( onError==OE_Default ){ onError = OE_Abort; } if( seenReplace ){ if( onError==OE_Ignore ) onError = OE_Replace; else if( onError==OE_Fail ) onError = OE_Abort; } /* Check to see if the new index entry will be unique */ sqlite3VdbeAddOp1(v, OP_SCopy, -(extra+nCol+1+hasTwoRowids)); jumpInst2 = sqlite3VdbeAddOp2(v, OP_IsUnique, base+iCur+1, 0); /* Generate code that executes if the new index entry is not unique */ assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail || onError==OE_Ignore || onError==OE_Replace ); switch( onError ){ case OE_Rollback: |
︙ | ︙ | |||
1189 1190 1191 1192 1193 1194 1195 | sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { int iRowid = sqlite3StackToReg(pParse, 1); sqlite3GenerateRowDelete(pParse->db, v, pTab, base, iRowid, 0); if( isUpdate ){ | | | 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 | sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest); break; } case OE_Replace: { int iRowid = sqlite3StackToReg(pParse, 1); sqlite3GenerateRowDelete(pParse->db, v, pTab, base, iRowid, 0); if( isUpdate ){ sqlite3VdbeAddOp1(v, OP_SCopy, -(nCol+extra+1+hasTwoRowids)); sqlite3VdbeAddOp2(v, OP_MoveGe, base, 0); } seenReplace = 1; break; } } #if NULL_DISTINCT_FOR_UNIQUE |
︙ | ︙ | |||
1241 1242 1243 1244 1245 1246 1247 | if( aIdxUsed && aIdxUsed[i]==0 ) continue; sqlite3VdbeAddOp2(v, OP_IdxInsert, base+i+1, 0); } sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0); sqlite3TableAffinityStr(v, pTab); #ifndef SQLITE_OMIT_TRIGGER if( newIdx>=0 ){ | | | | 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 | if( aIdxUsed && aIdxUsed[i]==0 ) continue; sqlite3VdbeAddOp2(v, OP_IdxInsert, base+i+1, 0); } sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0); sqlite3TableAffinityStr(v, pTab); #ifndef SQLITE_OMIT_TRIGGER if( newIdx>=0 ){ sqlite3VdbeAddOp1(v, OP_Copy, -1); sqlite3VdbeAddOp1(v, OP_Copy, -1); sqlite3CodeInsert(pParse, newIdx, 0); } #endif if( pParse->nested ){ pik_flags = 0; }else{ pik_flags = OPFLAG_NCHANGE; |
︙ | ︙ | |||
1562 1563 1564 1565 1566 1567 1568 | }else{ emptyDestTest = 0; } sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, 0); | | | 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 | }else{ emptyDestTest = 0; } sqlite3OpenTable(pParse, iSrc, iDbSrc, pSrc, OP_OpenRead); emptySrcTest = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); if( pDest->iPKey>=0 ){ addr1 = sqlite3VdbeAddOp2(v, OP_Rowid, iSrc, 0); sqlite3VdbeAddOp0(v, OP_Copy); addr2 = sqlite3VdbeAddOp2(v, OP_NotExists, iDest, 0); sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0, "PRIMARY KEY must be unique", P4_STATIC); sqlite3VdbeJumpHere(v, addr2); autoIncStep(pParse, counterMem, 0); }else if( pDest->pIndex==0 ){ addr1 = sqlite3VdbeAddOp1(v, OP_NewRowid, iDest); |
︙ | ︙ |
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.159 2008/01/05 04:06:04 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) |
︙ | ︙ | |||
296 297 298 299 300 301 302 | ** synchronous setting. A negative value means synchronous is off ** and a positive value means synchronous is on. */ if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){ static const VdbeOpList getCacheSize[] = { { OP_ReadCookie, 0, 0, 2}, /* 0 */ { OP_AbsValue, 0, 0, 0}, | | | 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | ** synchronous setting. A negative value means synchronous is off ** and a positive value means synchronous is on. */ if( sqlite3StrICmp(zLeft,"default_cache_size")==0 ){ static const VdbeOpList getCacheSize[] = { { OP_ReadCookie, 0, 0, 2}, /* 0 */ { OP_AbsValue, 0, 0, 0}, { OP_Copy, 0, 0, 0}, { OP_Integer, 0, 0, 0}, { OP_Ne, 0, 6, 0}, { OP_Integer, 0, 0, 0}, /* 5 */ { OP_Callback, 1, 0, 0}, }; int addr; if( sqlite3ReadSchema(pParse) ) goto pragma_out; |
︙ | ︙ | |||
826 827 828 829 830 831 832 | int i, j, addr, mxErr; /* Code that appears at the end of the integrity check. If no error ** messages have been generated, output OK. Otherwise output the ** error message */ static const VdbeOpList endCode[] = { | | | 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 | int i, j, addr, mxErr; /* Code that appears at the end of the integrity check. If no error ** messages have been generated, output OK. Otherwise output the ** error message */ static const VdbeOpList endCode[] = { { OP_SCopy, 1, 0, 0}, { OP_Integer, 0, 0, 0}, { OP_Ne, 0, 0, 0}, /* 2 */ { OP_String8, 0, 0, 0}, /* 3 */ { OP_Callback, 1, 0, 0}, }; int isQuick = (zLeft[0]=='q'); |
︙ | ︙ | |||
929 930 931 932 933 934 935 | sqlite3VdbeJumpHere(v, loopTop); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ static const VdbeOpList cntIdx[] = { { OP_Integer, 0, 3, 0}, { OP_Rewind, 0, 0, 0}, /* 1 */ { OP_MemIncr, 1, 3, 0}, { OP_Next, 0, 0, 0}, /* 3 */ | | | | 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 | sqlite3VdbeJumpHere(v, loopTop); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ static const VdbeOpList cntIdx[] = { { OP_Integer, 0, 3, 0}, { OP_Rewind, 0, 0, 0}, /* 1 */ { OP_MemIncr, 1, 3, 0}, { OP_Next, 0, 0, 0}, /* 3 */ { OP_SCopy, 2, 0, 0}, { OP_SCopy, 3, 0, 0}, { OP_Eq, 0, 0, 0}, /* 6 */ { OP_MemIncr, -1, 1, 0}, { OP_String8, 0, 0, 0}, /* 8 */ { OP_String8, 0, 0, 0}, /* 9 */ { OP_Concat, 0, 0, 0}, { OP_Callback, 1, 0, 0}, }; |
︙ | ︙ |
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.385 2008/01/05 04:06:04 drh Exp $ */ #include "sqliteInt.h" /* ** Delete all the content of a Select structure but do not deallocate ** the select structure itself. |
︙ | ︙ | |||
630 631 632 633 634 635 636 | addr2 = sqlite3VdbeAddOp2(v, OP_IfMemNull, iMem+1, 0); p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affinity); if( pOrderBy ){ /* 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 */ | | | 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 | addr2 = sqlite3VdbeAddOp2(v, OP_IfMemNull, iMem+1, 0); p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr, pDest->affinity); if( pOrderBy ){ /* 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 */ sqlite3VdbeAddOp2(v, OP_SCopy, iMem+1, 0); pushOntoSorter(pParse, pOrderBy, p); }else{ sqlite3VdbeAddOp4(v, OP_RegMakeRec, iMem, 0, 0, &p->affinity, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0); } sqlite3VdbeJumpHere(v, addr2); break; |
︙ | ︙ | |||
654 655 656 657 658 659 660 | /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. */ case SRT_Mem: { assert( nColumn==1 ); | | | | | 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. */ case SRT_Mem: { assert( nColumn==1 ); sqlite3VdbeAddOp2(v, OP_SCopy, iMem+1, 0); if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p); }else{ sqlite3VdbeAddOp2(v, OP_Move, 0, iParm); /* The LIMIT clause will jump out of the loop for us */ } break; } #endif /* #ifndef SQLITE_OMIT_SUBQUERY */ /* Send the data to the callback function or to a subroutine. In the ** case of a subroutine, the subroutine itself is responsible for ** popping the data from the stack. */ case SRT_Subroutine: case SRT_Callback: { if( pOrderBy ){ sqlite3VdbeAddOp2(v, OP_RegMakeRec, iMem, 0); pushOntoSorter(pParse, pOrderBy, p); }else if( eDest==SRT_Subroutine ){ for(i=0; i<nColumn; i++) sqlite3VdbeAddOp2(v, OP_SCopy, iMem+i+1, 0); sqlite3VdbeAddOp2(v, OP_Gosub, 0, iParm); }else{ sqlite3VdbeAddOp2(v, OP_ResultRow, iMem+1, nColumn); } break; } |
︙ | ︙ | |||
802 803 804 805 806 807 808 | sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &p->affinity, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0); break; } case SRT_Mem: { assert( nColumn==1 ); | | | 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 | sqlite3VdbeAddOp2(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp4(v, OP_MakeRecord, 1, 0, 0, &p->affinity, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, iParm, 0); break; } case SRT_Mem: { assert( nColumn==1 ); sqlite3VdbeAddOp2(v, OP_Move, 0, iParm); /* The LIMIT clause will terminate the loop for us */ break; } #endif case SRT_Callback: case SRT_Subroutine: { int i; |
︙ | ︙ | |||
1748 1749 1750 1751 1752 1753 1754 | if( p->pLimit ){ p->iLimit = iLimit = ++pParse->nMem; pParse->nMem++; v = sqlite3GetVdbe(pParse); if( v==0 ) return; sqlite3ExprCode(pParse, p->pLimit, 0); sqlite3VdbeAddOp2(v, OP_MustBeInt, 0, 0); | | | | | | 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 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 | if( p->pLimit ){ p->iLimit = iLimit = ++pParse->nMem; pParse->nMem++; v = sqlite3GetVdbe(pParse); if( v==0 ) return; sqlite3ExprCode(pParse, p->pLimit, 0); sqlite3VdbeAddOp2(v, OP_MustBeInt, 0, 0); sqlite3VdbeAddOp2(v, OP_Move, 0, iLimit); VdbeComment((v, "LIMIT counter")); sqlite3VdbeAddOp2(v, OP_IfMemZero, iLimit, iBreak); sqlite3VdbeAddOp2(v, OP_SCopy, iLimit, 0); } if( p->pOffset ){ p->iOffset = iOffset = ++pParse->nMem; v = sqlite3GetVdbe(pParse); if( v==0 ) return; sqlite3ExprCode(pParse, p->pOffset, 0); sqlite3VdbeAddOp2(v, OP_MustBeInt, 0, 0); sqlite3VdbeAddOp2(v, p->pLimit==0 ? OP_Move : OP_Copy, 0, iOffset); VdbeComment((v, "OFFSET counter")); addr1 = sqlite3VdbeAddOp2(v, OP_IfMemPos, iOffset, 0); sqlite3VdbeAddOp2(v, OP_Pop, 1, 0); sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); sqlite3VdbeJumpHere(v, addr1); if( p->pLimit ){ sqlite3VdbeAddOp2(v, OP_Add, 0, 0); } } if( p->pLimit ){ addr1 = sqlite3VdbeAddOp2(v, OP_IfMemPos, iLimit, 0); sqlite3VdbeAddOp2(v, OP_Pop, 1, 0); sqlite3VdbeAddOp2(v, OP_Integer, -1, iLimit+1); addr2 = sqlite3VdbeAddOp2(v, OP_Goto, 0, 0); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Move, 0, iLimit+1); VdbeComment((v, "LIMIT+OFFSET")); sqlite3VdbeJumpHere(v, addr2); } } /* ** Allocate a virtual index to use for sorting. |
︙ | ︙ | |||
3543 3544 3545 3546 3547 3548 3549 | for(j=0; j<pGroupBy->nExpr; j++){ if( groupBySort ){ sqlite3VdbeAddOp2(v, OP_Column, sAggInfo.sortingIdx, j); }else{ sAggInfo.directMode = 1; sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, 0); } | | | | | | 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 | for(j=0; j<pGroupBy->nExpr; j++){ if( groupBySort ){ sqlite3VdbeAddOp2(v, OP_Column, sAggInfo.sortingIdx, j); }else{ sAggInfo.directMode = 1; sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, 0); } sqlite3VdbeAddOp2(v, j<pGroupBy->nExpr-1?OP_Move:OP_Copy, 0, iBMem+j); } for(j=pGroupBy->nExpr-1; j>=0; j--){ if( j<pGroupBy->nExpr-1 ){ sqlite3VdbeAddOp2(v, OP_SCopy, iBMem+j, 0); } sqlite3VdbeAddOp2(v, OP_SCopy, iAMem+j, 0); if( j==0 ){ sqlite3VdbeAddOp2(v, OP_Eq, 0x200, addrProcessRow); }else{ sqlite3VdbeAddOp2(v, OP_Ne, 0x200, addrGroupByChange); } sqlite3VdbeChangeP4(v, -1, (void*)pKeyInfo->aColl[j], P4_COLLSEQ); } /* Generate code that runs whenever the GROUP BY changes. ** Change in the GROUP BY are detected by the previous code ** block. If there were no changes, this block is skipped. ** ** This code copies current group by terms in b0,b1,b2,... ** over to a0,a1,a2. It then calls the output subroutine ** and resets the aggregate accumulator registers in preparation ** for the next GROUP BY batch. */ sqlite3VdbeResolveLabel(v, addrGroupByChange); for(j=0; j<pGroupBy->nExpr; j++){ sqlite3VdbeAddOp2(v, OP_Move, iBMem+j, iAMem+j); } sqlite3VdbeAddOp2(v, OP_Gosub, 0, addrOutputRow); VdbeComment((v, "output one row")); sqlite3VdbeAddOp2(v, OP_IfMemPos, iAbortFlag, addrEnd); VdbeComment((v, "check abort flag")); sqlite3VdbeAddOp2(v, OP_Gosub, 0, addrReset); VdbeComment((v, "reset accumulator")); |
︙ | ︙ |
Changes to src/trigger.c.
︙ | ︙ | |||
233 234 235 236 237 238 239 | { OP_String8, 0, 0, 0 }, /* 2: trigger name */ { OP_String8, 0, 0, 0 }, /* 3: table name */ { OP_Integer, 0, 0, 0 }, { OP_String8, 0, 0, 0 }, /* 5: "CREATE TRIGGER " */ { OP_String8, 0, 0, 0 }, /* 6: SQL */ { OP_Concat, 0, 0, 0 }, { OP_MakeRecord, 5, 0, 0 }, /* 8: "aaada" */ | | | | | | | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | { OP_String8, 0, 0, 0 }, /* 2: trigger name */ { OP_String8, 0, 0, 0 }, /* 3: table name */ { OP_Integer, 0, 0, 0 }, { OP_String8, 0, 0, 0 }, /* 5: "CREATE TRIGGER " */ { OP_String8, 0, 0, 0 }, /* 6: SQL */ { OP_Concat, 0, 0, 0 }, { OP_MakeRecord, 5, 0, 0 }, /* 8: "aaada" */ { OP_Move, 0, 0, 0 }, /* 9: Store data */ { OP_Move, 0, 0, 0 }, /* 10: Store key */ { OP_Insert, 0, 0, 0 }, }; int addr; Vdbe *v; int iKey = ++pParse->nMem; int iData = ++pParse->nMem; /* Make an entry in the sqlite_master table */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto triggerfinish_cleanup; sqlite3BeginWriteOperation(pParse, 0, iDb); sqlite3OpenMasterTable(pParse, iDb); addr = sqlite3VdbeAddOpList(v, ArraySize(insertTrig), insertTrig); sqlite3VdbeChangeP4(v, addr+1, "trigger", P4_STATIC); sqlite3VdbeChangeP4(v, addr+2, pTrig->name, 0); sqlite3VdbeChangeP4(v, addr+3, pTrig->table, 0); sqlite3VdbeChangeP4(v, addr+5, "CREATE TRIGGER ", P4_STATIC); sqlite3VdbeChangeP4(v, addr+6, (char*)pAll->z, pAll->n); sqlite3VdbeChangeP4(v, addr+8, "aaada", P4_STATIC); sqlite3VdbeChangeP2(v, addr+9, iData); sqlite3VdbeChangeP2(v, addr+10, iKey); sqlite3VdbeChangeP2(v, addr+11, iData); sqlite3VdbeChangeP3(v, addr+11, iKey); sqlite3ChangeCookie(db, v, iDb); sqlite3VdbeAddOp2(v, OP_Close, 0, 0); sqlite3VdbeAddOp4(v, OP_ParseSchema, iDb, 0, 0, sqlite3MPrintf( db, "type='trigger' AND name='%q'", pTrig->name), P4_DYNAMIC ); } |
︙ | ︙ |
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.159 2008/01/05 04:06:04 drh Exp $ */ #include "sqliteInt.h" #ifndef SQLITE_OMIT_VIRTUALTABLE /* Forward declaration */ static void updateVirtualTable( Parse *pParse, /* The parsing context */ |
︙ | ︙ | |||
452 453 454 455 456 457 458 | /* Loop over every record that needs updating. We have to load ** the old data for each record to be updated because some columns ** might not change and we will need to copy the old value. ** Also, the old data is needed to delete the old index entries. ** So make the cursor point at the old record. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid); | | | 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 | /* Loop over every record that needs updating. We have to load ** the old data for each record to be updated because some columns ** might not change and we will need to copy the old value. ** Also, the old data is needed to delete the old index entries. ** So make the cursor point at the old record. */ sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addr, iRowid); sqlite3VdbeAddOp2(v, OP_SCopy, iRowid, 0); /* If the record number will change, push the record number as it ** will be after the update. (The old record number is currently ** on top of the stack.) */ if( chngRowid ){ sqlite3ExprCode(pParse, pRowidExpr, 0); |
︙ | ︙ |
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.680 2008/01/05 04:06:04 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> #include "vdbeInt.h" /* ** The following global variable is incremented every time a cursor |
︙ | ︙ | |||
466 467 468 469 470 471 472 473 474 475 476 477 478 479 | int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ u8 encoding = ENC(db); /* The database encoding */ Mem *pTos; /* Top entry in the operand stack */ Mem *pIn1, *pIn2; /* Input operands */ Mem *pOut; /* Output operand */ int nPop = 0; /* Number of times to pop the stack */ #ifdef VDBE_PROFILE unsigned long long start; /* CPU clock count at start of opcode */ int origPc; /* Program counter at start of opcode */ #endif #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int nProgressOps = 0; /* Opcodes executed since progress callback. */ #endif | > | 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 | int rc = SQLITE_OK; /* Value to return */ sqlite3 *db = p->db; /* The database */ u8 encoding = ENC(db); /* The database encoding */ Mem *pTos; /* Top entry in the operand stack */ Mem *pIn1, *pIn2; /* Input operands */ Mem *pOut; /* Output operand */ int nPop = 0; /* Number of times to pop the stack */ u8 opProperty; #ifdef VDBE_PROFILE unsigned long long start; /* CPU clock count at start of opcode */ int origPc; /* Program counter at start of opcode */ #endif #ifndef SQLITE_OMIT_PROGRESS_CALLBACK int nProgressOps = 0; /* Opcodes executed since progress callback. */ #endif |
︙ | ︙ | |||
592 593 594 595 596 597 598 | /* Do common setup processing for any opcode that is marked ** with the "out2-prerelease" tag. Such opcodes have a single ** output which is specified by the P2 parameter. The output ** is normally written into the P2-th register. But if P2==0 ** then the output is pushed onto the stack. The P2 operand ** is initialized to a NULL. */ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 | /* Do common setup processing for any opcode that is marked ** with the "out2-prerelease" tag. Such opcodes have a single ** output which is specified by the P2 parameter. The output ** is normally written into the P2-th register. But if P2==0 ** then the output is pushed onto the stack. The P2 operand ** is initialized to a NULL. */ opProperty = opcodeProperty[pOp->opcode]; if( (opProperty & OPFLG_OUT2_PRERELEASE)!=0 ){ assert( pOp->p2>=0 ); if( pOp->p2==0 ){ pOut = ++pTos; }else{ assert( pOp->p2<=p->nMem ); pOut = &p->aMem[pOp->p2]; sqlite3VdbeMemRelease(pOut); } pOut->flags = MEM_Null; }else /* Do common setup for opcodes marked with one of the following ** combinations of properties. ** ** in1 ** in1 in2 ** in1 in2 out3 ** in1 in3 ** in1 out2 ** ** Variables pIn1 and pIn2 are made to point to the first two ** inputs and pOut points to the output. Variable nPop holds the ** number of times that the stack should be popped after the ** the instruction. */ if( (opProperty & OPFLG_IN1)!=0 ){ assert( pOp->p1>=0 ); if( pOp->p1==0 ){ pIn1 = pTos; nPop = 1; }else{ assert( pOp->p1<=p->nMem ); pIn1 = &p->aMem[pOp->p1]; } if( (opProperty & OPFLG_IN2)!=0 ){ assert( pOp->p2>=0 ); if( pOp->p2==0 ){ pIn2 = &pTos[-nPop]; nPop++; }else{ assert( pOp->p2<=p->nMem ); pIn2 = &p->aMem[pOp->p2]; } if( (opProperty & OPFLG_OUT3)!=0 ){ assert( pOp->p3>=0 ); if( pOp->p3==0 ){ pTos++; pOut = &pTos[-nPop]; pOut->flags = MEM_Null; }else{ assert( pOp->p3<=p->nMem ); pOut = &p->aMem[pOp->p3]; } } }else if( (opProperty & OPFLG_IN3)!=0 ){ assert( pOp->p3>=0 ); if( pOp->p3==0 ){ pIn2 = &pTos[-nPop]; nPop++; }else{ assert( pOp->p3<=p->nMem ); pIn2 = &p->aMem[pOp->p3]; } }else if( (opProperty & OPFLG_OUT2)!=0 ){ assert( pOp->p2>=0 ); if( pOp->p2==0 ){ pTos++; pOut = &pTos[-nPop]; pOut->flags = MEM_Null; }else{ assert( pOp->p2<=p->nMem ); pOut = &p->aMem[pOp->p2]; } } } switch( pOp->opcode ){ /***************************************************************************** ** What follows is a massive switch statement where each case implements a ** separate instruction in the virtual machine. If we follow the usual |
︙ | ︙ | |||
922 923 924 925 926 927 928 | case OP_Pop: { /* no-push */ assert( pOp->p1>=0 ); popStack(&pTos, pOp->p1); assert( pTos>=&p->aStack[-1] ); break; } | | > | > > > > | > | > > > > > | > > | > | > | | > > > > > > > > > | | > > > > > > | > > > | | > > > > > > | > > > > > > > > > | | | > < < | 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 | case OP_Pop: { /* no-push */ assert( pOp->p1>=0 ); popStack(&pTos, pOp->p1); assert( pTos>=&p->aStack[-1] ); break; } /* Opcode: Move P1 P2 * * * ** ** Move the value in P1 into P2. If P1 is positive then read from the ** P1-th register. If P1 is zero or negative read from the stack. ** When P1 is 0 read from the top the stack. When P1 is -1 read from ** the next entry down on the stack. And so forth. ** ** If P2 is zero, push the new value onto the top of the stack. ** If P2 is positive, write into the P2-th register. ** ** If P1 is zero then the stack is popped once. The stack is ** unchanged for all other values of P1. The P1 value contains ** a NULL after this operation. */ /* Opcode: Copy P1 P2 * * * ** ** Make a copy of P1 into P2. If P1 is positive then read from the ** P1-th register. If P1 is zero or negative read from the stack. ** When P1 is 0 read from the top the stack. When P1 is -1 read from ** the next entry down on the stack. And so forth. ** ** If P2 is zero, push the new value onto the top of the stack. ** If P2 is positive, write into the P2-th register. ** ** This instruction makes a deep copy of the value. A duplicate ** is made of any string or blob constant. See also OP_SCopy. */ /* Opcode: SCopy P1 P2 * * * ** ** Make a shallow copy of P1 into P2. If P1 is positive then read from the ** P1-th register. If P1 is zero or negative read from the stack. ** When P1 is 0 read from the top the stack. When P1 is -1 read from ** the next entry down on the stack. And so forth. ** ** If P2 is zero, push the new value onto the top of the stack. ** If P2 is positive, write into the P2-th register. ** ** This instruction makes a shallow copy of the value. If the value ** is a string or blob, then the copy is only a pointer to the ** original and hence if the original changes so will the copy. ** Worse, if the original is deallocated, the copy becomes invalid. ** Thus the program must guarantee that the original will not change ** during the lifetime of the copy. Use OP_Copy to make a complete ** copy. */ case OP_Move: case OP_Copy: case OP_SCopy: { if( pOp->p1<=0 ){ pIn1 = &pTos[pOp->p1]; assert( pIn1>=p->aStack ); }else{ assert( pOp->p1<=p->nMem ); pIn1 = &p->aMem[pOp->p1]; } assert( pOp->p2>=0 ); if( pOp->p2==0 ){ pOut = ++pTos; pOut->flags = MEM_Null; }else{ assert( pOp->p2<=p->nMem ); pOut = &p->aMem[pOp->p2]; } if( pOp->opcode==OP_Move ){ rc = sqlite3VdbeMemMove(pOut, pIn1); if( pOp->p1==0 ) pTos--; }else{ sqlite3VdbeMemShallowCopy(pOut, pIn1, MEM_Ephem); if( pOp->opcode==OP_Copy ){ Deephemeralize(pOut); } } break; } /* Opcode: Pull P1 * * ** ** The P1-th element is removed from its current location on ** the stack and pushed back on top of the stack. The ** top of the stack is element 0, so "Pull 0 0 0" is ** a no-op. "Pull 1 0 0" swaps the top two elements of ** the stack. */ case OP_Pull: { /* no-push */ Mem *pFrom = &pTos[-pOp->p1]; int i; Mem ts; ts = *pFrom; |
︙ | ︙ | |||
2677 2678 2679 2680 2681 2682 2683 | if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){ goto abort_due_to_error; } } break; } | | | 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 | if( rc!=SQLITE_OK && rc!=SQLITE_READONLY /* && rc!=SQLITE_BUSY */ ){ goto abort_due_to_error; } } break; } /* Opcode: ReadCookie P1 P2 P3 * * ** ** Read cookie number P3 from database P1 and write it into register ** P2 or push it onto the stack if P2==0. ** P3==0 is the schema version. P3==1 is the database format. ** P3==2 is the recommended pager cache size, and so forth. P1==0 is ** the main database file and P1==1 is the database file used to store ** temporary tables. |
︙ | ︙ | |||
4611 4612 4613 4614 4615 4616 4617 | p->nChange = pContext->nChange; sqlite3VdbeFifoClear(&p->sFifo); p->sFifo = pContext->sFifo; break; } #endif /* #ifndef SQLITE_OMIT_TRIGGER */ | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 | p->nChange = pContext->nChange; sqlite3VdbeFifoClear(&p->sFifo); p->sFifo = pContext->sFifo; break; } #endif /* #ifndef SQLITE_OMIT_TRIGGER */ #ifndef SQLITE_OMIT_AUTOINCREMENT /* Opcode: MemMax P1 P2 * ** ** Set the value of memory cell P1 to the maximum of its current value ** and the value in cell P2, or the value on the top of the stack if P2 ** is zero. The stack is unchanged in either case. ** |
︙ | ︙ | |||
4764 4765 4766 4767 4768 4769 4770 | assert( i>0 && i<=p->nMem ); if( p->aMem[i].flags & MEM_Null ){ pc = pOp->p2 - 1; } break; } | < < < < < < < < < < < < < | 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 | assert( i>0 && i<=p->nMem ); if( p->aMem[i].flags & MEM_Null ){ pc = pOp->p2 - 1; } break; } /* Opcode: AggStep P1 P2 P4 ** ** Execute the step function for an aggregate. The ** function has P2 arguments. P4 is a pointer to the FuncDef ** structure that specifies the function. Use memory location ** P1 as the accumulator. ** |
︙ | ︙ | |||
5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 | /***************************************************************************** ** The cases of the switch statement above this line should all be indented ** by 6 spaces. But the left-most 6 spaces have been removed to improve the ** readability. From this point on down, the normal indentation rules are ** restored. *****************************************************************************/ } /* Make sure the stack limit was not exceeded */ assert( pTos>=&p->aStack[-1] && pTos<=pStackLimit ); #ifdef VDBE_PROFILE { long long elapse = hwtime() - start; | > > > > > > | 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 | /***************************************************************************** ** The cases of the switch statement above this line should all be indented ** by 6 spaces. But the left-most 6 spaces have been removed to improve the ** readability. From this point on down, the normal indentation rules are ** restored. *****************************************************************************/ } /* Pop the stack if necessary */ if( nPop ){ popStack(&pTos, nPop); nPop = 0; } /* Make sure the stack limit was not exceeded */ assert( pTos>=&p->aStack[-1] && pTos<=pStackLimit ); #ifdef VDBE_PROFILE { long long elapse = hwtime() - start; |
︙ | ︙ |
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.274 2008/01/05 04:06:04 drh Exp $ */ #include "sqliteInt.h" /* ** The number of bits in a Bitmask. "BMS" means "BitMask Size". */ #define BMS (sizeof(Bitmask)*8) |
︙ | ︙ | |||
1823 1824 1825 1826 1827 1828 1829 | if( pTerm==0 ) break; assert( (pTerm->flags & TERM_CODED)==0 ); codeEqualityTerm(pParse, pTerm, pLevel); if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ sqlite3VdbeAddOp2(v, OP_IsNull, termsInMem ? -1 : -(j+1), pLevel->brk); } if( termsInMem ){ | | | | 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 | if( pTerm==0 ) break; assert( (pTerm->flags & TERM_CODED)==0 ); codeEqualityTerm(pParse, pTerm, pLevel); if( (pTerm->eOperator & (WO_ISNULL|WO_IN))==0 ){ sqlite3VdbeAddOp2(v, OP_IsNull, termsInMem ? -1 : -(j+1), pLevel->brk); } if( termsInMem ){ sqlite3VdbeAddOp2(v, OP_Move, 0, pLevel->iMem+j+1); } } /* Make sure all the constraint values are on the top of the stack */ if( termsInMem ){ for(j=0; j<nEq; j++){ sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem+j+1, 0); } } } #if defined(SQLITE_TEST) /* ** The following variable holds a text description of query plan generated |
︙ | ︙ | |||
2358 2359 2360 2361 2362 2363 2364 | if( pEnd ){ Expr *pX; pX = pEnd->pExpr; assert( pX!=0 ); assert( pEnd->leftCursor==iCur ); sqlite3ExprCode(pParse, pX->pRight, 0); pLevel->iMem = ++pParse->nMem; | | | | 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 | if( pEnd ){ Expr *pX; pX = pEnd->pExpr; assert( pX!=0 ); assert( pEnd->leftCursor==iCur ); sqlite3ExprCode(pParse, pX->pRight, 0); pLevel->iMem = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Move, 0, 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 ){ sqlite3VdbeAddOp2(v, OP_Rowid, iCur, 0); sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); sqlite3VdbeAddOp2(v, testOp, SQLITE_AFF_NUMERIC|0x100, brk); } }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 |
︙ | ︙ | |||
2406 2407 2408 2409 2410 2411 2412 | codeAllEqualityTerms(pParse, pLevel, &wc, notReady); /* Duplicate the equality term values because they will all be ** used twice: once to make the termination key and once to make the ** start key. */ for(j=0; j<nEq; j++){ | | | 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 | codeAllEqualityTerms(pParse, pLevel, &wc, notReady); /* Duplicate the equality term values because they will all be ** used twice: once to make the termination key and once to make the ** start key. */ for(j=0; j<nEq; j++){ sqlite3VdbeAddOp1(v, OP_Copy, 1-nEq); } /* 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. */ |
︙ | ︙ | |||
2455 2456 2457 2458 2459 2460 2461 | int nCol = nEq + topLimit; pLevel->iMem = ++pParse->nMem; buildIndexProbe(v, nCol, pIdx); if( bRev ){ int op = topEq ? OP_MoveLe : OP_MoveLt; sqlite3VdbeAddOp2(v, op, iIdxCur, nxt); }else{ | | | 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 | int nCol = nEq + topLimit; pLevel->iMem = ++pParse->nMem; buildIndexProbe(v, nCol, pIdx); if( bRev ){ int op = topEq ? OP_MoveLe : OP_MoveLt; sqlite3VdbeAddOp2(v, op, iIdxCur, nxt); }else{ sqlite3VdbeAddOp2(v, OP_Move, 0, 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 |
︙ | ︙ | |||
2489 2490 2491 2492 2493 2494 2495 | btmEq = 1; } if( nEq>0 || btmLimit ){ int nCol = nEq + btmLimit; buildIndexProbe(v, nCol, pIdx); if( bRev ){ pLevel->iMem = ++pParse->nMem; | | | | 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 | btmEq = 1; } if( nEq>0 || btmLimit ){ int nCol = nEq + btmLimit; buildIndexProbe(v, nCol, pIdx); if( bRev ){ pLevel->iMem = ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Move, 0, pLevel->iMem); testOp = OP_IdxLT; }else{ int op = btmEq ? OP_MoveGe : OP_MoveGt; sqlite3VdbeAddOp2(v, op, iIdxCur, nxt); } }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 ){ sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); sqlite3VdbeAddOp2(v, testOp, iIdxCur, nxt); if( (topEq && !bRev) || (!btmEq && bRev) ){ sqlite3VdbeChangeP4(v, -1, "+", P4_STATIC); } } if( topLimit | btmLimit ){ sqlite3VdbeAddOp2(v, OP_Column, iIdxCur, nEq); |
︙ | ︙ | |||
2544 2545 2546 2547 2548 2549 2550 | codeAllEqualityTerms(pParse, pLevel, &wc, notReady); nxt = pLevel->nxt; /* Generate a single key that will be used to both start and terminate ** the search */ buildIndexProbe(v, nEq, pIdx); | | | | | 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 | codeAllEqualityTerms(pParse, pLevel, &wc, notReady); nxt = pLevel->nxt; /* Generate a single key that will be used to both start and terminate ** the search */ buildIndexProbe(v, nEq, pIdx); sqlite3VdbeAddOp2(v, OP_Copy, 0, pLevel->iMem); /* 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 */ sqlite3VdbeAddOp2(v, OP_MoveLe, iIdxCur, nxt); start = sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); sqlite3VdbeAddOp2(v, OP_IdxLT, iIdxCur, nxt); pLevel->op = OP_Prev; }else{ /* Scan in the forward order */ sqlite3VdbeAddOp2(v, OP_MoveGe, iIdxCur, nxt); start = sqlite3VdbeAddOp2(v, OP_SCopy, pLevel->iMem, 0); sqlite3VdbeAddOp4(v, OP_IdxGE, iIdxCur, nxt, 0, "+", P4_STATIC); pLevel->op = OP_Next; } if( !omitTable ){ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, 0); sqlite3VdbeAddOp2(v, OP_MoveGe, iCur, 0); } |
︙ | ︙ |
Changes to test/incrblob.test.
1 2 3 4 5 6 7 8 9 10 11 | # 2007 May 1 # # 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. # #*********************************************************************** # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # 2007 May 1 # # 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. # #*********************************************************************** # # $Id: incrblob.test,v 1.18 2008/01/05 04:06:04 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {!autovacuum || !pragma || !incrblob} { finish_test |
︙ | ︙ | |||
78 79 80 81 82 83 84 | do_test incrblob-1.3.4 { seek $::blob 8496 read $::blob 10 } {....123456} do_test incrblob-1.3.10 { close $::blob } {} | < | 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | do_test incrblob-1.3.4 { seek $::blob 8496 read $::blob 10 } {....123456} do_test incrblob-1.3.10 { close $::blob } {} #------------------------------------------------------------------------ # incrblob-2.*: # # Test that the following operations use ptrmap pages to reduce # unnecessary reads: # |
︙ | ︙ |