From a2a49dc9dfb6a341680d2d528a9567ea1f666569 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 2 Jan 2008 14:28:13 +0000 Subject: [PATCH] Add opcodes OP_ResultRow and OP_RegMakeRec which are register-based equivalents to OP_Callback and OP_MakeRecord. Use the new opcodes. (CVS 4656) FossilOrigin-Name: 4c7f35da7751c61a9b61b1d95adddcc37fff3266 --- manifest | 18 ++++++------ manifest.uuid | 2 +- src/analyze.c | 4 +-- src/expr.c | 9 +++--- src/select.c | 76 ++++++++++++++++++++++++++++++++++++--------------- src/vdbe.c | 34 +++++++++++++++++------ 6 files changed, 96 insertions(+), 47 deletions(-) diff --git a/manifest b/manifest index e078a51246..d7caafca7f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\sa\ssurplus\sOP_Close\sfrom\sdelete.c.\s\sFixes\sa\sproblem\swith\s(4654).\s(CVS\s4655) -D 2008-01-02T13:05:51 +C Add\sopcodes\sOP_ResultRow\sand\sOP_RegMakeRec\swhich\sare\sregister-based\nequivalents\sto\sOP_Callback\sand\sOP_MakeRecord.\s\sUse\sthe\snew\sopcodes.\s(CVS\s4656) +D 2008-01-02T14:28:13 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 30789bf70614bad659351660d76b8e533f3340e9 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -79,7 +79,7 @@ F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.def a96c1d0d39362b763d2ddba220a32da41a15c4b4 F sqlite3.pc.in abed4664817e1cd500f2276142c71958087c16bc F src/alter.c 23d18ec53ef27fcb5e5ae9ca050217231ae15a0d -F src/analyze.c cb25936f0148ee65c825a49f8064292a98050a50 +F src/analyze.c 40806c79cf2cd4fd0f6396d3d283fa05711439d1 F src/attach.c 95658e74e3e0d1cbdb8658817516d4d1467fc13d F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/btmutex.c 5d39da37c9d1282f3c6f9967afae6a34ee36b7ff @@ -92,7 +92,7 @@ F src/complete.c 4cf68fd75d60257524cbe74f87351b9848399131 F src/date.c 49c5a6d2de6c12000905b4d36868b07d3011bbf6 F src/delete.c 9a98d854ac2613d14616f5023577a6bec53b2d0e F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b -F src/expr.c c3fb939d6801071ce19243521ca444eca40b057a +F src/expr.c 9f46128496d750edc0a2b32585a109defd9ce74c F src/func.c 996071cf0af9d967e58b69fce1909555059ebc7d F src/hash.c 45a7005aac044b6c86bd7e49c44bc15d30006d6c F src/hash.h 031cd9f915aff27e12262cb9eb570ac1b8326b53 @@ -131,7 +131,7 @@ F src/pragma.c 4a7f377a509eb14e35b09d4bf7b808ef647aad0b F src/prepare.c 7aeba7851773fbe3950a26b35d3389bef0eb1c62 F src/printf.c eb27822ba2eec669161409ca31279a24c26ac910 F src/random.c 4a22746501bf36b0a088c66e38dde5daba6a35da -F src/select.c 55b1a99e1d28a6ec3db2870a9f3f932fb3e7cb2a +F src/select.c c0a225dc3133f914760908c7a73fce83b2834fbb F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96 F src/shell.c 77895a54c2082157e169c857a2e244525ec25af7 F src/sqlite.h.in 2a7e3776534bbe6ff2cdc058f3abebe91e7e429f @@ -168,7 +168,7 @@ F src/update.c 24ab2157d360bc20ac4447f50d3a70cd993a7d98 F src/utf.c ef4b7d83bae533b76c3e1bf635b113fdad86a736 F src/util.c 05f31144bbd3f1a24f4139ae029c42545cb72624 F src/vacuum.c 25ffbd766f25bca099ead1c1e11f5528c86102b8 -F src/vdbe.c 56a6e80d3357622305cffe6ea509e5d643e7dadb +F src/vdbe.c 85e44649ad750d4c249751693ca93b4f57737b0f F src/vdbe.h a042e6d3b567ac81f182ca5b4639807621355822 F src/vdbeInt.h 2985f1369273e635898cf5952237efcb3fdb21f3 F src/vdbeapi.c 4acfaab3e10c99eb66c5332979d7b14a1c3505ae @@ -603,7 +603,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P f1966a8a47fca85f7862c0797a527ab01ac8b0c1 -R 087c5875afd19f460dd964b443ff0b13 +P 03cc91b3b0ff9be192532f8a404b3c7b827e1449 +R 7a6df4f12366724f53264755c79c306d U drh -Z 539bcbd7c9fe31e2d5dc24d68f84bb81 +Z 99aefce3e13cf9b619d1d8015ce6d124 diff --git a/manifest.uuid b/manifest.uuid index c38acced6c..79c505e502 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -03cc91b3b0ff9be192532f8a404b3c7b827e1449 \ No newline at end of file +4c7f35da7751c61a9b61b1d95adddcc37fff3266 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 13e3ad34b1..8228d416c6 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code associated with the ANALYZE command. ** -** @(#) $Id: analyze.c,v 1.25 2008/01/02 00:34:37 drh Exp $ +** @(#) $Id: analyze.c,v 1.26 2008/01/02 14:28:13 drh Exp $ */ #ifndef SQLITE_OMIT_ANALYZE #include "sqliteInt.h" @@ -149,7 +149,7 @@ static void analyzeOneTable( sqlite3VdbeAddOp(v, OP_MemInt, 0, iMem+i); } for(i=0; i @@ -1798,14 +1798,14 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ */ static const Token one = { (u8*)"1", 0, 1 }; Select *pSel; - int iMem; int sop; + int iMem; - pExpr->iColumn = iMem = pParse->nMem++; pSel = pExpr->pSelect; + iMem = pParse->nMem++; if( pExpr->op==TK_SELECT ){ sop = SRT_Mem; - sqlite3VdbeAddOp(v, OP_MemNull, iMem, 0); + sqlite3VdbeAddOp(v, OP_MemNull, 0, iMem); VdbeComment((v, "Init subquery result")); }else{ sop = SRT_Exists; @@ -1817,6 +1817,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ if( sqlite3Select(pParse, pSel, sop, iMem, 0, 0, 0, 0) ){ return; } + pExpr->iColumn = iMem; break; } } diff --git a/src/select.c b/src/select.c index 23f2c70a21..e684966ba4 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.374 2008/01/02 00:34:37 drh Exp $ +** $Id: select.c,v 1.375 2008/01/02 14:28:13 drh Exp $ */ #include "sqliteInt.h" @@ -436,7 +436,7 @@ static void codeOffset( ** A jump to addrRepeat is made and the N+1 values are popped from the ** stack if the top N elements are not distinct. */ -static void codeDistinct( +static void codeDistinct_OLD( Vdbe *v, /* Generate code into this VM */ int iTab, /* A sorting index used to test for distinctness */ int addrRepeat, /* Jump to here if not distinct */ @@ -450,6 +450,29 @@ static void codeDistinct( sqlite3VdbeAddOp(v, OP_IdxInsert, iTab, 0); } +/* +** Add code that will check to make sure the top N elements of the +** stack are distinct. iTab is a sorting index that holds previously +** seen combinations of the N values. A new entry is made in iTab +** if the current N values are new. +** +** A jump to addrRepeat is made and the N+1 values are popped from the +** stack if the top N elements are not distinct. +*/ +static void codeDistinct( + Vdbe *v, /* Generate code into this VM */ + int iTab, /* A sorting index used to test for distinctness */ + int addrRepeat, /* Jump to here if not distinct */ + int iMem /* First element */ +){ + sqlite3VdbeAddOp(v, OP_RegMakeRec, iMem, 0); + sqlite3VdbeAddOp(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3); + sqlite3VdbeAddOp(v, OP_Pop, 1, 0); + sqlite3VdbeAddOp(v, OP_Goto, 0, addrRepeat); + VdbeComment((v, "skip indistinct records")); + sqlite3VdbeAddOp(v, OP_IdxInsert, iTab, 0); +} + /* ** Generate an error message when a SELECT is used within a subexpression ** (example: "a IN (SELECT * FROM table)") but it has more than 1 result @@ -490,8 +513,9 @@ static int selectInnerLoop( char *aff /* affinity string if eDest is SRT_Union */ ){ Vdbe *v = pParse->pVdbe; - int i; + int i, n; int hasDistinct; /* True if the DISTINCT keyword is present */ + int iMem; /* Start of memory holding result set */ if( v==0 ) return 0; assert( pEList!=0 ); @@ -506,14 +530,24 @@ static int selectInnerLoop( /* Pull the requested columns. */ + if( nColumn>0 ){ + n = nColumn; + }else{ + n = pEList->nExpr; + } + iMem = pParse->nMem; + pParse->nMem += n+1; + sqlite3VdbeAddOp(v, OP_MemInt, n, iMem); if( nColumn>0 ){ for(i=0; inExpr; - sqlite3ExprCodeExprList(pParse, pEList); + for(i=0; ia[i].pExpr, iMem+i+1); + } } + nColumn = n; /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row @@ -522,7 +556,7 @@ static int selectInnerLoop( if( hasDistinct ){ assert( pEList!=0 ); assert( pEList->nExpr==nColumn ); - codeDistinct(v, distinct, iContinue, nColumn); + codeDistinct(v, distinct, iContinue, iMem); if( pOrderBy==0 ){ codeOffset(v, p, iContinue, nColumn); } @@ -538,7 +572,7 @@ static int selectInnerLoop( */ #ifndef SQLITE_OMIT_COMPOUND_SELECT case SRT_Union: { - sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); + sqlite3VdbeAddOp(v, OP_RegMakeRec, iMem, 0); if( aff ){ sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC); } @@ -552,7 +586,7 @@ static int selectInnerLoop( */ case SRT_Except: { int addr; - addr = sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); + addr = sqlite3VdbeAddOp(v, OP_RegMakeRec, iMem, 0); sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC); sqlite3VdbeAddOp(v, OP_NotFound, iParm, addr+3); sqlite3VdbeAddOp(v, OP_Delete, iParm, 0); @@ -564,7 +598,7 @@ static int selectInnerLoop( */ case SRT_Table: case SRT_EphemTab: { - sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); + sqlite3VdbeAddOp(v, OP_RegMakeRec, iMem, 0); if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p); }else{ @@ -581,22 +615,20 @@ static int selectInnerLoop( ** item into the set table with bogus data. */ case SRT_Set: { - int addr1 = sqlite3VdbeCurrentAddr(v); int addr2; assert( nColumn==1 ); - sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3); - sqlite3VdbeAddOp(v, OP_Pop, 1, 0); - addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); + addr2 = sqlite3VdbeAddOp(v, OP_IfMemNull, iMem+1, 0); p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr,(iParm>>16)&0xff); if( pOrderBy ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ + sqlite3VdbeAddOp(v, OP_MemLoad, iMem+1, 0); pushOntoSorter(pParse, pOrderBy, p); }else{ - sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &p->affinity, 1); + sqlite3VdbeOp3(v, OP_RegMakeRec, iMem, 0, &p->affinity, 1); sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); } sqlite3VdbeJumpHere(v, addr2); @@ -607,7 +639,6 @@ static int selectInnerLoop( */ case SRT_Exists: { sqlite3VdbeAddOp(v, OP_MemInt, 1, iParm); - sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); /* The LIMIT clause will terminate the loop for us */ break; } @@ -618,6 +649,7 @@ static int selectInnerLoop( */ case SRT_Mem: { assert( nColumn==1 ); + sqlite3VdbeAddOp(v, OP_MemLoad, iMem+1, 0); if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p); }else{ @@ -635,12 +667,13 @@ static int selectInnerLoop( case SRT_Subroutine: case SRT_Callback: { if( pOrderBy ){ - sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); + sqlite3VdbeAddOp(v, OP_RegMakeRec, iMem, 0); pushOntoSorter(pParse, pOrderBy, p); }else if( eDest==SRT_Subroutine ){ + for(i=0; inColumn; i++){ - sqlite3VdbeAddOp(v, OP_MemNull, pAggInfo->aCol[i].iMem, 0); + sqlite3VdbeAddOp(v, OP_MemNull, 0, pAggInfo->aCol[i].iMem); } for(pFunc=pAggInfo->aFunc, i=0; inFunc; i++, pFunc++){ - sqlite3VdbeAddOp(v, OP_MemNull, pFunc->iMem, 0); + sqlite3VdbeAddOp(v, OP_MemNull, 0, pFunc->iMem); if( pFunc->iDistinct>=0 ){ Expr *pE = pFunc->pExpr; if( pE->pList==0 || pE->pList->nExpr!=1 ){ @@ -2934,7 +2966,7 @@ static void updateAccumulator(Parse *pParse, AggInfo *pAggInfo){ if( pF->iDistinct>=0 ){ addrNext = sqlite3VdbeMakeLabel(v); assert( nArg==1 ); - codeDistinct(v, pF->iDistinct, addrNext, 1); + codeDistinct_OLD(v, pF->iDistinct, addrNext, 1); } if( pF->pFunc->needCollSeq ){ CollSeq *pColl = 0; diff --git a/src/vdbe.c b/src/vdbe.c index 4c1071e21a..1bfb812210 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.662 2008/01/02 00:34:37 drh Exp $ +** $Id: vdbe.c,v 1.663 2008/01/02 14:28:13 drh Exp $ */ #include "sqliteInt.h" #include @@ -2384,6 +2384,7 @@ case OP_MakeRecord: { u32 serial_type; /* Type field */ int containsNull = 0; /* True if any of the data fields are NULL */ Mem *pData0; /* Bottom of the stack */ + Mem *pLast; /* Top of the stack */ int leaveOnStack; /* If true, leave the entries on the stack */ int nField; /* Number of fields in the record */ int jumpIfNull; /* Jump here if non-zero and any entries are NULL. */ @@ -2411,11 +2412,13 @@ case OP_MakeRecord: { pCount = &p->aMem[nField]; assert( pCount->flags & MEM_Int ); assert( pCount->u.i>=0 && pCount->u.i+nFieldnMem ); - assert( leaveOnStack==1 ); + leaveOnStack = 1; nField = pCount->u.i; pData0 = &pCount[1]; + pLast = &pData0[nField-1]; }else{ pData0 = &pTos[1-nField]; + pLast = pTos; assert( pData0>=p->aStack ); } containsNull = 0; @@ -2424,7 +2427,7 @@ case OP_MakeRecord: { /* Loop through the elements that will make up the record to figure ** out how much space is required for the new record. */ - for(pRec=pData0; pRec<=pTos; pRec++){ + for(pRec=pData0; pRec<=pLast; pRec++){ int len; if( zAffinity ){ applyAffinity(pRec, zAffinity[pRec-pData0], encoding); @@ -2484,14 +2487,14 @@ case OP_MakeRecord: { /* Write the record */ i = sqlite3PutVarint(zNewRecord, nHdr); - for(pRec=pData0; pRec<=pTos; pRec++){ + for(pRec=pData0; pRec<=pLast; pRec++){ serial_type = sqlite3VdbeSerialType(pRec, file_format); i += sqlite3PutVarint(&zNewRecord[i], serial_type); /* serial type */ } if( addRowid ){ i += sqlite3PutVarint(&zNewRecord[i], sqlite3VdbeSerialType(pRowid, 0)); } - for(pRec=pData0; pRec<=pTos; pRec++){ /* serial data */ + for(pRec=pData0; pRec<=pLast; pRec++){ /* serial data */ i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format); } if( addRowid ){ @@ -4719,13 +4722,26 @@ case OP_IfMemZero: { /* no-push */ break; } -/* Opcode: MemNull P1 * * +/* Opcode: IfMemNull P1 P2 * +** +** If the value of memory cell P1 is NULL, jump to P2. +*/ +case OP_IfMemNull: { /* no-push */ + int i = pOp->p1; + assert( i>=0 && inMem ); + if( p->aMem[i].flags & MEM_Null ){ + pc = pOp->p2 - 1; + } + break; +} + +/* Opcode: MemNull * P2 * ** -** Store a NULL in memory cell P1 +** Store a NULL in memory cell P2 */ case OP_MemNull: { - assert( pOp->p1>=0 && pOp->p1nMem ); - sqlite3VdbeMemSetNull(&p->aMem[pOp->p1]); + assert( pOp->p2>=0 && pOp->p2nMem ); + sqlite3VdbeMemSetNull(&p->aMem[pOp->p2]); break; } -- 2.47.3