Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | If SQLITE_ENABLE_STMT_SCANSTATUS is defined, record the number of times each VDBE opcode is executed. Derive the values returned by sqlite3_stmt_scanstatus() from these records on demand. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | scanstatus |
Files: | files | file ages | folders |
SHA1: | 9ea37422a8cc2fce51bb10508e5e90f4 |
User & Date: | dan 2014-11-01 20:38:06 |
Context
2014-11-01
| ||
21:00 | Minor performance enhancements to SQLITE_ENABLE_STMT_SCANSTATUS code. check-in: f13d6ba8 user: dan tags: scanstatus | |
20:38 | If SQLITE_ENABLE_STMT_SCANSTATUS is defined, record the number of times each VDBE opcode is executed. Derive the values returned by sqlite3_stmt_scanstatus() from these records on demand. check-in: 9ea37422 user: dan tags: scanstatus | |
18:08 | Minor fixes and documentation improvements for sqlite3_stmt_scanstatus(). check-in: 8d8cc960 user: dan tags: scanstatus | |
Changes
Changes to src/vdbe.c.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 ... 616 617 618 619 620 621 622 623 624 625 626 627 628 629 .... 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 .... 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 .... 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 .... 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 .... 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 .... 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 .... 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 .... 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 .... 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 |
#define Deephemeralize(P) \ if( ((P)->flags&MEM_Ephem)!=0 \ && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} /* Return true if the cursor was opened using the OP_OpenSorter opcode. */ #define isSorter(x) ((x)->pSorter!=0) /* ** The first argument passed to the IncrementExplainCounter() macro must ** be a non-NULL pointer to an object of type VdbeCursor. The second ** argument must be either "nLoop" or "nVisit" (without the double-quotes). */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS # define IncrementExplainCounter(pCsr, counter) \ if( (pCsr)->pExplain ) (pCsr)->pExplain->counter++ #else # define IncrementExplainCounter(pCsr, counter) #endif /* ** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL ** if we run out of memory. */ static VdbeCursor *allocateCursor( Vdbe *p, /* The virtual machine */ int iCur, /* Index of the new VdbeCursor */ ................................................................................ assert( pc>=0 && pc<p->nOp ); if( db->mallocFailed ) goto no_mem; #ifdef VDBE_PROFILE start = sqlite3Hwtime(); #endif nVmStep++; pOp = &aOp[pc]; /* Only allow tracing if SQLITE_DEBUG is defined. */ #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ sqlite3VdbePrintOp(stdout, pc, pOp); } ................................................................................ assert( pC->isOrdered ); assert( pC->pCursor!=0 ); oc = pOp->opcode; pC->nullRow = 0; #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif IncrementExplainCounter(pC, nLoop); if( pC->isTable ){ /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so convert it. */ pIn3 = &aMem[pOp->p3]; if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3, 0); ................................................................................ res = sqlite3BtreeEof(pC->pCursor); } } assert( pOp->p2>0 ); VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; }else{ IncrementExplainCounter(pC, nVisit); } break; } /* Opcode: Seek P1 P2 * * * ** Synopsis: intkey=r[P2] ** ................................................................................ assert( pC->isTable ); assert( pC->pseudoTableReg==0 ); pCrsr = pC->pCursor; assert( pCrsr!=0 ); res = 0; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); IncrementExplainCounter(pC, nLoop); pC->movetoTarget = iKey; /* Used by OP_Delete */ pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; pC->deferredMoveto = 0; VdbeBranchTaken(res!=0,2); if( res!=0 ){ pc = pOp->p2 - 1; }else{ IncrementExplainCounter(pC, nVisit); } pC->seekResult = res; break; } /* Opcode: Sequence P1 P2 * * * ** Synopsis: r[P2]=cursor[P1].ctr++ ................................................................................ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); pCrsr = pC->pCursor; res = 0; assert( pCrsr!=0 ); rc = sqlite3BtreeLast(pCrsr, &res); IncrementExplainCounter(pC, nLoop); if( res==0 ) IncrementExplainCounter(pC, nVisit); pC->nullRow = (u8)res; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; #ifdef SQLITE_DEBUG pC->seekOp = OP_Last; #endif if( pOp->p2>0 ){ ................................................................................ }else{ pCrsr = pC->pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } IncrementExplainCounter(pC, nLoop); pC->nullRow = (u8)res; assert( pOp->p2>0 && pOp->p2<p->nOp ); VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; }else{ IncrementExplainCounter(pC, nVisit); } break; } /* Opcode: Next P1 P2 P3 P4 P5 ** ** Advance cursor P1 so that it points to the next key/data pair in its ................................................................................ || pC->seekOp==OP_Last ); rc = pOp->p4.xAdvance(pC->pCursor, &res); next_tail: pC->cacheStatus = CACHE_STALE; VdbeBranchTaken(res==0,2); if( res==0 ){ IncrementExplainCounter(pC, nVisit); pC->nullRow = 0; pc = pOp->p2 - 1; p->aCounter[pOp->p5]++; #ifdef SQLITE_TEST sqlite3_search_count++; #endif }else{ ................................................................................ sqlite3VtabImportErrmsg(p, pVtab); if( rc==SQLITE_OK ){ res = pModule->xEof(pVtabCursor); } VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; }else{ IncrementExplainCounter(pCur, nVisit); } IncrementExplainCounter(pCur, nLoop); } pCur->nullRow = 0; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ ................................................................................ if( rc==SQLITE_OK ){ res = pModule->xEof(pCur->pVtabCursor); } VdbeBranchTaken(!res,2); if( !res ){ /* If there is data, jump to P2 */ pc = pOp->p2 - 1; IncrementExplainCounter(pCur, nVisit); } goto check_for_interrupt; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VRename P1 * * P4 * ................................................................................ sqlite3DebugPrintf("SQL-trace: %s\n", zTrace); } #endif /* SQLITE_DEBUG */ #endif /* SQLITE_OMIT_TRACE */ break; } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS case OP_Explain: { ExplainArg *pArg; VdbeCursor *pCur; if( pOp->p4type==P4_EXPLAIN && (pArg = pOp->p4.pExplain)->iCsr>=0 ){ pArg = pOp->p4.pExplain; pCur = p->apCsr[pArg->iCsr]; pCur->pExplain = pArg; } break; } #endif /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump ** destination. */ /* |
< < < < < < < < < < < < > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
163 164 165 166 167 168 169 170 171 172 173 174 175 176 ... 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 .... 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 .... 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 .... 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 .... 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 .... 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 .... 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 .... 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 .... 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 .... 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 |
#define Deephemeralize(P) \ if( ((P)->flags&MEM_Ephem)!=0 \ && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} /* Return true if the cursor was opened using the OP_OpenSorter opcode. */ #define isSorter(x) ((x)->pSorter!=0) /* ** Allocate VdbeCursor number iCur. Return a pointer to it. Return NULL ** if we run out of memory. */ static VdbeCursor *allocateCursor( Vdbe *p, /* The virtual machine */ int iCur, /* Index of the new VdbeCursor */ ................................................................................ assert( pc>=0 && pc<p->nOp ); if( db->mallocFailed ) goto no_mem; #ifdef VDBE_PROFILE start = sqlite3Hwtime(); #endif nVmStep++; pOp = &aOp[pc]; #ifdef SQLITE_ENABLE_STMT_SCANSTATUS if( p->pFrame==0 ) p->anExec[pc]++; #endif /* Only allow tracing if SQLITE_DEBUG is defined. */ #ifdef SQLITE_DEBUG if( db->flags & SQLITE_VdbeTrace ){ sqlite3VdbePrintOp(stdout, pc, pOp); } ................................................................................ assert( pC->isOrdered ); assert( pC->pCursor!=0 ); oc = pOp->opcode; pC->nullRow = 0; #ifdef SQLITE_DEBUG pC->seekOp = pOp->opcode; #endif if( pC->isTable ){ /* The input value in P3 might be of any type: integer, real, string, ** blob, or NULL. But it needs to be an integer before we can do ** the seek, so convert it. */ pIn3 = &aMem[pOp->p3]; if( (pIn3->flags & (MEM_Int|MEM_Real|MEM_Str))==MEM_Str ){ applyNumericAffinity(pIn3, 0); ................................................................................ res = sqlite3BtreeEof(pC->pCursor); } } assert( pOp->p2>0 ); VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; } break; } /* Opcode: Seek P1 P2 * * * ** Synopsis: intkey=r[P2] ** ................................................................................ assert( pC->isTable ); assert( pC->pseudoTableReg==0 ); pCrsr = pC->pCursor; assert( pCrsr!=0 ); res = 0; iKey = pIn3->u.i; rc = sqlite3BtreeMovetoUnpacked(pCrsr, 0, iKey, 0, &res); pC->movetoTarget = iKey; /* Used by OP_Delete */ pC->nullRow = 0; pC->cacheStatus = CACHE_STALE; pC->deferredMoveto = 0; VdbeBranchTaken(res!=0,2); if( res!=0 ){ pc = pOp->p2 - 1; } pC->seekResult = res; break; } /* Opcode: Sequence P1 P2 * * * ** Synopsis: r[P2]=cursor[P1].ctr++ ................................................................................ assert( pOp->p1>=0 && pOp->p1<p->nCursor ); pC = p->apCsr[pOp->p1]; assert( pC!=0 ); pCrsr = pC->pCursor; res = 0; assert( pCrsr!=0 ); rc = sqlite3BtreeLast(pCrsr, &res); pC->nullRow = (u8)res; pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; #ifdef SQLITE_DEBUG pC->seekOp = OP_Last; #endif if( pOp->p2>0 ){ ................................................................................ }else{ pCrsr = pC->pCursor; assert( pCrsr ); rc = sqlite3BtreeFirst(pCrsr, &res); pC->deferredMoveto = 0; pC->cacheStatus = CACHE_STALE; } pC->nullRow = (u8)res; assert( pOp->p2>0 && pOp->p2<p->nOp ); VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; } break; } /* Opcode: Next P1 P2 P3 P4 P5 ** ** Advance cursor P1 so that it points to the next key/data pair in its ................................................................................ || pC->seekOp==OP_Last ); rc = pOp->p4.xAdvance(pC->pCursor, &res); next_tail: pC->cacheStatus = CACHE_STALE; VdbeBranchTaken(res==0,2); if( res==0 ){ pC->nullRow = 0; pc = pOp->p2 - 1; p->aCounter[pOp->p5]++; #ifdef SQLITE_TEST sqlite3_search_count++; #endif }else{ ................................................................................ sqlite3VtabImportErrmsg(p, pVtab); if( rc==SQLITE_OK ){ res = pModule->xEof(pVtabCursor); } VdbeBranchTaken(res!=0,2); if( res ){ pc = pOp->p2 - 1; } } pCur->nullRow = 0; break; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ ................................................................................ if( rc==SQLITE_OK ){ res = pModule->xEof(pCur->pVtabCursor); } VdbeBranchTaken(!res,2); if( !res ){ /* If there is data, jump to P2 */ pc = pOp->p2 - 1; } goto check_for_interrupt; } #endif /* SQLITE_OMIT_VIRTUALTABLE */ #ifndef SQLITE_OMIT_VIRTUALTABLE /* Opcode: VRename P1 * * P4 * ................................................................................ sqlite3DebugPrintf("SQL-trace: %s\n", zTrace); } #endif /* SQLITE_DEBUG */ #endif /* SQLITE_OMIT_TRACE */ break; } /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump ** destination. */ /* |
Changes to src/vdbe.h.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 .. 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 .. 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 ... 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 ... 293 294 295 296 297 298 299 300 301 |
/* ** A single VDBE is an opaque structure named "Vdbe". Only routines ** in the source file sqliteVdbe.c are allowed to see the insides ** of this structure. */ typedef struct Vdbe Vdbe; typedef struct ExplainArg ExplainArg; /* ** The names of the following types declared in vdbeInt.h are required ** for the VdbeOp definition. */ typedef struct Mem Mem; typedef struct SubProgram SubProgram; ................................................................................ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ int *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ ExplainArg *pExplain; /* Used when p4type is P4_EXPLAIN */ int (*xAdvance)(BtCursor *, int *); } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zComment; /* Comment to improve readability */ #endif #ifdef VDBE_PROFILE u32 cnt; /* Number of times this instruction was executed */ ................................................................................ struct VdbeOpList { u8 opcode; /* What operation to perform */ signed char p1; /* First operand */ signed char p2; /* Second parameter (often the jump destination) */ signed char p3; /* Third parameter */ }; typedef struct VdbeOpList VdbeOpList; /* ** Structure used as the P4 parameter for OP_Explain opcodes. */ struct ExplainArg { int iCsr; /* Cursor number this applies to */ i64 nLoop; /* Number of times loop has run */ i64 nVisit; /* Total number of rows visited */ i64 nEst; /* Estimated number of rows per scan */ const char *zName; /* Name of table/index being scanned */ const char *zExplain; /* EQP text for this loop */ }; /* ** Allowed values of VdbeOp.p4type */ #define P4_NOTUSED 0 /* The P4 parameter is not used */ #define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ #define P4_STATIC (-2) /* Pointer to a static string */ ................................................................................ #define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ #define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */ #define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */ #define P4_EXPLAIN (-20) /* P4 is a pointer to an instance of ExplainArg */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 #define P5_ConstraintUnique 2 #define P5_ConstraintCheck 3 #define P5_ConstraintFK 4 ................................................................................ #else # define VdbeCoverage(v) # define VdbeCoverageIf(v,x) # define VdbeCoverageAlwaysTaken(v) # define VdbeCoverageNeverTaken(v) # define VDBE_OFFSET_LINENO(x) 0 #endif #endif |
< < < < < < < < < < < < < < < < > > > > > > |
21 22 23 24 25 26 27 28 29 30 31 32 33 34 .. 55 56 57 58 59 60 61 62 63 64 65 66 67 68 .. 95 96 97 98 99 100 101 102 103 104 105 106 107 108 ... 115 116 117 118 119 120 121 122 123 124 125 126 127 128 ... 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
/* ** A single VDBE is an opaque structure named "Vdbe". Only routines ** in the source file sqliteVdbe.c are allowed to see the insides ** of this structure. */ typedef struct Vdbe Vdbe; /* ** The names of the following types declared in vdbeInt.h are required ** for the VdbeOp definition. */ typedef struct Mem Mem; typedef struct SubProgram SubProgram; ................................................................................ FuncDef *pFunc; /* Used when p4type is P4_FUNCDEF */ CollSeq *pColl; /* Used when p4type is P4_COLLSEQ */ Mem *pMem; /* Used when p4type is P4_MEM */ VTable *pVtab; /* Used when p4type is P4_VTAB */ KeyInfo *pKeyInfo; /* Used when p4type is P4_KEYINFO */ int *ai; /* Used when p4type is P4_INTARRAY */ SubProgram *pProgram; /* Used when p4type is P4_SUBPROGRAM */ int (*xAdvance)(BtCursor *, int *); } p4; #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS char *zComment; /* Comment to improve readability */ #endif #ifdef VDBE_PROFILE u32 cnt; /* Number of times this instruction was executed */ ................................................................................ struct VdbeOpList { u8 opcode; /* What operation to perform */ signed char p1; /* First operand */ signed char p2; /* Second parameter (often the jump destination) */ signed char p3; /* Third parameter */ }; typedef struct VdbeOpList VdbeOpList; /* ** Allowed values of VdbeOp.p4type */ #define P4_NOTUSED 0 /* The P4 parameter is not used */ #define P4_DYNAMIC (-1) /* Pointer to a string obtained from sqliteMalloc() */ #define P4_STATIC (-2) /* Pointer to a static string */ ................................................................................ #define P4_MPRINTF (-11) /* P4 is a string obtained from sqlite3_mprintf() */ #define P4_REAL (-12) /* P4 is a 64-bit floating point value */ #define P4_INT64 (-13) /* P4 is a 64-bit signed integer */ #define P4_INT32 (-14) /* P4 is a 32-bit signed integer */ #define P4_INTARRAY (-15) /* P4 is a vector of 32-bit integers */ #define P4_SUBPROGRAM (-18) /* P4 is a pointer to a SubProgram structure */ #define P4_ADVANCE (-19) /* P4 is a pointer to BtreeNext() or BtreePrev() */ /* Error message codes for OP_Halt */ #define P5_ConstraintNotNull 1 #define P5_ConstraintUnique 2 #define P5_ConstraintCheck 3 #define P5_ConstraintFK 4 ................................................................................ #else # define VdbeCoverage(v) # define VdbeCoverageIf(v,x) # define VdbeCoverageAlwaysTaken(v) # define VdbeCoverageNeverTaken(v) # define VDBE_OFFSET_LINENO(x) 0 #endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS void sqlite3VdbeScanCounter(Vdbe*, int, int, int, i64, const char*); #else # define sqlite3VdbeScanCounter(a,b,c,d,e) #endif #endif |
Changes to src/vdbeInt.h.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 ... 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 ... 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
Bool isTable:1; /* True if a table requiring integer keys */ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */ Pgno pgnoRoot; /* Root page of the open btree cursor */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ ExplainArg *pExplain; /* Object to store seek/visit counts (may be NULL) */ /* Cached information about the header for the data record that the ** cursor is currently pointing to. Only valid if cacheStatus matches ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that ** the cache is out of date. ** ................................................................................ Vdbe *pVdbe; /* Attach the explanation to this Vdbe */ StrAccum str; /* The string being accumulated */ int nIndent; /* Number of elements in aIndent */ u16 aIndent[100]; /* Levels of indentation */ char zBase[100]; /* Initial space */ }; /* A bitfield type for use inside of structures. Always follow with :N where ** N is the number of bits. */ typedef unsigned bft; /* Bit Field Type */ /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. ** ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare() ** is really a pointer to an instance of this structure. ................................................................................ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ int nFrame; /* Number of frames in pFrame list */ u32 expmask; /* Binding to these vars invalidates VM */ SubProgram *pProgram; /* Linked list of all sub-programs used by VM */ int nOnceFlag; /* Size of array aOnceFlag[] */ u8 *aOnceFlag; /* Flags for OP_Once */ AuxData *pAuxData; /* Linked list of auxdata allocations */ ExplainArg **apExplain; /* Array of pointers to P4_EXPLAIN p4 values */ int nExplain; /* Number of entries in array apExplain */ }; /* ** The following are allowed values for Vdbe.magic */ #define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */ #define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */ |
< < > > > > > > > > > | | > > > |
79 80 81 82 83 84 85 86 87 88 89 90 91 92 ... 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 ... 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 |
Bool isTable:1; /* True if a table requiring integer keys */ Bool isOrdered:1; /* True if the underlying table is BTREE_UNORDERED */ Pgno pgnoRoot; /* Root page of the open btree cursor */ sqlite3_vtab_cursor *pVtabCursor; /* The cursor for a virtual table */ i64 seqCount; /* Sequence counter */ i64 movetoTarget; /* Argument to the deferred sqlite3BtreeMoveto() */ VdbeSorter *pSorter; /* Sorter object for OP_SorterOpen cursors */ /* Cached information about the header for the data record that the ** cursor is currently pointing to. Only valid if cacheStatus matches ** Vdbe.cacheCtr. Vdbe.cacheCtr will never take on the value of ** CACHE_STALE and so setting cacheStatus=CACHE_STALE guarantees that ** the cache is out of date. ** ................................................................................ Vdbe *pVdbe; /* Attach the explanation to this Vdbe */ StrAccum str; /* The string being accumulated */ int nIndent; /* Number of elements in aIndent */ u16 aIndent[100]; /* Levels of indentation */ char zBase[100]; /* Initial space */ }; /* A bitfield type for use inside of structures. Always follow with :N where ** N is the number of bits. */ typedef unsigned bft; /* Bit Field Type */ typedef struct ScanCounter ScanCounter; struct ScanCounter { int addrExplain; /* OP_Explain for loop */ int addrLoop; /* Address of "loops" counter */ int addrVisit; /* Address of "rows visited" counter */ i64 nEst; /* Estimated rows per loop */ char *zName; /* Name of table or index */ }; /* ** An instance of the virtual machine. This structure contains the complete ** state of the virtual machine. ** ** The "sqlite3_stmt" structure pointer that is returned by sqlite3_prepare() ** is really a pointer to an instance of this structure. ................................................................................ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ int nFrame; /* Number of frames in pFrame list */ u32 expmask; /* Binding to these vars invalidates VM */ SubProgram *pProgram; /* Linked list of all sub-programs used by VM */ int nOnceFlag; /* Size of array aOnceFlag[] */ u8 *aOnceFlag; /* Flags for OP_Once */ AuxData *pAuxData; /* Linked list of auxdata allocations */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS i64 *anExec; /* Number of times each op has been executed */ int nScan; /* Entries in aScan[] */ ScanCounter *aScan; /* Scan definitions for sqlite3_stmt_scanstatus() */ #endif }; /* ** The following are allowed values for Vdbe.magic */ #define VDBE_MAGIC_INIT 0x26bceaa5 /* Building a VDBE program */ #define VDBE_MAGIC_RUN 0xbdf20da3 /* VDBE is ready to execute */ |
Changes to src/vdbeapi.c.
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 |
} #endif v = pVdbe->aCounter[op]; if( resetFlag ) pVdbe->aCounter[op] = 0; return (int)v; } /* ** Return status data for a single loop within query pStmt. */ int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, int idx, /* Index of loop to report on */ sqlite3_int64 *pnLoop, /* OUT: Number of times loop was run */ sqlite3_int64 *pnVisit, /* OUT: Number of rows visited (all loops) */ sqlite3_int64 *pnEst, /* OUT: Number of rows estimated (per loop) */ const char **pzName, /* OUT: Object name (table or index) */ const char **pzExplain /* OUT: EQP string */ ){ Vdbe *p = (Vdbe*)pStmt; ExplainArg *pExplain; if( idx<0 || idx>=p->nExplain ) return 1; pExplain = p->apExplain[idx]; if( pnLoop ) *pnLoop = pExplain->nLoop; if( pnVisit ) *pnVisit = pExplain->nVisit; if( pnEst ) *pnEst = pExplain->nEst; if( *pzName ) *pzName = pExplain->zName; if( *pzExplain ) *pzExplain = pExplain->zExplain; return 0; } /* ** Zero all counters associated with the sqlite3_stmt_scanstatus() data. */ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; int i; for(i=0; i<p->nExplain; i++){ p->apExplain[i]->nLoop = 0; p->apExplain[i]->nVisit = 0; } } |
> | | | | | | | | > > > > > > | < < < | > | < |
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 |
} #endif v = pVdbe->aCounter[op]; if( resetFlag ) pVdbe->aCounter[op] = 0; return (int)v; } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* ** Return status data for a single loop within query pStmt. */ int sqlite3_stmt_scanstatus( sqlite3_stmt *pStmt, int idx, /* Index of loop to report on */ sqlite3_int64 *pnLoop, /* OUT: Number of times loop was run */ sqlite3_int64 *pnVisit, /* OUT: Number of rows visited (all loops) */ sqlite3_int64 *pnEst, /* OUT: Number of rows estimated (per loop) */ const char **pzName, /* OUT: Object name (table or index) */ const char **pzExplain /* OUT: EQP string */ ){ Vdbe *p = (Vdbe*)pStmt; ScanCounter *pScan; if( idx<0 || idx>=p->nScan ) return 1; pScan = &p->aScan[idx]; if( pnLoop ) *pnLoop = p->anExec[pScan->addrLoop]; if( pnVisit ) *pnVisit = p->anExec[pScan->addrVisit]; if( pnEst ) *pnEst = pScan->nEst; if( *pzName ) *pzName = pScan->zName; if( *pzExplain ){ if( pScan->addrExplain ){ *pzExplain = p->aOp[ pScan->addrExplain ].p4.z; }else{ *pzExplain = 0; } } return 0; } /* ** Zero all counters associated with the sqlite3_stmt_scanstatus() data. */ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt *pStmt){ Vdbe *p = (Vdbe*)pStmt; memset(p->anExec, 0, p->nOp * sizeof(i64)); } #endif /* SQLITE_ENABLE_STMT_SCANSTATUS */ |
Changes to src/vdbeaux.c.
592 593 594 595 596 597 598 599 600 601 602 603 604 605 ... 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 ... 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 .... 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 .... 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 .... 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 |
} #endif } p->nOp += nOp; } return addr; } /* ** Change the value of the P1 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. */ ................................................................................ /* ** Delete a P4 value if necessary. */ static void freeP4(sqlite3 *db, int p4type, void *p4){ if( p4 ){ assert( db ); switch( p4type ){ case P4_EXPLAIN: case P4_REAL: case P4_INT64: case P4_DYNAMIC: case P4_INTARRAY: { sqlite3DbFree(db, p4); break; } ................................................................................ pOp->p4.p = (void*)zP4; pOp->p4type = P4_KEYINFO; }else if( n==P4_VTAB ){ pOp->p4.p = (void*)zP4; pOp->p4type = P4_VTAB; sqlite3VtabLock((VTable *)zP4); assert( ((VTable *)zP4)->db==p->db ); }else if( n==P4_EXPLAIN ){ pOp->p4.p = (void*)zP4; pOp->p4type = P4_EXPLAIN; p->apExplain = (ExplainArg**)sqlite3DbReallocOrFree( p->db, p->apExplain, sizeof(ExplainArg*) * p->nExplain + 1 ); if( p->apExplain ) p->apExplain[p->nExplain++] = (ExplainArg*)zP4; }else if( n<0 ){ pOp->p4.p = (void*)zP4; pOp->p4type = (signed char)n; }else{ if( n==0 ) n = sqlite3Strlen30(zP4); pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); pOp->p4type = P4_DYNAMIC; ................................................................................ sqlite3_snprintf(nTemp, zTemp, "program"); break; } case P4_ADVANCE: { zTemp[0] = 0; break; } case P4_EXPLAIN: { zP4 = (char*)pOp->p4.pExplain->zExplain; break; } default: { zP4 = pOp->p4.z; if( zP4==0 ){ zP4 = zTemp; zTemp[0] = 0; } } ................................................................................ p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte); if( nByte ){ p->pFree = sqlite3DbMallocZero(db, nByte); } zCsr = p->pFree; zEnd = &zCsr[nByte]; }while( nByte && !db->mallocFailed ); p->nCursor = nCursor; p->nOnceFlag = nOnce; if( p->aVar ){ p->nVar = (ynVar)nVar; for(n=0; n<nVar; n++){ p->aVar[n].flags = MEM_Null; ................................................................................ sqlite3DbFree(db, pSub); } for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); sqlite3DbFree(db, p->apExplain); } /* ** Delete an entire VDBE. */ void sqlite3VdbeDelete(Vdbe *p){ sqlite3 *db; |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < > > > > > | > > > > > |
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 621 622 623 624 625 626 627 628 629 630 631 632 633 ... 696 697 698 699 700 701 702 703 704 705 706 707 708 709 ... 844 845 846 847 848 849 850 851 852 853 854 855 856 857 .... 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 .... 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 .... 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 |
} #endif } p->nOp += nOp; } return addr; } #if defined(SQLITE_ENABLE_STMT_SCANSTATUS) /* ** Add an entry to the array of counters managed by sqlite3_stmt_scanstatus(). */ void sqlite3VdbeScanCounter( Vdbe *p, /* VM to add scanstatus() to */ int addrExplain, /* Address of OP_Explain (or 0) */ int addrLoop, /* Address of loop counter */ int addrVisit, /* Address of rows visited counter */ i64 nEst, /* Estimated number of rows */ const char *zName /* Name of table or index being scanned */ ){ int nByte = (p->nScan+1) * sizeof(ScanCounter); ScanCounter *aNew; aNew = (ScanCounter*)sqlite3DbRealloc(p->db, p->aScan, nByte); if( aNew ){ ScanCounter *pNew = &aNew[p->nScan++]; pNew->addrExplain = addrExplain; pNew->addrLoop = addrLoop; pNew->addrVisit = addrVisit; pNew->nEst = nEst; pNew->zName = sqlite3DbStrDup(p->db, zName); p->aScan = aNew; } } #endif /* ** Change the value of the P1 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. */ ................................................................................ /* ** Delete a P4 value if necessary. */ static void freeP4(sqlite3 *db, int p4type, void *p4){ if( p4 ){ assert( db ); switch( p4type ){ case P4_REAL: case P4_INT64: case P4_DYNAMIC: case P4_INTARRAY: { sqlite3DbFree(db, p4); break; } ................................................................................ pOp->p4.p = (void*)zP4; pOp->p4type = P4_KEYINFO; }else if( n==P4_VTAB ){ pOp->p4.p = (void*)zP4; pOp->p4type = P4_VTAB; sqlite3VtabLock((VTable *)zP4); assert( ((VTable *)zP4)->db==p->db ); }else if( n<0 ){ pOp->p4.p = (void*)zP4; pOp->p4type = (signed char)n; }else{ if( n==0 ) n = sqlite3Strlen30(zP4); pOp->p4.z = sqlite3DbStrNDup(p->db, zP4, n); pOp->p4type = P4_DYNAMIC; ................................................................................ sqlite3_snprintf(nTemp, zTemp, "program"); break; } case P4_ADVANCE: { zTemp[0] = 0; break; } default: { zP4 = pOp->p4.z; if( zP4==0 ){ zP4 = zTemp; zTemp[0] = 0; } } ................................................................................ p->aOnceFlag = allocSpace(p->aOnceFlag, nOnce, &zCsr, zEnd, &nByte); if( nByte ){ p->pFree = sqlite3DbMallocZero(db, nByte); } zCsr = p->pFree; zEnd = &zCsr[nByte]; }while( nByte && !db->mallocFailed ); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS p->anExec = (i64*)sqlite3DbMallocZero(db, p->nOp*sizeof(i64)); #endif p->nCursor = nCursor; p->nOnceFlag = nOnce; if( p->aVar ){ p->nVar = (ynVar)nVar; for(n=0; n<nVar; n++){ p->aVar[n].flags = MEM_Null; ................................................................................ sqlite3DbFree(db, pSub); } for(i=p->nzVar-1; i>=0; i--) sqlite3DbFree(db, p->azVar[i]); vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); sqlite3DbFree(db, p->pFree); #ifdef SQLITE_ENABLE_STMT_SCANSTATUS sqlite3DbFree(db, p->anExec); for(i=0; i<p->nScan; i++){ sqlite3DbFree(db, p->aScan[i].zName); } sqlite3DbFree(db, p->aScan); #endif } /* ** Delete an entire VDBE. */ void sqlite3VdbeDelete(Vdbe *p){ sqlite3 *db; |
Changes to src/where.c.
2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 .... 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 .... 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 .... 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 .... 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 .... 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 |
} } } *pzAff = zAff; return regBase; } #if !defined(SQLITE_OMIT_EXPLAIN) || defined(SQLITE_ENABLE_STMT_SCANSTATUS) /* ** This routine is a helper for explainIndexRange() below ** ** pStr holds the text of an expression that we are building up one term ** at a time. This routine adds a new term to the end of the expression. ** Terms are separated by AND so add the "AND" text for second and subsequent ** terms only. ................................................................................ /* ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN ** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single ** record is added to the output to describe the table scan strategy in ** pLevel. */ static void explainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereInfo *pWInfo, /* WHERE clause this loop belongs to */ int iLevel, /* Value for "level" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ #if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( pParse->explain==2 ) #endif { WhereLevel *pLevel = &pWInfo->a[iLevel]; struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ #ifdef SQLITE_OMIT_EXPLAIN int iId = 0; /* Select id (left-most output column) */ #else int iId = pParse->iSelectId; /* Select id (left-most output column) */ #endif int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ const char *zObj; ExplainArg *pExplain; i64 nEstRow; /* Estimated rows per scan of pLevel */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; if( (flags&WHERE_MULTI_OR) ) return; sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); str.db = db; /* Reserve space at the start of the buffer managed by the StrAccum ** object for *pExplain. */ assert( sizeof(*pExplain)<=sizeof(zBuf) ); str.nChar = sizeof(*pExplain); /* Append the object (table or index) name to the buffer. */ if( pItem->pSelect ){ zObj = ""; }else if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ zObj = pLoop->u.btree.pIndex->zName; }else{ zObj = pItem->zName; } sqlite3StrAccumAppend(&str, zObj, sqlite3Strlen30(zObj)+1); /* Append the EQP text to the buffer */ isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ #ifdef SQLITE_OMIT_EXPLAIN sqlite3XPrintf(&str, 0, " SUBQUERY 0"); #else sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); #endif }else{ sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias); } ................................................................................ } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s", pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif nEstRow = pLoop->nOut>=10 ? sqlite3LogEstToInt(pLoop->nOut) : 1; #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS sqlite3XPrintf(&str, 0, " (~%llu rows)", nEstRow); #endif pExplain = (ExplainArg*)sqlite3StrAccumFinish(&str); assert( pExplain || db->mallocFailed ); if( pExplain ){ memset(pExplain, 0, sizeof(*pExplain)); if( pLoop->wsFlags & WHERE_INDEXED ){ pExplain->iCsr = pLevel->iIdxCur; }else if( pItem->pSelect==0 ){ pExplain->iCsr = pLevel->iTabCur; }else{ pExplain->iCsr = -1; } pExplain->nEst = nEstRow; pExplain->zName = (const char*)&pExplain[1]; pExplain->zExplain = &pExplain->zName[sqlite3Strlen30(pExplain->zName)+1]; pWInfo->iExplain = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, pLevel->iFrom, (char*)pExplain,P4_EXPLAIN ); } } } #else # define explainOneScan(v,w,x,y,z) #endif /* !SQLITE_OMIT_EXPLAIN || SQLITE_ENABLE_STMT_SCANSTATUS */ /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ static Bitmask codeOneLoopStart( ................................................................................ /* Loop through table entries that match term pOrTerm. */ WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, wctrlFlags, iCovCur); assert( pSubWInfo || pParse->nErr || db->mallocFailed ); if( pSubWInfo ){ WhereLoop *pSubLoop; /* If an OP_Explain was added for this sub-loop, fix the P2 and ** P3 parameters to it so that they are relative to the current ** context. */ if( pSubWInfo->iExplain!=0 ){ sqlite3VdbeChangeP2(v, pSubWInfo->iExplain, iLevel); sqlite3VdbeChangeP3(v, pSubWInfo->iExplain, pLevel->iFrom); } /* This is the sub-WHERE clause body. First skip over ** duplicate rows from prior sub-WHERE clauses, and record the ** rowid (or PRIMARY KEY) for the current row so that the same ** row will be skipped in subsequent sub-WHERE clauses. */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ ................................................................................ pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } } /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE; testcase( pTerm->wtFlags & TERM_VIRTUAL ); ................................................................................ /* Generate the code to do the search. Each iteration of the for ** loop below generates code for a single nested loop of the VM ** program. */ notReady = ~(Bitmask)0; for(ii=0; ii<nTabList; ii++){ pLevel = &pWInfo->a[ii]; #ifndef SQLITE_OMIT_AUTOMATIC_INDEX if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){ constructAutomaticIndex(pParse, &pWInfo->sWC, &pTabList->a[pLevel->iFrom], notReady, pLevel); if( db->mallocFailed ) goto whereBeginError; } #endif explainOneScan(pParse, pTabList, pWInfo, ii, wctrlFlags); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = codeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; } /* Done. */ VdbeModuleComment((v, "Begin WHERE-core")); return pWInfo; /* Jump here if malloc fails */ |
| | | > < > > < < | < < < > < < < | < < < < < < < < < < < < < < < < < < < > > > < < < < < > | > > > | < < < | < > | < > | | > | < | | | | > > | > > > > > > > | > > > > > < < > > > < > | < > | < < < < > > > > > > > | > > > > > |
2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 .... 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 .... 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 .... 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 .... 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 .... 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 |
} } } *pzAff = zAff; return regBase; } #ifndef SQLITE_OMIT_EXPLAIN /* ** This routine is a helper for explainIndexRange() below ** ** pStr holds the text of an expression that we are building up one term ** at a time. This routine adds a new term to the end of the expression. ** Terms are separated by AND so add the "AND" text for second and subsequent ** terms only. ................................................................................ /* ** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN ** command. If the query being compiled is an EXPLAIN QUERY PLAN, a single ** record is added to the output to describe the table scan strategy in ** pLevel. */ static int explainOneScan( Parse *pParse, /* Parse context */ SrcList *pTabList, /* Table list this loop refers to */ WhereLevel *pLevel, /* Scan to write OP_Explain opcode for */ int iLevel, /* Value for "level" column of output */ int iFrom, /* Value for "from" column of output */ u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */ ){ int ret = 0; #ifndef SQLITE_DEBUG if( pParse->explain==2 ) #endif { struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ int iId = pParse->iSelectId; /* Select id (left-most output column) */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ char *zMsg; /* Text to add to EQP output */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ pLoop = pLevel->pWLoop; flags = pLoop->wsFlags; if( (flags&WHERE_MULTI_OR) || (wctrlFlags&WHERE_ONETABLE_ONLY) ) return 0; isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumInit(&str, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); str.db = db; sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ sqlite3XPrintf(&str, 0, " SUBQUERY %d", pItem->iSelectId); }else{ sqlite3XPrintf(&str, 0, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ sqlite3XPrintf(&str, 0, " AS %s", pItem->zAlias); } ................................................................................ } #ifndef SQLITE_OMIT_VIRTUALTABLE else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ sqlite3XPrintf(&str, 0, " VIRTUAL TABLE INDEX %d:%s", pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); } #endif #ifdef SQLITE_EXPLAIN_ESTIMATED_ROWS if( pLoop->nOut>=10 ){ sqlite3XPrintf(&str, 0, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); }else{ sqlite3StrAccumAppend(&str, " (~1 row)", 9); } #endif zMsg = sqlite3StrAccumFinish(&str); ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC); } return ret; } #else # define explainOneScan(u,v,w,x,y,z) 0 #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS static void addScanStatus( Vdbe *v, SrcList *pSrclist, WhereLevel *pLvl, int addrExplain ){ const char *zObj = 0; i64 nEst = 1; WhereLoop *pLoop = pLvl->pWLoop; if( (pLoop->wsFlags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 ){ zObj = pLoop->u.btree.pIndex->zName; }else{ zObj = pSrclist->a[pLvl->iFrom].zName; } if( pLoop->nOut>=10 ){ nEst = sqlite3LogEstToInt(pLoop->nOut); } sqlite3VdbeScanCounter( v, addrExplain, pLvl->addrBody, pLvl->addrVisit, nEst, zObj ); } #else # define addScanStatus(a, b, c, d) #endif /* ** Generate code for the start of the iLevel-th loop in the WHERE clause ** implementation described by pWInfo. */ static Bitmask codeOneLoopStart( ................................................................................ /* Loop through table entries that match term pOrTerm. */ WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, wctrlFlags, iCovCur); assert( pSubWInfo || pParse->nErr || db->mallocFailed ); if( pSubWInfo ){ WhereLoop *pSubLoop; int addrExplain = explainOneScan( pParse, pOrTab, &pSubWInfo->a[0], iLevel, pLevel->iFrom, 0 ); addScanStatus(v, pOrTab, &pSubWInfo->a[0], addrExplain); /* This is the sub-WHERE clause body. First skip over ** duplicate rows from prior sub-WHERE clauses, and record the ** rowid (or PRIMARY KEY) for the current row so that the same ** row will be skipped in subsequent sub-WHERE clauses. */ if( (pWInfo->wctrlFlags & WHERE_DUPLICATES_OK)==0 ){ ................................................................................ pLevel->p1 = iCur; pLevel->p2 = 1 + sqlite3VdbeAddOp2(v, aStart[bRev], iCur, addrBrk); VdbeCoverageIf(v, bRev==0); VdbeCoverageIf(v, bRev!=0); pLevel->p5 = SQLITE_STMTSTATUS_FULLSCAN_STEP; } } #ifdef SQLITE_ENABLE_STMT_SCANSTATUS pLevel->addrVisit = sqlite3VdbeCurrentAddr(v); #endif /* Insert code to test every subexpression that can be completely ** computed using the current set of tables. */ for(pTerm=pWC->a, j=pWC->nTerm; j>0; j--, pTerm++){ Expr *pE; testcase( pTerm->wtFlags & TERM_VIRTUAL ); ................................................................................ /* Generate the code to do the search. Each iteration of the for ** loop below generates code for a single nested loop of the VM ** program. */ notReady = ~(Bitmask)0; for(ii=0; ii<nTabList; ii++){ int addrExplain; int wsFlags; pLevel = &pWInfo->a[ii]; wsFlags = pLevel->pWLoop->wsFlags; #ifndef SQLITE_OMIT_AUTOMATIC_INDEX if( (pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){ constructAutomaticIndex(pParse, &pWInfo->sWC, &pTabList->a[pLevel->iFrom], notReady, pLevel); if( db->mallocFailed ) goto whereBeginError; } #endif addrExplain = explainOneScan( pParse, pTabList, pLevel, ii, pLevel->iFrom, wctrlFlags ); pLevel->addrBody = sqlite3VdbeCurrentAddr(v); notReady = codeOneLoopStart(pWInfo, ii, notReady); pWInfo->iContinue = pLevel->addrCont; if( (wsFlags&WHERE_MULTI_OR)==0 && (wctrlFlags&WHERE_ONETABLE_ONLY)==0 ){ addScanStatus(v, pTabList, pLevel, addrExplain); } } /* Done. */ VdbeModuleComment((v, "Begin WHERE-core")); return pWInfo; /* Jump here if malloc fails */ |
Changes to src/whereInt.h.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ } *aInLoop; /* Information about each nested IN operator */ } in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */ Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; struct WhereLoop *pWLoop; /* The selected WhereLoop object */ Bitmask notReady; /* FROM entries not usable at this level */ }; /* ** Each instance of this object represents an algorithm for evaluating one ** term of a join. Every term of the FROM clause will have at least ** one corresponding WhereLoop object (unless INDEXED BY constraints ** prevent a query solution - which is an error) and many terms of the |
> > > |
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
u8 eEndLoopOp; /* IN Loop terminator. OP_Next or OP_Prev */ } *aInLoop; /* Information about each nested IN operator */ } in; /* Used when pWLoop->wsFlags&WHERE_IN_ABLE */ Index *pCovidx; /* Possible covering index for WHERE_MULTI_OR */ } u; struct WhereLoop *pWLoop; /* The selected WhereLoop object */ Bitmask notReady; /* FROM entries not usable at this level */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS int addrVisit; /* Address at which row is visited */ #endif }; /* ** Each instance of this object represents an algorithm for evaluating one ** term of a join. Every term of the FROM clause will have at least ** one corresponding WhereLoop object (unless INDEXED BY constraints ** prevent a query solution - which is an error) and many terms of the |
Changes to test/scanstatus.test.
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 ... 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 ... 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 ... 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j=?)} } do_execsql_test 2.4.1 { SELECT * FROM x1 WHERE j<'two' } {4 four 1 one 3 three} do_scanstatus_test 2.4.2 { nLoop 1 nVisit 4 nEst 262144 zName x1j zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j<?)} } do_execsql_test 2.5.1 { SELECT * FROM x1 WHERE j>='two' } {2 two} do_scanstatus_test 2.5.2 { ................................................................................ zExplain {SEARCH TABLE x2 USING INDEX x2j (j>? AND j<?)} } do_execsql_test 2.8.1 { SELECT * FROM x2 WHERE i=1 AND j='two' } do_scanstatus_test 2.8.2 { nLoop 1 nVisit 1 nEst 8 zName x2ij zExplain {SEARCH TABLE x2 USING INDEX x2ij (i=? AND j=?)} } do_execsql_test 2.9.1 { SELECT * FROM x2 WHERE i=5 AND j='two' } do_scanstatus_test 2.9.2 { ................................................................................ zExplain {SEARCH TABLE x2 USING INDEX x2ij (i=? AND j=?)} } do_execsql_test 2.10.1 { SELECT * FROM x2 WHERE i=3 AND j='three' } {3 three {3 three}} do_scanstatus_test 2.10.2 { nLoop 1 nVisit 2 nEst 8 zName x2ij zExplain {SEARCH TABLE x2 USING INDEX x2ij (i=? AND j=?)} } #------------------------------------------------------------------------- # Try with queries that use the OR optimization. # do_execsql_test 3.1 { ................................................................................ WITH d(x) AS (SELECT 1 UNION ALL SELECT x+1 AS n FROM d WHERE n<=100) INSERT INTO a1 SELECT x, x, x, x FROM d; } do_execsql_test 3.2.1 { SELECT d FROM a1 WHERE (a=4 OR b=13) } {4 13} do_scanstatus_test 2.4 { nLoop 1 nVisit 2 nEst 10 zName a1a zExplain {SEARCH TABLE a1 USING INDEX a1a (a=?)} nLoop 1 nVisit 2 nEst 10 zName a1bc zExplain {SEARCH TABLE a1 USING INDEX a1bc (b=?)} } finish_test |
| | | > > > > > | > > > > | | | > > | > > > > > > > > > > > > > > > > | | > > > > > > | |
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 ... 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 ... 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 ... 183 184 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 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j=?)} } do_execsql_test 2.4.1 { SELECT * FROM x1 WHERE j<'two' } {4 four 1 one 3 three} do_scanstatus_test 2.4.2 { nLoop 1 nVisit 3 nEst 262144 zName x1j zExplain {SEARCH TABLE x1 USING COVERING INDEX x1j (j<?)} } do_execsql_test 2.5.1 { SELECT * FROM x1 WHERE j>='two' } {2 two} do_scanstatus_test 2.5.2 { ................................................................................ zExplain {SEARCH TABLE x2 USING INDEX x2j (j>? AND j<?)} } do_execsql_test 2.8.1 { SELECT * FROM x2 WHERE i=1 AND j='two' } do_scanstatus_test 2.8.2 { nLoop 1 nVisit 0 nEst 8 zName x2ij zExplain {SEARCH TABLE x2 USING INDEX x2ij (i=? AND j=?)} } do_execsql_test 2.9.1 { SELECT * FROM x2 WHERE i=5 AND j='two' } do_scanstatus_test 2.9.2 { ................................................................................ zExplain {SEARCH TABLE x2 USING INDEX x2ij (i=? AND j=?)} } do_execsql_test 2.10.1 { SELECT * FROM x2 WHERE i=3 AND j='three' } {3 three {3 three}} do_scanstatus_test 2.10.2 { nLoop 1 nVisit 1 nEst 8 zName x2ij zExplain {SEARCH TABLE x2 USING INDEX x2ij (i=? AND j=?)} } #------------------------------------------------------------------------- # Try with queries that use the OR optimization. # do_execsql_test 3.1 { ................................................................................ WITH d(x) AS (SELECT 1 UNION ALL SELECT x+1 AS n FROM d WHERE n<=100) INSERT INTO a1 SELECT x, x, x, x FROM d; } do_execsql_test 3.2.1 { SELECT d FROM a1 WHERE (a=4 OR b=13) } {4 13} do_scanstatus_test 3.2.2 { nLoop 1 nVisit 1 nEst 10 zName a1a zExplain {SEARCH TABLE a1 USING INDEX a1a (a=?)} nLoop 1 nVisit 1 nEst 10 zName a1bc zExplain {SEARCH TABLE a1 USING INDEX a1bc (b=?)} } do_execsql_test 3.2.1 { SELECT count(*) FROM a1 WHERE (a BETWEEN 4 AND 12) OR (b BETWEEN 40 AND 60) } {30} do_scanstatus_test 3.2.2 { nLoop 1 nVisit 9 nEst 16384 zName a1a zExplain {SEARCH TABLE a1 USING INDEX a1a (a>? AND a<?)} nLoop 1 nVisit 21 nEst 16384 zName a1bc zExplain {SEARCH TABLE a1 USING INDEX a1bc (b>? AND b<?)} } do_execsql_test 3.3.1 { SELECT count(*) FROM a1 AS x, a1 AS y WHERE (x.a BETWEEN 4 AND 12) AND (y.b BETWEEN 1 AND 10) } {90} do_scanstatus_test 3.2.2 { nLoop 1 nVisit 10 nEst 16384 zName a1bc zExplain {SEARCH TABLE a1 AS y USING COVERING INDEX a1bc (b>? AND b<?)} nLoop 10 nVisit 90 nEst 16384 zName a1a zExplain {SEARCH TABLE a1 AS x USING COVERING INDEX a1a (a>? AND a<?)} } do_execsql_test 3.4.1 { SELECT count(*) FROM a1 WHERE a IN (1, 5, 10, 15); } {4} do_scanstatus_test 3.4.2 { nLoop 1 nVisit 4 nEst 40 zName a1a zExplain {SEARCH TABLE a1 USING COVERING INDEX a1a (a=?)} } do_execsql_test 3.4.1 { SELECT count(*) FROM a1 WHERE rowid IN (1, 5, 10, 15); } {4} do_scanstatus_test 3.4.2 { nLoop 1 nVisit 4 nEst 4 zName a1 zExplain {SEARCH TABLE a1 USING INTEGER PRIMARY KEY (rowid=?)} } finish_test |