An attempt to delete a single row using a WHERE clause that specifies
the rowid would result in an error if the rowid did not exist.  This
problem has been resolved. (CVS 338)

FossilOrigin-Name: 011be9a9d2632d261489005d97c69b0a0bc5a108
diff --git a/src/btree.c b/src/btree.c
index 289282b..e4b18d5 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.45 2001/12/15 14:22:19 drh Exp $
+** $Id: btree.c,v 1.46 2002/01/04 03:09:29 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -728,6 +728,7 @@
 ** unless a transaction is started first:
 **
 **      sqliteBtreeCreateTable()
+**      sqliteBtreeCreateIndex()
 **      sqliteBtreeClearTable()
 **      sqliteBtreeDropTable()
 **      sqliteBtreeInsert()
@@ -2227,8 +2228,13 @@
 }
 
 /*
-** Create a new BTree in the same file.  Write into *piTable the index
-** of the root page of the new table.
+** Create a new BTree table.  Write into *piTable the page
+** number for the root page of the new table.
+**
+** In the current implementation, BTree tables and BTree indices are the 
+** the same.  But in the future, we may change this so that BTree tables
+** are restricted to having a 4-byte integer key and arbitrary data and
+** BTree indices are restricted to having an arbitrary key and no data.
 */
 int sqliteBtreeCreateTable(Btree *pBt, int *piTable){
   MemPage *pRoot;
@@ -2247,6 +2253,31 @@
 }
 
 /*
+** Create a new BTree index.  Write into *piTable the page
+** number for the root page of the new index.
+**
+** In the current implementation, BTree tables and BTree indices are the 
+** the same.  But in the future, we may change this so that BTree tables
+** are restricted to having a 4-byte integer key and arbitrary data and
+** BTree indices are restricted to having an arbitrary key and no data.
+*/
+int sqliteBtreeCreateIndex(Btree *pBt, int *piIndex){
+  MemPage *pRoot;
+  Pgno pgnoRoot;
+  int rc;
+  if( !pBt->inTrans ){
+    return SQLITE_ERROR;  /* Must start a transaction first */
+  }
+  rc = allocatePage(pBt, &pRoot, &pgnoRoot);
+  if( rc ) return rc;
+  assert( sqlitepager_iswriteable(pRoot) );
+  zeroPage(pRoot);
+  sqlitepager_unref(pRoot);
+  *piIndex = (int)pgnoRoot;
+  return SQLITE_OK;
+}
+
+/*
 ** Erase the given database page and all its children.  Return
 ** the page to the freelist.
 */
diff --git a/src/btree.h b/src/btree.h
index bce1a84..a869661 100644
--- a/src/btree.h
+++ b/src/btree.h
@@ -13,7 +13,7 @@
 ** subsystem.  See comments in the source code for a detailed description
 ** of what each interface routine does.
 **
-** @(#) $Id: btree.h,v 1.18 2001/12/15 14:22:19 drh Exp $
+** @(#) $Id: btree.h,v 1.19 2002/01/04 03:09:30 drh Exp $
 */
 #ifndef _BTREE_H_
 #define _BTREE_H_
@@ -30,6 +30,7 @@
 int sqliteBtreeRollback(Btree*);
 
 int sqliteBtreeCreateTable(Btree*, int*);
+int sqliteBtreeCreateIndex(Btree*, int*);
 int sqliteBtreeDropTable(Btree*, int);
 int sqliteBtreeClearTable(Btree*, int);
 
diff --git a/src/expr.c b/src/expr.c
index 37f4d28..526ad66 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.35 2001/12/21 14:30:43 drh Exp $
+** $Id: expr.c,v 1.36 2002/01/04 03:09:30 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -244,7 +244,7 @@
         ** table.  The cursor number of the temporary table has already
         ** been put in iTable by sqliteExprResolveInSelect().
         */
-        sqliteVdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 0);
+        sqliteVdbeAddOp(v, OP_OpenTemp, pExpr->iTable, 1);
         if( sqliteSelect(pParse, pExpr->pSelect, SRT_Set, pExpr->iTable) );
       }else if( pExpr->pList ){
         /* Case 2:     expr IN (exprlist)
diff --git a/src/insert.c b/src/insert.c
index a3f41dc..cd124f1 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.30 2001/12/31 02:48:51 drh Exp $
+** $Id: insert.c,v 1.31 2002/01/04 03:09:30 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -84,7 +84,7 @@
   }
 
   /* Figure out how many columns of data are supplied.  If the data
-  ** is comming from a SELECT statement, then this step has to generate
+  ** is coming from a SELECT statement, then this step has to generate
   ** all the code to implement the SELECT statement and leave the data
   ** in a temporary table.  If data is coming from an expression list,
   ** then we just have to count the number of expressions.
diff --git a/src/select.c b/src/select.c
index 399c563..cc4a2d9 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.52 2001/12/31 02:48:51 drh Exp $
+** $Id: select.c,v 1.53 2002/01/04 03:09:30 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -546,7 +546,7 @@
           return 1;
         }
         if( p->op!=TK_ALL ){
-          sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 0);
+          sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 1);
           sqliteVdbeAddOp(v, OP_KeyAsData, unionTab, 1);
         }else{
           sqliteVdbeAddOp(v, OP_OpenTemp, unionTab, 0);
@@ -608,7 +608,7 @@
       if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){
         return 1;
       }
-      sqliteVdbeAddOp(v, OP_OpenTemp, tab1, 0);
+      sqliteVdbeAddOp(v, OP_OpenTemp, tab1, 1);
       sqliteVdbeAddOp(v, OP_KeyAsData, tab1, 1);
 
       /* Code the SELECTs to our left into temporary table "tab1".
@@ -618,7 +618,7 @@
 
       /* Code the current SELECT into temporary table "tab2"
       */
-      sqliteVdbeAddOp(v, OP_OpenTemp, tab2, 0);
+      sqliteVdbeAddOp(v, OP_OpenTemp, tab2, 1);
       sqliteVdbeAddOp(v, OP_KeyAsData, tab2, 1);
       p->pPrior = 0;
       rc = sqliteSelect(pParse, p, SRT_Union, tab2);
@@ -932,7 +932,7 @@
   /* Begin the database scan
   */
   if( isDistinct ){
-    sqliteVdbeAddOp(v, OP_OpenTemp, distinct, 0);
+    sqliteVdbeAddOp(v, OP_OpenTemp, distinct, 1);
   }
   pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
   if( pWInfo==0 ) return 1;
diff --git a/src/vdbe.c b/src/vdbe.c
index 7079e17..dd23959 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -30,7 +30,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.103 2001/12/31 02:48:51 drh Exp $
+** $Id: vdbe.c,v 1.104 2002/01/04 03:09:30 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -2537,12 +2537,16 @@
   break;
 }
 
-/* Opcode: OpenTemp P1 * *
+/* Opcode: OpenTemp P1 P2 *
 **
-** Open a new cursor that points to a table in a temporary database
-** file.  The temporary file is opened read/write even if the main
-** database is read-only.  The temporary file is deleted when the
-** cursor is closed.
+** Open a new cursor that points to a table or index in a temporary
+** database file.  The temporary file is opened read/write even if 
+** the main database is read-only.  The temporary file is deleted
+** when the cursor is closed.
+**
+** The cursor points to a BTree table if P2==0 and to a BTree index
+** if P2==1.  A BTree table must have an integer key and can have arbitrary
+** data.  A BTree index has no data but can have an arbitrary key.
 **
 ** This opcode is used for tables that exist for the duration of a single
 ** SQL statement only.  Tables created using CREATE TEMPORARY TABLE
@@ -2570,10 +2574,18 @@
   memset(pCx, 0, sizeof(*pCx));
   rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt);
   if( rc==SQLITE_OK ){
-    rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor);
+    rc = sqliteBtreeBeginTrans(pCx->pBt);
   }
   if( rc==SQLITE_OK ){
-    rc = sqliteBtreeBeginTrans(pCx->pBt);
+    if( pOp->p2 ){
+      int pgno;
+      rc = sqliteBtreeCreateIndex(pCx->pBt, &pgno);
+      if( rc==SQLITE_OK ){
+        rc = sqliteBtreeCursor(pCx->pBt, pgno, 1, &pCx->pCursor);
+      }
+    }else{
+      rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor);
+    }
   }
   break;
 }
@@ -3224,14 +3236,19 @@
 ** number into the parser's internal data structures that describe the
 ** new table.
 **
+** The difference between a table and an index is this:  A table must
+** have a 4-byte integer key and can have arbitrary data.  An index
+** has an arbitrary key but no data.
+**
 ** See also: CreateIndex
 */
 /* Opcode: CreateIndex * P2 P3
 **
-** This instruction does exactly the same thing as CreateTable.  It
-** has a different name for historical reasons.
+** Allocate a new index in the main database file if P2==0 or in the
+** auxiliary database file if P2==1.  Push the page number of the
+** root page of the new index onto the stack.
 **
-** See also: CreateTable
+** See documentation on OP_CreateTable for additional information.
 */
 case OP_CreateIndex:
 case OP_CreateTable: {
@@ -3239,7 +3256,11 @@
   int pgno;
   VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
   assert( pOp->p3!=0 && pOp->p3type==P3_POINTER );
-  rc = sqliteBtreeCreateTable(pOp->p2 ? db->pBeTemp : pBt, &pgno);
+  if( pOp->opcode==OP_CreateTable ){
+    rc = sqliteBtreeCreateTable(pOp->p2 ? db->pBeTemp : pBt, &pgno);
+  }else{
+    rc = sqliteBtreeCreateIndex(pOp->p2 ? db->pBeTemp : pBt, &pgno);
+  }
   if( rc==SQLITE_OK ){
     aStack[i].i = pgno;
     aStack[i].flags = STK_Int;
diff --git a/src/where.c b/src/where.c
index 54a2cdd..4fe59e7 100644
--- a/src/where.c
+++ b/src/where.c
@@ -13,7 +13,7 @@
 ** the WHERE clause of SQL statements.  Also found here are subroutines
 ** to generate VDBE code to evaluate expressions.
 **
-** $Id: where.c,v 1.29 2001/12/22 14:49:26 drh Exp $
+** $Id: where.c,v 1.30 2002/01/04 03:09:30 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -439,6 +439,7 @@
       sqliteVdbeAddOp(v, OP_MustBeInt, 0, brk);
       if( i==pTabList->nId-1 && pushKey ){
         haveKey = 1;
+        sqliteVdbeAddOp(v, OP_Distinct, base+idx, brk);
       }else{
         sqliteVdbeAddOp(v, OP_NotFound, base+idx, brk);
         haveKey = 0;