Continued refactoring of the name resolution logic and query optimizer. (CVS 2236)

FossilOrigin-Name: d8b2a7e09187564fe66a2b4bf0992c6a017146cf
diff --git a/src/expr.c b/src/expr.c
index 88ca91f..0256934 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.181 2005/01/18 17:20:10 drh Exp $
+** $Id: expr.c,v 1.182 2005/01/19 23:24:50 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -1095,6 +1095,9 @@
   return 0;
 }
 
+/* Forward declaration */
+static int sqlite3ExprCodeSubquery(Parse*, NameContext*, Expr*);
+
 /*
 ** This routine walks an expression tree and resolves references to
 ** table columns.  Nodes of the form ID.ID or ID resolve into an
@@ -1117,12 +1120,13 @@
 ** property on the expression.
 */
 int sqlite3ExprResolveNames(
-  Parse *pParse,     /* The parser context */
-  SrcList *pSrcList, /* List of tables used to resolve column names */
-  ExprList *pEList,  /* List of expressions used to resolve "AS" */
-  Expr *pExpr,       /* The expression to be analyzed. */
-  int allowAgg,      /* True to allow aggregate expressions */
-  int codeSubquery   /* If true, then generate code for subqueries too */
+  Parse *pParse,          /* The parser context */
+  SrcList *pSrcList,      /* List of tables used to resolve column names */
+  ExprList *pEList,       /* List of expressions used to resolve "AS" */
+  NameContext *pNC,       /* Namespace of enclosing statement */
+  Expr *pExpr,            /* The expression to be analyzed. */
+  int allowAgg,           /* True to allow aggregate expressions */
+  int codeSubquery        /* If true, then generate code for subqueries too */
 ){
   NameContext sNC;
 
@@ -1132,18 +1136,29 @@
   sNC.pParse = pParse;
   sNC.pEList = pEList;
   sNC.allowAgg = allowAgg;
+  sNC.pNext = pNC;
   walkExprTree(pExpr, nameResolverStep, &sNC);
   if( sNC.hasAgg ){
     ExprSetProperty(pExpr, EP_Agg);
   }
   if( sNC.nErr>0 ){
     ExprSetProperty(pExpr, EP_Error);
-  }else if( codeSubquery  && sqlite3ExprCodeSubquery(pParse, pExpr) ){
+  }else if( codeSubquery  && sqlite3ExprCodeSubquery(pParse, &sNC, pExpr) ){
     return 1;
   }
   return ExprHasProperty(pExpr, EP_Error);
 }
 
+/*
+** A pointer instance of this structure is used to pass information
+** through walkExprTree into codeSubqueryStep().
+*/
+typedef struct QueryCoder QueryCoder;
+struct QueryCoder {
+  Parse *pParse;       /* The parsing context */
+  NameContext *pNC;    /* Namespace of first enclosing query */
+};
+
 
 /*
 ** Generate code for subqueries and IN operators.
@@ -1167,7 +1182,8 @@
 ** additional information.
 */
 static int codeSubqueryStep(void *pArg, Expr *pExpr){
-  Parse *pParse = (Parse*)pArg;
+  QueryCoder *pCoder = (QueryCoder*)pArg;
+  Parse *pParse = pCoder->pParse;
 
   switch( pExpr->op ){
     case TK_IN: {
@@ -1207,7 +1223,7 @@
         int iParm = pExpr->iTable +  (((int)affinity)<<16);
         ExprList *pEList;
         assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
-        sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0);
+        sqlite3Select(pParse, pExpr->pSelect, SRT_Set, iParm, 0, 0, 0, 0, 0);
         pEList = pExpr->pSelect->pEList;
         if( pEList && pEList->nExpr>0 ){ 
           keyInfo.aColl[0] = binaryCompareCollSeq(pParse, pExpr->pLeft,
@@ -1237,7 +1253,7 @@
               "right-hand side of IN operator must be constant");
             return 2;
           }
-          if( sqlite3ExprResolveNames(pParse, 0, 0, pE2, 0, 0) ){
+          if( sqlite3ExprResolveNames(pParse, 0, 0, 0, pE2, 0, 0) ){
             return 2;
           }
 
@@ -1257,8 +1273,27 @@
       ** value of this select in a memory cell and record the number
       ** of the memory cell in iColumn.
       */
+      NameContext *pNC;
+      int nRef;
+      Vdbe *v;
+      int addr;
+
+      pNC = pCoder->pNC;
+      if( pNC ) nRef = pNC->nRef;
+      v = sqlite3GetVdbe(pParse);
+      addr = sqlite3VdbeAddOp(v, OP_Goto, 0, 0);
       pExpr->iColumn = pParse->nMem++;
-      sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0);
+      sqlite3Select(pParse, pExpr->pSelect, SRT_Mem,pExpr->iColumn,0,0,0,0,pNC);
+      if( pNC && pNC->nRef>nRef ){
+        /* Subquery value changes.  Evaluate at each use */
+        pExpr->iTable = addr+1;
+        sqlite3VdbeAddOp(v, OP_Return, 0, 0);
+        sqlite3VdbeChangeP2(v, addr, sqlite3VdbeCurrentAddr(v));
+      }else{
+        /* Subquery value is constant.  evaluate only once. */
+        pExpr->iTable = -1;
+        sqlite3VdbeChangeP2(v, addr, addr+1);
+      }
       return 1;
     }
   }
@@ -1269,8 +1304,15 @@
 ** Generate code to evaluate subqueries and IN operators contained
 ** in expression pExpr.
 */
-int sqlite3ExprCodeSubquery(Parse *pParse, Expr *pExpr){
-  walkExprTree(pExpr, codeSubqueryStep, pParse);
+static int sqlite3ExprCodeSubquery(
+  Parse *pParse,       /* Parser */
+  NameContext *pNC,    /* First enclosing namespace.  Often NULL */
+  Expr *pExpr          /* Subquery to be coded */
+){
+  QueryCoder sCoder;
+  sCoder.pParse = pParse;
+  sCoder.pNC = pNC;
+  walkExprTree(pExpr, codeSubqueryStep, &sCoder);
   return 0;
 }
 
@@ -1478,6 +1520,10 @@
       break;
     }
     case TK_SELECT: {
+      if( pExpr->iTable>=0 ){
+        sqlite3VdbeAddOp(v, OP_Gosub, 0, pExpr->iTable);
+        VdbeComment((v, "# run subquery"));
+      }
       sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iColumn, 0);
       VdbeComment((v, "# load subquery result"));
       break;