When materializing a view for an UPDATE or DELETE make use of the WHERE
clause to limit the number of rows materialized.  Ticket #2938. (CVS 4782)

FossilOrigin-Name: 5ab71c3a79cac04cb2c576f83a62218d05571006
diff --git a/src/delete.c b/src/delete.c
index 5fffc8e..94839c9 100644
--- a/src/delete.c
+++ b/src/delete.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** in order to generate code for DELETE FROM statements.
 **
-** $Id: delete.c,v 1.160 2008/01/25 15:04:50 drh Exp $
+** $Id: delete.c,v 1.161 2008/02/12 16:52:14 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -81,6 +81,39 @@
 }
 
 
+#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
+/*
+** Evaluate a view and store its result in an ephemeral table.  The
+** pWhere argument is an optional WHERE clause that restricts the
+** set of rows in the view that are to be added to the ephemeral table.
+*/
+void sqlite3MaterializeView(
+  Parse *pParse,       /* Parsing context */
+  Select *pView,       /* View definition */
+  Expr *pWhere,        /* Optional WHERE clause to be added */
+  u32 col_mask,        /* Render only the columns in this mask. */
+  int iCur             /* Cursor number for ephemerial table */
+){
+  SelectDest dest;
+  Select *pDup;
+  sqlite3 *db = pParse->db;
+
+  pDup = sqlite3SelectDup(db, pView);
+  if( pWhere ){
+    SrcList *pFrom;
+    
+    pWhere = sqlite3ExprDup(db, pWhere);
+    pFrom = sqlite3SrcListAppendFromTerm(pParse, 0, 0, 0, 0, pDup, 0, 0);
+    pDup = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
+  }
+  sqlite3SelectMask(pParse, pDup, col_mask);
+  sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
+  sqlite3Select(pParse, pDup, &dest, 0, 0, 0, 0);
+  sqlite3SelectDelete(pDup);
+}
+#endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */
+
+
 /*
 ** Generate code for a DELETE FROM statement.
 **
@@ -170,19 +203,13 @@
     oldIdx = pParse->nTab++;
   }
 
-  /* Resolve the column names in the WHERE clause.
+  /* Assign  cursor number to the table and all its indices.
   */
   assert( pTabList->nSrc==1 );
   iCur = pTabList->a[0].iCursor = pParse->nTab++;
   for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
     pParse->nTab++;
   }
-  memset(&sNC, 0, sizeof(sNC));
-  sNC.pParse = pParse;
-  sNC.pSrcList = pTabList;
-  if( sqlite3ExprResolveNames(&sNC, pWhere) ){
-    goto delete_from_cleanup;
-  }
 
   /* Start the view context
   */
@@ -221,14 +248,16 @@
   ** a ephemeral table.
   */
   if( isView ){
-    SelectDest dest;
-    Select *pView;
+    sqlite3MaterializeView(pParse, pTab->pSelect, pWhere, old_col_mask, iCur);
+  }
 
-    pView = sqlite3SelectDup(db, pTab->pSelect);
-    sqlite3SelectMask(pParse, pView, old_col_mask);
-    sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
-    sqlite3Select(pParse, pView, &dest, 0, 0, 0, 0);
-    sqlite3SelectDelete(pView);
+  /* Resolve the column names in the WHERE clause.
+  */
+  memset(&sNC, 0, sizeof(sNC));
+  sNC.pParse = pParse;
+  sNC.pSrcList = pTabList;
+  if( sqlite3ExprResolveNames(&sNC, pWhere) ){
+    goto delete_from_cleanup;
   }
 
   /* Initialize the counter of the number of rows deleted, if
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 2f26f58..f9087f7 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.659 2008/02/02 04:47:09 danielk1977 Exp $
+** @(#) $Id: sqliteInt.h,v 1.660 2008/02/12 16:52:14 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1826,6 +1826,7 @@
 int sqlite3SafetyCheckOk(sqlite3*);
 int sqlite3SafetyCheckSickOrOk(sqlite3*);
 void sqlite3ChangeCookie(Parse*, int);
+void sqlite3MaterializeView(Parse*, Select*, Expr*, u32, int);
 
 #ifndef SQLITE_OMIT_TRIGGER
   void sqlite3BeginTrigger(Parse*, Token*,Token*,int,int,IdList*,SrcList*,
diff --git a/src/update.c b/src/update.c
index fb45563..5c21ab8 100644
--- a/src/update.c
+++ b/src/update.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle UPDATE statements.
 **
-** $Id: update.c,v 1.170 2008/01/19 03:35:59 drh Exp $
+** $Id: update.c,v 1.171 2008/02/12 16:52:14 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -289,13 +289,6 @@
   }
 #endif
 
-  /* Resolve the column names in all the expressions in the
-  ** WHERE clause.
-  */
-  if( sqlite3ExprResolveNames(&sNC, pWhere) ){
-    goto update_cleanup;
-  }
-
   /* Start the view context
   */
   if( isView ){
@@ -335,14 +328,15 @@
   ** a ephemeral table.
   */
   if( isView ){
-    Select *pView;
-    SelectDest dest;
+    sqlite3MaterializeView(pParse, pTab->pSelect, pWhere,
+                           old_col_mask|new_col_mask, iCur);
+  }
 
-    pView = sqlite3SelectDup(db, pTab->pSelect);
-    sqlite3SelectMask(pParse, pView, old_col_mask|new_col_mask);
-    sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
-    sqlite3Select(pParse, pView, &dest, 0, 0, 0, 0);
-    sqlite3SelectDelete(pView);
+  /* Resolve the column names in all the expressions in the
+  ** WHERE clause.
+  */
+  if( sqlite3ExprResolveNames(&sNC, pWhere) ){
+    goto update_cleanup;
   }
 
   /* Begin the database scan