Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch faster-OP_Column Excluding Merge-Ins
This is equivalent to a diff from 7fb16268 to 5e5d6e86
2014-09-30
| ||
12:33 | Remove the SQLITE_ENABLE_TREE_EXPLAIN compile-time option. Add alternative debugging display routines: sqlite3TreeViewExpr(), sqlite3TreeViewExprList(), and sqlite3TreeViewSelect(). (check-in: 4ff51325 user: drh tags: trunk) | |
2014-09-29
| ||
18:47 | Add the OPFLAG_MULTICOLUMN flag to the OP_Column opcode. Rearrange OP_Column instructions to take advantage of the new flag for a small performance increase (Leaf check-in: 5e5d6e86 user: drh tags: faster-OP_Column) | |
15:42 | Fix the header comment in sqlite3VdbeDeletePriorOpcode(). No changes to code. (check-in: 7fb16268 user: drh tags: trunk) | |
15:00 | Ensure that the OP_Prev opcode verifies that content has not been deleted out from under the cursor. Fix for ticket [209d31e3161b9e9ff]. (check-in: 414f0d6a user: drh tags: trunk) | |
Changes to src/expr.c.
︙ | ︙ | |||
2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 | if( !HasRowid(pTab) ){ x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol); } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); } if( iCol>=0 ){ sqlite3ColumnDefault(v, pTab, iCol, regOut); } } /* ** Generate code that will extract the iColumn-th column from ** table pTab and store the column value in a register. An effort ** is made to store the column value in register iReg, but this is | > | 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 | if( !HasRowid(pTab) ){ x = sqlite3ColumnOfIndex(sqlite3PrimaryKeyIndex(pTab), iCol); } sqlite3VdbeAddOp3(v, op, iTabCur, x, regOut); } if( iCol>=0 ){ sqlite3ColumnDefault(v, pTab, iCol, regOut); sqlite3VdbeOptimizeColumnOpcodes(v); } } /* ** Generate code that will extract the iColumn-th column from ** table pTab and store the column value in a register. An effort ** is made to store the column value in register iReg, but this is |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
702 703 704 705 706 707 708 | ** and reported later. But we need to make sure enough memory is allocated ** to avoid other spurious errors in the meantime. */ pParse->nMem += nResultCol; } pDest->nSdst = nResultCol; regResult = pDest->iSdst; if( srcTab>=0 ){ | | | 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | ** and reported later. But we need to make sure enough memory is allocated ** to avoid other spurious errors in the meantime. */ pParse->nMem += nResultCol; } pDest->nSdst = nResultCol; regResult = pDest->iSdst; if( srcTab>=0 ){ for(i=nResultCol-1; i>=0; i--){ sqlite3VdbeAddOp3(v, OP_Column, srcTab, i, regResult+i); VdbeComment((v, "%s", pEList->a[i].zName)); } }else if( eDest!=SRT_Exists ){ /* If the destination is an EXISTS(...) expression, the actual ** values returned by the SELECT are not required. */ |
︙ | ︙ | |||
1221 1222 1223 1224 1225 1226 1227 | }else{ addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); iSortTab = iTab; p5 = 0; bSeq = 1; } | | | > | 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 | }else{ addr = 1 + sqlite3VdbeAddOp2(v, OP_Sort, iTab, addrBreak); VdbeCoverage(v); codeOffset(v, p->iOffset, addrContinue); iSortTab = iTab; p5 = 0; bSeq = 1; } for(i=nSortData-1; i>=0; i--){ sqlite3VdbeAddOp3(v, OP_Column, iSortTab, nKey+bSeq+i, regRow+i); sqlite3VdbeChangeP5(v, p5); VdbeComment((v, "%s", aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].zSpan)); p5 = 0; } switch( eDest ){ case SRT_Table: case SRT_EphemTab: { testcase( eDest==SRT_Table ); testcase( eDest==SRT_EphemTab ); sqlite3VdbeAddOp2(v, OP_NewRowid, iParm, regRowid); |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 | #define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ #define OPFLAG_CLEARCACHE 0x20 /* Clear pseudo-table cache in OP_Column */ #define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ #define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */ #define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */ #define OPFLAG_P2ISREG 0x02 /* P2 to OP_Open** is a register number */ #define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ /* * Each trigger present in the database schema is stored as an instance of * struct Trigger. * * Pointers to instances of struct Trigger are stored in two ways. * 1. In the "trigHash" hash table (part of the sqlite3* that represents the | > | 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 | #define OPFLAG_USESEEKRESULT 0x10 /* Try to avoid a seek in BtreeInsert() */ #define OPFLAG_CLEARCACHE 0x20 /* Clear pseudo-table cache in OP_Column */ #define OPFLAG_LENGTHARG 0x40 /* OP_Column only used for length() */ #define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */ #define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */ #define OPFLAG_P2ISREG 0x02 /* P2 to OP_Open** is a register number */ #define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ #define OPFLAG_MULTICOLUMN 0x10 /* OP_Column followed by another */ /* * Each trigger present in the database schema is stored as an instance of * struct Trigger. * * Pointers to instances of struct Trigger are stored in two ways. * 1. In the "trigHash" hash table (part of the sqlite3* that represents the |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
69 70 71 72 73 74 75 76 77 78 79 80 81 82 | sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc, pCol->affinity, &pValue); if( pValue ){ sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM); } #ifndef SQLITE_OMIT_FLOATING_POINT if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); } #endif } } /* | > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | sqlite3ValueFromExpr(sqlite3VdbeDb(v), pCol->pDflt, enc, pCol->affinity, &pValue); if( pValue ){ sqlite3VdbeChangeP4(v, -1, (const char *)pValue, P4_MEM); } #ifndef SQLITE_OMIT_FLOATING_POINT if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ sqlite3VdbeOptimizeColumnOpcodes(v); sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg); } #endif } } /* |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 | const u8 *zHdr; /* Next unparsed byte of the header */ const u8 *zEndHdr; /* Pointer to first byte after the header */ u32 offset; /* Offset into the data */ u32 szField; /* Number of bytes in the content of a field */ u32 avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ u16 fx; /* pDest->flags value */ Mem *pReg; /* PseudoTable input register */ p2 = pOp->p2; assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( p2<pC->nField ); | > > | 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 | const u8 *zHdr; /* Next unparsed byte of the header */ const u8 *zEndHdr; /* Pointer to first byte after the header */ u32 offset; /* Offset into the data */ u32 szField; /* Number of bytes in the content of a field */ u32 avail; /* Number of bytes of available data */ u32 t; /* A type code from the record header */ u16 fx; /* pDest->flags value */ u8 p5; Mem *pReg; /* PseudoTable input register */ p2 = pOp->p2; p5 = 0; assert( pOp->p3>0 && pOp->p3<=(p->nMem-p->nCursor) ); pDest = &aMem[pOp->p3]; memAboutToChange(p, pDest); assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); assert( p2<pC->nField ); |
︙ | ︙ | |||
2432 2433 2434 2435 2436 2437 2438 | }else{ MemSetTypeFlag(pDest, MEM_Null); } goto op_column_out; } } | > > > > > > | > | | > > > | | 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 | }else{ MemSetTypeFlag(pDest, MEM_Null); } goto op_column_out; } } /* At this point, all of the following values are set: ** ** p2 Index of column to extract. pOp->p2. ** pDest Memory register into which to write result ** pC->aRow Binary row content from the btree. Might be incomplete ** pC->szRow Number of bytes in pC->szRow ** aOffset[p2] Offset into the binary row where P2-th column starts ** aOffste[p2+1] Offset into binary row of first byte past P2-th column ** pC->aType[p2] Datatype of the P2-th column (as stored on disk) ** ** Extract the content for column number p2. */ op_column_decode: assert( p2<pC->nHdrParsed ); assert( rc==SQLITE_OK ); assert( sqlite3VdbeCheckMemInvariants(pDest) ); if( VdbeMemDynamic(pDest) ) sqlite3VdbeMemSetNull(pDest); t = pC->aType[p2]; p5 = pOp->p5; if( pC->szRow>=aOffset[p2+1] ){ /* This is the common case where the desired content fits on the original ** page - where the content is not on an overflow page */ sqlite3VdbeSerialGet(pC->aRow+aOffset[p2], t, pDest); }else{ /* This branch happens only when content is on overflow pages */ if( ((p5 & (OPFLAG_LENGTHARG|OPFLAG_TYPEOFARG))!=0 && ((t>=12 && (t&1)==0) || (pOp->p5 & OPFLAG_TYPEOFARG)!=0)) || (len = sqlite3VdbeSerialTypeLen(t))==0 ){ /* Content is irrelevant for ** 1. the typeof() function, ** 2. the length(X) function if X is a blob, and ** 3. if the content length is zero. |
︙ | ︙ | |||
2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 | pDest->z[len] = 0; pDest->z[len+1] = 0; pDest->flags = fx|MEM_Term; } op_column_error: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); break; } /* Opcode: Affinity P1 P2 * P4 * ** Synopsis: affinity(r[P1@P2]) ** ** Apply affinities to a range of P2 registers starting with P1. | > > > > > > > > > > > > > > > > > | 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 | pDest->z[len] = 0; pDest->z[len+1] = 0; pDest->flags = fx|MEM_Term; } op_column_error: UPDATE_MAX_BLOBSIZE(pDest); REGISTER_TRACE(pOp->p3, pDest); /* If the OPFLAG_MULTICOLUMN bit is set on P5, that means that this ** OP_Column is immediately followed by another OP_Column with the same ** P1 and a P2 that is no larger than the current P2. In that case, ** process the following OP_Column as part of this instruction, without ** returning to the main instruction dispatch loop. */ if( (p5 & OPFLAG_MULTICOLUMN)!=0 && rc==0 ){ pc++; assert( pOp[1].opcode==OP_Column ); assert( pOp[1].p1==pOp[0].p1 ); assert( pOp[1].p2<=pOp[0].p2 ); pOp++; p2 = pOp->p2; pDest = &aMem[pOp->p3]; goto op_column_decode; } break; } /* Opcode: Affinity P1 P2 * P4 * ** Synopsis: affinity(r[P1@P2]) ** ** Apply affinities to a range of P2 registers starting with P1. |
︙ | ︙ |
Changes to src/vdbe.h.
︙ | ︙ | |||
175 176 177 178 179 180 181 182 183 184 185 186 187 188 | void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); void sqlite3VdbeChangeP5(Vdbe*, u8 P5); void sqlite3VdbeJumpHere(Vdbe*, int addr); void sqlite3VdbeChangeToNoop(Vdbe*, int addr); int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); void sqlite3VdbeUsesBtree(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); int sqlite3VdbeMakeLabel(Vdbe*); void sqlite3VdbeRunOnlyOnce(Vdbe*); void sqlite3VdbeDelete(Vdbe*); | > | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); void sqlite3VdbeChangeP5(Vdbe*, u8 P5); void sqlite3VdbeJumpHere(Vdbe*, int addr); void sqlite3VdbeChangeToNoop(Vdbe*, int addr); int sqlite3VdbeDeletePriorOpcode(Vdbe*, u8 op); void sqlite3VdbeOptimizeColumnOpcodes(Vdbe*); void sqlite3VdbeChangeP4(Vdbe*, int addr, const char *zP4, int N); void sqlite3VdbeSetP4KeyInfo(Parse*, Index*); void sqlite3VdbeUsesBtree(Vdbe*, int); VdbeOp *sqlite3VdbeGetOp(Vdbe*, int); int sqlite3VdbeMakeLabel(Vdbe*); void sqlite3VdbeRunOnlyOnce(Vdbe*); void sqlite3VdbeDelete(Vdbe*); |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
498 499 500 501 502 503 504 505 506 507 508 509 510 511 | } case OP_Prev: case OP_PrevIfOpen: { pOp->p4.xAdvance = sqlite3BtreePrevious; pOp->p4type = P4_ADVANCE; break; } } pOp->opflags = sqlite3OpcodeProperty[opcode]; if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ assert( -1-pOp->p2<pParse->nLabel ); pOp->p2 = aLabel[-1-pOp->p2]; } | > > > > > > > > > | 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | } case OP_Prev: case OP_PrevIfOpen: { pOp->p4.xAdvance = sqlite3BtreePrevious; pOp->p4type = P4_ADVANCE; break; } case OP_Column: { if( pOp[1].opcode==OP_Column && pOp[1].p1==pOp->p1 && pOp[1].p2<=pOp->p2 ){ pOp->p5 |= OPFLAG_MULTICOLUMN; } break; } } pOp->opflags = sqlite3OpcodeProperty[opcode]; if( (pOp->opflags & OPFLG_JUMP)!=0 && pOp->p2<0 ){ assert( -1-pOp->p2<pParse->nLabel ); pOp->p2 = aLabel[-1-pOp->p2]; } |
︙ | ︙ | |||
759 760 761 762 763 764 765 766 767 768 769 770 771 772 | if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){ sqlite3VdbeChangeToNoop(p, p->nOp-1); return 1; }else{ return 0; } } /* ** Change the value of the P4 operand for a specific instruction. ** This routine is useful when a large program is loaded from a ** static array using sqlite3VdbeAddOpList but we want to make a ** few minor changes to the program. ** | > > > > > > > > > > > > > > > > > > > > > > > > | 768 769 770 771 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 804 805 | if( (p->nOp-1)>(p->pParse->iFixedOp) && p->aOp[p->nOp-1].opcode==op ){ sqlite3VdbeChangeToNoop(p, p->nOp-1); return 1; }else{ return 0; } } /* ** When running multiple OP_Column opcodes in a row, it is advantagous ** to run the one with the largest P2 value (the largest column number) ** first. This routine checks the last few OP_Column opcodes and ** might reorder them so that a larger P2 value opertion occurs at ** the start of the list. */ void sqlite3VdbeOptimizeColumnOpcodes(Vdbe *p){ VdbeOp *aOp, tempOp; int i; aOp = p->aOp; i = p->nOp-2; while( i>p->pParse->iFixedOp && aOp[i+1].opcode==OP_Column && aOp[i].opcode==OP_Column && aOp[i].p1==aOp[i+1].p1 && aOp[i].p2<aOp[i+1].p2 ){ tempOp = aOp[i]; aOp[i] = aOp[i+1]; aOp[i+1] = tempOp; i--; } } /* ** Change the value of the P4 operand for a specific instruction. ** This routine is useful when a large program is loaded from a ** static array using sqlite3VdbeAddOpList but we want to make a ** few minor changes to the program. ** |
︙ | ︙ |