Fix a code generator bug caused by the new CSE optimization. Add test cases
to prevent a recurrence. (CVS 5011)
FossilOrigin-Name: d04246a46399e839e70b1bd57e209f80143f0d5b
diff --git a/src/expr.c b/src/expr.c
index 3002ef7..f58743b 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.366 2008/04/11 15:36:03 drh Exp $
+** $Id: expr.c,v 1.367 2008/04/15 12:14:22 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -2104,6 +2104,24 @@
}
/*
+** If the last instruction coded is an ephemeral copy of any of
+** the registers in the nReg registers beginning with iReg, then
+** convert the last instruction from OP_SCopy to OP_Copy.
+*/
+void sqlite3ExprHardCopy(Parse *pParse, int iReg, int nReg){
+ int addr;
+ VdbeOp *pOp;
+ Vdbe *v;
+
+ v = pParse->pVdbe;
+ addr = sqlite3VdbeCurrentAddr(v);
+ pOp = sqlite3VdbeGetOp(v, addr-1);
+ if( pOp->opcode==OP_SCopy && pOp->p1>=iReg && pOp->p1<iReg+nReg ){
+ pOp->opcode = OP_Copy;
+ }
+}
+
+/*
** Generate code into the current Vdbe to evaluate the given
** expression. Attempt to store the results in register "target".
** Return the register where results are stored.
@@ -2374,7 +2392,7 @@
if( pList ){
nExpr = pList->nExpr;
r1 = sqlite3GetTempRange(pParse, nExpr);
- sqlite3ExprCodeExprList(pParse, pList, r1);
+ sqlite3ExprCodeExprList(pParse, pList, r1, 1);
}else{
nExpr = r1 = 0;
}
@@ -2804,7 +2822,8 @@
int sqlite3ExprCodeExprList(
Parse *pParse, /* Parsing context */
ExprList *pList, /* The expression list to be coded */
- int target /* Where to write results */
+ int target, /* Where to write results */
+ int doHardCopy /* Call sqlite3ExprHardCopy on each element if true */
){
struct ExprList_item *pItem;
int i, n;
@@ -2814,9 +2833,9 @@
}
assert( target>0 );
n = pList->nExpr;
- for(pItem=pList->a, i=n; i>0; i--, pItem++){
- sqlite3ExprCode(pParse, pItem->pExpr, target);
- target++;
+ for(pItem=pList->a, i=0; i<n; i++, pItem++){
+ sqlite3ExprCode(pParse, pItem->pExpr, target+i);
+ if( doHardCopy ) sqlite3ExprHardCopy(pParse, target, n);
}
return n;
}
diff --git a/src/select.c b/src/select.c
index 89fe2e1..4b9f1df 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.426 2008/04/10 13:33:18 drh Exp $
+** $Id: select.c,v 1.427 2008/04/15 12:14:22 drh Exp $
*/
#include "sqliteInt.h"
@@ -422,7 +422,7 @@
int nExpr = pOrderBy->nExpr;
int regBase = sqlite3GetTempRange(pParse, nExpr+2);
int regRecord = sqlite3GetTempReg(pParse);
- sqlite3ExprCodeExprList(pParse, pOrderBy, regBase);
+ sqlite3ExprCodeExprList(pParse, pOrderBy, regBase, 0);
sqlite3VdbeAddOp2(v, OP_Sequence, pOrderBy->iECursor, regBase+nExpr);
sqlite3ExprCodeMove(pParse, regData, regBase+nExpr+1);
sqlite3VdbeAddOp3(v, OP_MakeRecord, regBase, nExpr + 2, regRecord);
@@ -580,9 +580,7 @@
/* If the destination is an EXISTS(...) expression, the actual
** values returned by the SELECT are not required.
*/
- for(i=0; i<nResultCol; i++){
- sqlite3ExprCode(pParse, pEList->a[i].pExpr, regResult+i);
- }
+ sqlite3ExprCodeExprList(pParse, pEList, regResult, eDest==SRT_Callback);
}
nColumn = nResultCol;
@@ -2902,7 +2900,7 @@
if( pList ){
nArg = pList->nExpr;
regAgg = sqlite3GetTempRange(pParse, nArg);
- sqlite3ExprCodeExprList(pParse, pList, regAgg);
+ sqlite3ExprCodeExprList(pParse, pList, regAgg, 0);
}else{
nArg = 0;
regAgg = 0;
@@ -3432,7 +3430,7 @@
}
}
regBase = sqlite3GetTempRange(pParse, nCol);
- sqlite3ExprCodeExprList(pParse, pGroupBy, regBase);
+ sqlite3ExprCodeExprList(pParse, pGroupBy, regBase, 0);
sqlite3VdbeAddOp2(v, OP_Sequence, sAggInfo.sortingIdx,regBase+nGroupBy);
j = nGroupBy+1;
for(i=0; i<sAggInfo.nColumn; i++){
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index b6f5b1e..6ff5b1f 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.691 2008/04/10 16:47:42 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.692 2008/04/15 12:14:22 drh Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
@@ -1872,12 +1872,13 @@
void sqlite3ExprClearColumnCache(Parse*, int);
void sqlite3ExprCacheAffinityChange(Parse*, int, int);
int sqlite3ExprWritableRegister(Parse*,int,int);
+void sqlite3ExprHardCopy(Parse*,int,int);
int sqlite3ExprCode(Parse*, Expr*, int);
int sqlite3ExprCodeTemp(Parse*, Expr*, int*);
int sqlite3ExprCodeTarget(Parse*, Expr*, int);
int sqlite3ExprCodeAndCache(Parse*, Expr*, int);
void sqlite3ExprCodeConstants(Parse*, Expr*);
-int sqlite3ExprCodeExprList(Parse*, ExprList*, int);
+int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int);
void sqlite3ExprIfTrue(Parse*, Expr*, int, int);
void sqlite3ExprIfFalse(Parse*, Expr*, int, int);
Table *sqlite3FindTable(sqlite3*,const char*, const char*);
diff --git a/src/test_func.c b/src/test_func.c
index 478474c..50d7bd6 100644
--- a/src/test_func.c
+++ b/src/test_func.c
@@ -12,7 +12,7 @@
** Code for testing all sorts of SQLite interfaces. This code
** implements new SQL functions used by the test scripts.
**
-** $Id: test_func.c,v 1.4 2008/04/10 17:14:07 drh Exp $
+** $Id: test_func.c,v 1.5 2008/04/15 12:14:22 drh Exp $
*/
#include "sqlite3.h"
#include "tcl.h"
@@ -204,6 +204,33 @@
}
}
+/*
+** This function takes two arguments. It performance UTF-8/16 type
+** conversions on the first argument then returns a copy of the second
+** argument.
+**
+** This function is used in cases such as the following:
+**
+** SELECT test_isolation(x,x) FROM t1;
+**
+** We want to verify that the type conversions that occur on the
+** first argument do not invalidate the second argument.
+*/
+static void test_isolation(
+ sqlite3_context *pCtx,
+ int nArg,
+ sqlite3_value **argv
+){
+#ifndef SQLITE_OMIT_UTF16
+ sqlite3_value_text16(argv[0]);
+ sqlite3_value_text(argv[0]);
+ sqlite3_value_text16(argv[0]);
+ sqlite3_value_text(argv[0]);
+#endif
+ sqlite3_result_value(pCtx, argv[1]);
+}
+
+
static int registerTestFunctions(sqlite3 *db){
static const struct {
char *zName;
@@ -218,6 +245,7 @@
{ "test_auxdata", -1, SQLITE_UTF8, test_auxdata},
{ "test_error", 1, SQLITE_UTF8, test_error},
{ "test_error", 2, SQLITE_UTF8, test_error},
+ { "test_isolation", 2, SQLITE_UTF8, test_isolation},
};
int i;
extern int Md5_Register(sqlite3*);
diff --git a/src/vdbe.c b/src/vdbe.c
index 7a45f64..07bd6b9 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.729 2008/04/10 14:00:10 drh Exp $
+** $Id: vdbe.c,v 1.730 2008/04/15 12:14:22 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -880,6 +880,7 @@
if( SQLITE_OK!=sqlite3VdbeMemDynamicify(pOut) ) goto no_mem;
pOut->zMalloc = 0;
pOut->flags |= MEM_Static;
+ pOut->flags &= ~MEM_Dyn;
if( pOp->p4type==P4_DYNAMIC ){
sqlite3_free(pOp->p4.z);
}