aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2008-06-20 18:13:25 +0000
committerdrh <drh@noemail.net>2008-06-20 18:13:25 +0000
commit16ee60fff91b43d615fbc5df51037e83abc8b424 (patch)
treeeb834bdfa803e9c21af47732e52dbbf8d4acc449 /src
parent9324c8f2808e3050463e288e40627161ac9105cb (diff)
downloadsqlite-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.c33
-rw-r--r--src/vdbe.c49
-rw-r--r--src/vdbe.h8
-rw-r--r--src/vdbeInt.h3
-rw-r--r--src/vdbeaux.c23
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;