More work on the implementation of cursors, but they are still not
functioning. (CVS 2142)

FossilOrigin-Name: 8b61d1ae1ca469b80f2b344d550c3b363448b193
diff --git a/src/cursor.c b/src/cursor.c
index 061fcb6..6bd6f6c 100644
--- a/src/cursor.c
+++ b/src/cursor.c
@@ -21,7 +21,7 @@
 ** cursors, they are really very different things.  It is worth your while
 ** to fully understand the difference.
 **
-** @(#) $Id: cursor.c,v 1.1 2004/11/22 19:12:20 drh Exp $
+** @(#) $Id: cursor.c,v 1.2 2004/11/23 01:47:30 drh Exp $
 */
 #ifndef SQLITE_OMIT_CURSOR
 #include "sqliteInt.h"
@@ -86,13 +86,16 @@
   }
   db->apSqlCursor[i] = pNew = sqliteMallocRaw( sizeof(*pNew) + pName->n + 1 );
   if( pNew==0 ) goto end_create_cursor;
+  pNew->idx = i;
   pNew->zName = (char*)&pNew[1];
   memcpy(pNew->zName, pName->z, pName->n);
   pNew->zName[pName->n] = 0;
   pNew->pSelect = sqlite3SelectDup(pSelect);
-  pNew->nPtr = 0;
-  pNew->aPtr = 0;
-  pNew->idx = i;
+  pNew->nPtr = 2;
+  pNew->aPtr = sqliteMalloc( sizeof(Mem)*2 );
+  for(i=0; i<2; i++){
+    pNew->aPtr[i].flags = MEM_Null;
+  }
 
 end_create_cursor:
   sqlite3SelectDelete(pSelect);
@@ -118,6 +121,26 @@
 }
 
 /*
+** Reverse the direction the ORDER BY clause on the SELECT statement.
+*/
+static void reverseSortOrder(Select *p){
+  if( p->pOrderBy==0 ){
+    /* If there no ORDER BY clause, add a new one that is "rowid DESC" */
+    static const Token rowid = { "ROWID", 0, 5 };
+    Expr *pExpr = sqlite3Expr(TK_ID, 0, 0, &rowid);
+    ExprList *pList = sqlite3ExprListAppend(0, pExpr, 0);
+    if( pList )  pList->a[0].sortOrder = SQLITE_SO_DESC;
+    p->pOrderBy = pList;
+  }else{
+    int i;
+    ExprList *pList = p->pOrderBy;
+    for(i=0; i<pList->nExpr; i++){
+      pList->a[i].sortOrder = !pList->a[i].sortOrder;
+    }
+  }
+}
+
+/*
 ** The parser calls this routine when it sees a complete FETCH statement.
 ** This routine generates code to implement the FETCH.
 **
@@ -142,26 +165,73 @@
   pCopy->pFetch = &sFetch;
   switch( pParse->fetchDir ){
     case TK_FIRST: {
+      sFetch.isBackwards = 0;
+      sFetch.doRewind = 1;
+      pCopy->nLimit = pParse->dirArg1;
+      pCopy->nOffset = 0;
       break;
     }
     case TK_LAST: {
+      reverseSortOrder(pCopy);
+      sFetch.isBackwards = 1;
+      sFetch.doRewind = 1;
+      pCopy->nLimit = pParse->dirArg1;
+      pCopy->nOffset = 0;
       break;
     }
     case TK_NEXT: {
+      sFetch.isBackwards = 0;
+      sFetch.doRewind = 0;
+      pCopy->nLimit = pParse->dirArg1;
+      pCopy->nOffset = 0;
       break;
     }
     case TK_PRIOR: {
+      reverseSortOrder(pCopy);
+      sFetch.isBackwards = 1;
+      sFetch.doRewind = 0;
+      pCopy->nLimit = pParse->dirArg1;
+      pCopy->nOffset = 0;
       break;
     }
     case TK_ABSOLUTE: {
+      sFetch.isBackwards = 0;
+      sFetch.doRewind = 1;
+      pCopy->nLimit = pParse->dirArg1;
+      pCopy->nOffset = pParse->dirArg2;
       break;
     }
     default: {
       assert( pParse->fetchDir==TK_RELATIVE );
+      if( pParse->dirArg2>=0 ){
+        /* The index parameter is positive.  Move forward from the current
+        ** location */
+        sFetch.isBackwards = 0;
+        sFetch.doRewind = 0;
+        pCopy->nLimit = pParse->dirArg1;
+        pCopy->nOffset = pParse->dirArg2;
+      }else{
+        /* The index is negative.  We have to code two separate SELECTs.
+        ** The first one seeks to the no position and the second one does
+        ** the query.
+        */
+        Select *pSeek = sqlite3SelectDup(pCopy);
+        reverseSortOrder(pSeek);
+        sFetch.isBackwards = 1;
+        sFetch.doRewind = 0;
+        pSeek->nLimit = pParse->dirArg2;
+        pSeek->pFetch = &sFetch;
+        sqlite3Select(pParse, pSeek, SRT_Discard, 0, 0, 0, 0, 0);
+        sFetch.isBackwards = 0;
+        sFetch.doRewind = 0;
+        pCopy->nLimit = pParse->dirArg1;
+        pCopy->nOffset = 0;
+      }
       break;
     }
   }
   sqlite3Select(pParse, pCopy, SRT_Callback, 0, 0, 0, 0, 0);
+
 end_fetch:
   sqlite3IdListDelete(pInto);
 }
diff --git a/src/delete.c b/src/delete.c
index 4887d69..a0d30ea 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
 ** to handle DELETE FROM statements.
 **
-** $Id: delete.c,v 1.90 2004/11/22 10:02:10 danielk1977 Exp $
+** $Id: delete.c,v 1.91 2004/11/23 01:47:30 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -229,7 +229,7 @@
 
     /* Begin the database scan
     */
-    pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
+    pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0, 0);
     if( pWInfo==0 ) goto delete_from_cleanup;
 
     /* Remember the key of every item to be deleted.
diff --git a/src/expr.c b/src/expr.c
index 03fd866..de96ada 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.173 2004/11/22 19:12:20 drh Exp $
+** $Id: expr.c,v 1.174 2004/11/23 01:47:30 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -179,7 +179,7 @@
 ** for this node is obtained from sqliteMalloc().  The calling function
 ** is responsible for making sure the node eventually gets freed.
 */
-Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, Token *pToken){
+Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
   Expr *pNew;
   pNew = sqliteMalloc( sizeof(Expr) );
   if( pNew==0 ){
diff --git a/src/select.c b/src/select.c
index d17c269..d16f43d 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.216 2004/11/22 19:12:21 drh Exp $
+** $Id: select.c,v 1.217 2004/11/23 01:47:30 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -2547,16 +2547,8 @@
 
   /* Begin the database scan
   */
-#if 0 /* ndef SQLITE_OMIT_CURSOR */
-  if( p->pFetch ){
-    pWInfo = sqlite3WhereBeginFetch(pParse, pTabList, pWhere,
-                                    pOrderby, p->pFetch);
-  }else
-#endif
-  {
-    pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
-                               pGroupBy ? 0 : &pOrderBy);
-  }
+  pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0,
+                             pGroupBy ? 0 : &pOrderBy, p->pFetch);
   if( pWInfo==0 ) goto select_end;
 
   /* Use the standard inner loop if we are not dealing with
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 0616d05..43f9afa 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.343 2004/11/22 19:12:21 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.344 2004/11/23 01:47:30 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1281,7 +1281,7 @@
 int sqlite3KeywordCode(const char*, int);
 int sqlite3RunParser(Parse*, const char*, char **);
 void sqlite3FinishCoding(Parse*);
-Expr *sqlite3Expr(int, Expr*, Expr*, Token*);
+Expr *sqlite3Expr(int, Expr*, Expr*, const Token*);
 Expr *sqlite3RegisterExpr(Parse*,Token*);
 Expr *sqlite3ExprAnd(Expr*, Expr*);
 void sqlite3ExprSpan(Expr*,Token*,Token*);
@@ -1341,7 +1341,7 @@
 void sqlite3OpenTable(Vdbe*, int iCur, Table*, int);
 void sqlite3DeleteFrom(Parse*, SrcList*, Expr*);
 void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int);
-WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**);
+WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**, Fetch*);
 void sqlite3WhereEnd(WhereInfo*);
 void sqlite3ExprCode(Parse*, Expr*);
 int sqlite3ExprCodeExprList(Parse*, ExprList*);
diff --git a/src/update.c b/src/update.c
index 501ca6c..4dd040e 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.96 2004/11/22 10:02:11 danielk1977 Exp $
+** $Id: update.c,v 1.97 2004/11/23 01:47:30 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -235,7 +235,7 @@
 
   /* Begin the database scan
   */
-  pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0);
+  pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0, 0);
   if( pWInfo==0 ) goto update_cleanup;
 
   /* Remember the index of every item to be updated.
diff --git a/src/vdbe.c b/src/vdbe.c
index 31ecea1..dc4963e 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.430 2004/11/18 02:10:55 drh Exp $
+** $Id: vdbe.c,v 1.431 2004/11/23 01:47:30 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -4433,6 +4433,56 @@
   break;
 }
 
+#ifndef SQLITE_OMIT_CURSOR
+/* Opcode: CursorStore P1 P2 *
+**
+** The implementation of SQL cursors (not to be confused with VDBE cursors
+** or B-tree cursors) stores information in the SQLite database connection
+** structure (the sqlite3* pointer) that identifies the row
+** in a table that an SQL cursor is pointing to.  This opcode is
+** used to store that information.  P1 is an index of an SQL cursor.
+** P2 is the index of a memory slot within that SQL cursor.  This opcode
+** pops the top of the stack and stores it in the SQL cursor.
+*/
+case OP_CursorStore: {
+  SqlCursor *pCursor;
+  assert( pTos>=p->aStack );
+  assert( pOp->p1>=0 && pOp->p1<db->nSqlCursor );
+  pCursor = db->apSqlCursor[pOp->p1];
+  assert( pCursor!=0 );
+  assert( pOp->p2>=0 && pOp->p2<2 );  
+  rc = sqlite3VdbeMemMove(&pCursor->aPtr[pOp->p1], pTos);
+  pTos--;
+  break;
+}
+
+/* Opcode: CursorLoad P1 P2 *
+**
+** The implementation of SQL cursors (not to be confused with VDBE cursors
+** or B-tree cursors) stores information in the SQLite database connection
+** structure (the sqlite3* pointer) that effectively records the current
+** location in a table that an SQL cursor is pointing to.  This opcode is
+** used to recover that information.  P1 is an index of an SQL cursor.
+** P2 is the index of a memory slot within that SQL cursor.  This opcode
+** pushes a new value onto the stack which is a copy of the information
+** obtained from entry P2 of cursor P1.
+*/
+case OP_CursorLoad: {
+  SqlCursor *pCursor;
+  int i = pOp->p1;
+  assert( pTos>=p->aStack );
+  assert( pOp->p1>=0 && pOp->p1<db->nSqlCursor );
+  pCursor = db->apSqlCursor[pOp->p1];
+  assert( pCursor!=0 );
+  assert( pOp->p2>=0 && pOp->p2<2 );  
+  pTos++;
+  sqlite3VdbeMemShallowCopy(pTos, &pCursor->aPtr[i], MEM_Ephem);
+  break;
+}
+#endif /* SQLITE_OMIT_CURSOR */
+
+
+
 /* An other opcode is illegal...
 */
 default: {
diff --git a/src/where.c b/src/where.c
index 97cf37d..1e7073c 100644
--- a/src/where.c
+++ b/src/where.c
@@ -12,7 +12,7 @@
 ** This module contains C code that generates VDBE code used to process
 ** the WHERE clause of SQL statements.
 **
-** $Id: where.c,v 1.119 2004/11/22 19:12:21 drh Exp $
+** $Id: where.c,v 1.120 2004/11/23 01:47:31 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -498,17 +498,14 @@
 **
 ** If the where clause loops cannot be arranged to provide the correct
 ** output order, then the *ppOrderBy is unchanged.
-**
-** If parameter iTabCur is non-negative, then it is a cursor already open
-** on table pTabList->aSrc[0]. Use this cursor instead of opening a new
-** one.
 */
 WhereInfo *sqlite3WhereBegin(
   Parse *pParse,        /* The parser context */
   SrcList *pTabList,    /* A list of all tables to be scanned */
   Expr *pWhere,         /* The WHERE clause */
   int pushKey,          /* If TRUE, leave the table key on the stack */
-  ExprList **ppOrderBy  /* An ORDER BY clause, or NULL */
+  ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */
+  Fetch *pFetch         /* Initial location of cursors.  NULL otherwise */
 ){
   int i;                     /* Loop counter */
   WhereInfo *pWInfo;         /* Will become the return value of this function */
@@ -529,6 +526,9 @@
   */
   assert( pushKey==0 || pTabList->nSrc==1 );
 
+  /*
+  */
+
   /* Split the WHERE clause into separate subexpressions where each
   ** subexpression is separated by an AND operator.  If the aExpr[]
   ** array fills up, the last entry might point to an expression which