diff options
author | drh <drh@noemail.net> | 2008-06-20 18:13:25 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2008-06-20 18:13:25 +0000 |
commit | 16ee60fff91b43d615fbc5df51037e83abc8b424 (patch) | |
tree | eb834bdfa803e9c21af47732e52dbbf8d4acc449 /src | |
parent | 9324c8f2808e3050463e288e40627161ac9105cb (diff) | |
download | sqlite-16ee60fff91b43d615fbc5df51037e83abc8b424.tar.gz sqlite-16ee60fff91b43d615fbc5df51037e83abc8b424.zip |
Add new Compare and Jump codes to the virtual machine. Use them in the
implementation of aggregate queries. (CVS 5257)
FossilOrigin-Name: 083113652ff8f69b18cf1611710fdbbe5fbd9fef
Diffstat (limited to 'src')
-rw-r--r-- | src/select.c | 33 | ||||
-rw-r--r-- | src/vdbe.c | 49 | ||||
-rw-r--r-- | src/vdbe.h | 8 | ||||
-rw-r--r-- | src/vdbeInt.h | 3 | ||||
-rw-r--r-- | src/vdbeaux.c | 23 |
5 files changed, 88 insertions, 28 deletions
diff --git a/src/select.c b/src/select.c index f66214de0..2de5b94e6 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.431 2008/06/20 15:24:02 drh Exp $ +** $Id: select.c,v 1.432 2008/06/20 18:13:25 drh Exp $ */ #include "sqliteInt.h" @@ -1875,8 +1875,9 @@ static CollSeq *multiSelectCollSeq(Parse *pParse, Select *p, int iCol){ #ifndef SQLITE_OMIT_COMPOUND_SELECT /* -** This routine is called to process a query that is really the union -** or intersection of two or more separate queries. +** This routine is called to process a compound query form from +** two or more separate queries using UNION, UNION ALL, EXCEPT, or +** INTERSECT ** ** "p" points to the right-most of the two queries. the query on the ** left is p->pPrior. The left query could also be a compound query @@ -3291,12 +3292,10 @@ int sqlite3Select( /* The following variables hold addresses or labels for parts of the ** virtual machine program we are putting together */ int addrOutputRow; /* Start of subroutine that outputs a result row */ - int regOutputRow; /* Return address register for outputrow subroutine */ + int regOutputRow; /* Return address register for output subroutine */ int addrSetAbort; /* Set the abort flag and return */ int addrInitializeLoop; /* Start of code that initializes the input loop */ int addrTopOfLoop; /* Top of the input loop */ - int addrGroupByChange; /* Code that runs when any GROUP BY term changes */ - int addrProcessRow; /* Code to process a single input row */ int addrEnd; /* End of all processing */ int addrSortingIdx; /* The OP_OpenEphemeral for the sorting index */ int addrReset; /* Subroutine for resetting the accumulator */ @@ -3330,13 +3329,11 @@ int sqlite3Select( */ if( pGroupBy ){ KeyInfo *pKeyInfo; /* Keying information for the group by clause */ + int j1; /* Create labels that we will be needing */ - addrInitializeLoop = sqlite3VdbeMakeLabel(v); - addrGroupByChange = sqlite3VdbeMakeLabel(v); - addrProcessRow = sqlite3VdbeMakeLabel(v); /* If there is a GROUP BY clause we might need a sorting index to ** implement it. Allocate that sorting index now. If it turns out @@ -3474,15 +3471,10 @@ int sqlite3Select( sqlite3ExprCode(pParse, pGroupBy->a[j].pExpr, iBMem+j); } } - for(j=pGroupBy->nExpr-1; j>=0; j--){ - if( j==0 ){ - sqlite3VdbeAddOp3(v, OP_Eq, iAMem+j, addrProcessRow, iBMem+j); - }else{ - sqlite3VdbeAddOp3(v, OP_Ne, iAMem+j, addrGroupByChange, iBMem+j); - } - sqlite3VdbeChangeP4(v, -1, (void*)pKeyInfo->aColl[j], P4_COLLSEQ); - sqlite3VdbeChangeP5(v, SQLITE_NULLEQUAL); - } + sqlite3VdbeAddOp4(v, OP_Compare, iAMem, iBMem, pGroupBy->nExpr, + (char*)pKeyInfo, P4_KEYINFO_STATIC); + j1 = sqlite3VdbeCurrentAddr(v); + sqlite3VdbeAddOp3(v, OP_Jump, j1+1, 0, j1+1); /* Generate code that runs whenever the GROUP BY changes. ** Changes in the GROUP BY are detected by the previous code @@ -3493,7 +3485,6 @@ int sqlite3Select( ** and resets the aggregate accumulator registers in preparation ** for the next GROUP BY batch. */ - sqlite3VdbeResolveLabel(v, addrGroupByChange); for(j=0; j<pGroupBy->nExpr; j++){ sqlite3ExprCodeMove(pParse, iBMem+j, iAMem+j); } @@ -3507,7 +3498,7 @@ int sqlite3Select( /* Update the aggregate accumulators based on the content of ** the current row */ - sqlite3VdbeResolveLabel(v, addrProcessRow); + sqlite3VdbeJumpHere(v, j1); updateAccumulator(pParse, &sAggInfo); sqlite3VdbeAddOp2(v, OP_Integer, 1, iUseFlag); VdbeComment((v, "indicate data in accumulator")); @@ -3579,7 +3570,7 @@ int sqlite3Select( updateAccumulator(pParse, &sAggInfo); if( !pMinMax && flag ){ sqlite3VdbeAddOp2(v, OP_Goto, 0, pWInfo->iBreak); - VdbeComment((v, "%s() by index", (flag==WHERE_ORDERBY_MIN?"min":"max"))); + VdbeComment((v, "%s() by index",(flag==WHERE_ORDERBY_MIN?"min":"max"))); } sqlite3WhereEnd(pWInfo); finalizeAggFunctions(pParse, &sAggInfo); diff --git a/src/vdbe.c b/src/vdbe.c index 2c0d12a70..eec7b3731 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** 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.751 2008/06/20 15:24:02 drh Exp $ +** $Id: vdbe.c,v 1.752 2008/06/20 18:13:25 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1731,6 +1731,53 @@ case OP_Ge: { /* same as TK_GE, jump, in1, in3 */ break; } +/* Opcode: Compare P1 P2 P3 P4 * +** +** Compare to vectors of registers in reg(P1)..reg(P1+P3-1) (all this +** one "A") and in reg(P2)..reg(P2+P3-1) ("B"). Save the result of +** the comparison for use by the next OP_Jump instruct. +** +** P4 is a KeyInfo structure that defines collating sequences usedused for affinity purposes. The +** comparison is done for sorting purposes, so NULLs compare +** equal, NULLs are less than numbers, numbers are less than strings, +** and strings are less than blobs. +*/ +case OP_Compare: { + int n = pOp->p3; + int i, p1, p2; + const KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; + assert( n>0 ); + p1 = pOp->p1; + assert( p1>0 && p1+n-1<p->nMem ); + p2 = pOp->p2; + assert( p2>0 && p2+n-1<p->nMem ); + for(i=0; i<n; i++, p1++, p2++){ + REGISTER_TRACE(p1, &p->aMem[p1]); + REGISTER_TRACE(p2, &p->aMem[p2]); + p->iCompare = sqlite3MemCompare(&p->aMem[p1], &p->aMem[p2], + pKeyInfo && i<pKeyInfo->nField ? pKeyInfo->aColl[i] : 0); + if( p->iCompare ) break; + } + break; +} + +/* Opcode: Jump P1 P2 P3 * * +** +** Jump to the instruction at address P1, P2, or P3 depending on whether +** in the most recent OP_Compare instruction the P1 vector was less than +** equal to, or greater than the P2 vector, respectively. +*/ +case OP_Jump: { + if( p->iCompare<0 ){ + pc = pOp->p1 - 1; + }else if( p->iCompare==0 ){ + pc = pOp->p2 - 1; + }else{ + pc = pOp->p3 - 1; + } + break; +} + /* Opcode: And P1 P2 P3 * * ** ** Take the logical AND of the values in registers P1 and P2 and diff --git a/src/vdbe.h b/src/vdbe.h index 9a1e4a2de..b19e66dc2 100644 --- a/src/vdbe.h +++ b/src/vdbe.h @@ -15,7 +15,7 @@ ** or VDBE. The VDBE implements an abstract machine that runs a ** simple program to access and modify the underlying database. ** -** $Id: vdbe.h,v 1.132 2008/05/29 20:22:37 shane Exp $ +** $Id: vdbe.h,v 1.133 2008/06/20 18:13:25 drh Exp $ */ #ifndef _SQLITE_VDBE_H_ #define _SQLITE_VDBE_H_ @@ -109,7 +109,8 @@ typedef struct VdbeOpList VdbeOpList; ** from a single sqliteMalloc(). But no copy is made and the calling ** function should *not* try to free the KeyInfo. */ -#define P4_KEYINFO_HANDOFF (-9) +#define P4_KEYINFO_HANDOFF (-15) +#define P4_KEYINFO_STATIC (-16) /* ** The Vdbe.aColName array contains 5n Mem structures, where n is the @@ -193,8 +194,11 @@ int sqlite3VdbeRecordCompare(int,const void*,UnpackedRecord*); #ifndef NDEBUG void sqlite3VdbeComment(Vdbe*, const char*, ...); # define VdbeComment(X) sqlite3VdbeComment X + void sqlite3VdbeNoopComment(Vdbe*, const char*, ...); +# define VdbeNoopComment(X) sqlite3VdbeNoopComment X #else # define VdbeComment(X) +# define VdbeNoopComment(X) #endif #endif diff --git a/src/vdbeInt.h b/src/vdbeInt.h index ea8fafb62..7cbcb8e3a 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -15,7 +15,7 @@ ** 6000 lines long) it was split up into several smaller files and ** this header information was factored out. ** -** $Id: vdbeInt.h,v 1.147 2008/06/06 15:04:37 drh Exp $ +** $Id: vdbeInt.h,v 1.148 2008/06/20 18:13:25 drh Exp $ */ #ifndef _VDBEINT_H_ #define _VDBEINT_H_ @@ -321,6 +321,7 @@ struct Vdbe { u8 expired; /* True if the VM needs to be recompiled */ u8 minWriteFileFormat; /* Minimum file format for writable database files */ u8 inVtabMethod; /* See comments above */ + int iCompare; /* Result of most recent OP_Compare comparison */ int nChange; /* Number of db changes made since last reset */ i64 startTime; /* Time when query started - used for profiling */ int btreeMask; /* Bitmask of db->aDb[] entries referenced */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 762377fdc..e139fa971 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -14,7 +14,7 @@ ** to version 2.8.7, all this code was combined into the vdbe.c source file. ** But that file was getting too big so this subroutines were split out. ** -** $Id: vdbeaux.c,v 1.389 2008/06/20 14:59:51 danielk1977 Exp $ +** $Id: vdbeaux.c,v 1.390 2008/06/20 18:13:25 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -581,7 +581,10 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){ #ifndef NDEBUG /* -** Change the comment on the the most recently coded instruction. +** Change the comment on the the most recently coded instruction. Or +** insert a No-op and add the comment to that new instruction. This +** makes the code easier to read during debugging. None of this happens +** in a production build. */ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ va_list ap; @@ -595,7 +598,20 @@ void sqlite3VdbeComment(Vdbe *p, const char *zFormat, ...){ va_end(ap); } } -#endif +void sqlite3VdbeNoopComment(Vdbe *p, const char *zFormat, ...){ + va_list ap; + sqlite3VdbeAddOp0(p, OP_Noop); + assert( p->nOp>0 || p->aOp==0 ); + assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed ); + if( p->nOp ){ + char **pz = &p->aOp[p->nOp-1].zComment; + va_start(ap, zFormat); + sqlite3_free(*pz); + *pz = sqlite3VMPrintf(p->db, zFormat, ap); + va_end(ap); + } +} +#endif /* NDEBUG */ /* ** Return the opcode for a given address. @@ -616,6 +632,7 @@ static char *displayP4(Op *pOp, char *zTemp, int nTemp){ char *zP4 = zTemp; assert( nTemp>=20 ); switch( pOp->p4type ){ + case P4_KEYINFO_STATIC: case P4_KEYINFO: { int i, j; KeyInfo *pKeyInfo = pOp->p4.pKeyInfo; |