Remove code for SQL cursors. (CVS 2312)

FossilOrigin-Name: 2eb90870556c90b8d85da3d5eb7554f74ec922c2
This commit is contained in:
danielk1977
2005-02-04 04:07:16 +00:00
parent 62d54916c4
commit 6a67fe8edf
18 changed files with 58 additions and 634 deletions
+1 -3
View File
@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
** $Id: btree.c,v 1.244 2005/01/21 11:55:26 danielk1977 Exp $
** $Id: btree.c,v 1.245 2005/02/04 04:07:17 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@@ -1951,7 +1951,6 @@ static void invalidateCursors(Btree *pBt){
** Print debugging information about all cursors to standard output.
*/
void sqlite3BtreeCursorList(Btree *pBt){
#ifndef SQLITE_OMIT_CURSOR
BtCursor *pCur;
for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
MemPage *pPage = pCur->pPage;
@@ -1962,7 +1961,6 @@ void sqlite3BtreeCursorList(Btree *pBt){
pCur->isValid ? "" : " eof"
);
}
#endif
}
#endif
-239
View File
@@ -1,239 +0,0 @@
/*
** 2004 November 21
**
** The author disclaims copyright to this source code. In place of
** a legal notice, here is a blessing:
**
** May you do good and not evil.
** May you find forgiveness for yourself and forgive others.
** May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains code used to implement the DECLARE...CURSOR syntax
** of SQL and related processing.
**
** Do not confuse SQL cursors and B-tree cursors. An SQL cursor (as
** implemented by this file) is a user-visible cursor that is created
** using the DECLARE...CURSOR command and deleted using CLOSE. A
** B-tree cursor is an abstraction of the b-tree layer. See the btree.c
** module for additional information. There is also a VDBE-cursor that
** is used by the VDBE module. Even though all these objects are called
** cursors, they are really very different things. It is worth your while
** to fully understand the difference.
**
** @(#) $Id: cursor.c,v 1.3 2005/01/20 02:14:31 drh Exp $
*/
#include "sqliteInt.h"
#ifndef SQLITE_OMIT_CURSOR
#include "vdbeInt.h"
/*
** Delete a cursor object.
*/
void sqlite3CursorDelete(SqlCursor *p){
if( p ){
int i;
sqlite3SelectDelete(p->pSelect);
for(i=0; i<p->nPtr; i++){
sqlite3VdbeMemRelease(&p->aPtr[i]);
}
sqliteFree(p->aPtr);
sqliteFree(p);
}
}
/*
** Look up a cursor by name. Return NULL if not found.
*/
static SqlCursor *findCursor(sqlite3 *db, Token *pName){
int i;
SqlCursor *p;
for(i=0; i<db->nSqlCursor; i++){
p = db->apSqlCursor[i];
if( p && sqlite3StrNICmp(p->zName, pName->z, pName->n)==0 ){
return p;
}
}
return 0;
}
/*
** The parser calls this routine in order to create a new cursor.
** The arguments are the name of the new cursor and the SELECT statement
** that the new cursor will access.
*/
void sqlite3CursorCreate(Parse *pParse, Token *pName, Select *pSelect){
SqlCursor *pNew;
sqlite3 *db = pParse->db;
int i;
pNew = findCursor(db, pName);
if( pNew ){
sqlite3ErrorMsg(pParse, "another cursor named %T already exists", pName);
goto end_create_cursor;
}
if( pSelect==0 ){
/* This can only happen due to a prior malloc failure */
goto end_create_cursor;
}
for(i=0; i<db->nSqlCursor; i++){
if( db->apSqlCursor[i]==0 ) break;
}
if( i>=db->nSqlCursor ){
db->apSqlCursor = sqliteRealloc(db->apSqlCursor, (i+1)*sizeof(pNew));
db->nSqlCursor = i+1;
}
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 = 2;
pNew->aPtr = sqliteMalloc( sizeof(Mem)*2 );
for(i=0; i<2; i++){
pNew->aPtr[i].flags = MEM_Null;
}
end_create_cursor:
sqlite3SelectDelete(pSelect);
}
/*
** The parser calls this routine in response to a CLOSE command. Delete
** the cursor named in the argument.
*/
void sqlite3CursorClose(Parse *pParse, Token *pName){
SqlCursor *p;
sqlite3 *db = pParse->db;
p = findCursor(db, pName);
if( p==0 ){
sqlite3ErrorMsg(pParse, "no such cursor: %T", pName);
return;
}
assert( p->idx>=0 && p->idx<db->nSqlCursor );
assert( db->apSqlCursor[p->idx]==p );
db->apSqlCursor[p->idx] = 0;
sqlite3CursorDelete(p);
}
/*
** 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.
**
** Information about the direction of the FETCH has already been inserted
** into the pParse structure by parser rules. The arguments specify the
** name of the cursor from which we are fetching and the optional INTO
** clause.
*/
void sqlite3Fetch(Parse *pParse, Token *pName, IdList *pInto){
SqlCursor *p;
sqlite3 *db = pParse->db;
Select *pCopy;
Fetch sFetch;
p = findCursor(db, pName);
if( p==0 ){
sqlite3ErrorMsg(pParse, "no such cursor: %T", pName);
return;
}
sFetch.pCursor = p;
pCopy = sqlite3SelectDup(p->pSelect);
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);
}
#endif /* SQLITE_OMIT_CURSOR */
+3 -3
View File
@@ -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.190 2005/01/30 09:17:59 danielk1977 Exp $
** $Id: expr.c,v 1.191 2005/02/04 04:07:17 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -453,8 +453,8 @@ ExprList *sqlite3ExprListDup(ExprList *p){
** sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes
** called with a NULL argument.
*/
#if !defined(SQLITE_OMIT_CURSOR) || !defined(SQLITE_OMIT_VIEW) \
|| !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_SUBQUERY)
#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
|| !defined(SQLITE_OMIT_SUBQUERY)
SrcList *sqlite3SrcListDup(SrcList *p){
SrcList *pNew;
int i;
+1 -8
View File
@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.277 2005/01/31 12:42:29 danielk1977 Exp $
** $Id: main.c,v 1.278 2005/02/04 04:07:17 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -500,13 +500,6 @@ int sqlite3_close(sqlite3 *db){
sqlite3ValueFree(db->pErr);
}
#ifndef SQLITE_OMIT_CURSOR
for(j=0; j<db->nSqlCursor; j++){
sqlite3CursorDelete(db->apSqlCursor[j]);
}
sqliteFree(db->apSqlCursor);
#endif
db->magic = SQLITE_MAGIC_ERROR;
sqliteFree(db);
return SQLITE_OK;
+1 -33
View File
@@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.163 2005/01/29 08:32:45 danielk1977 Exp $
** @(#) $Id: parse.y,v 1.164 2005/02/04 04:07:17 danielk1977 Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -600,9 +600,6 @@ term(A) ::= INTEGER(X). {A = sqlite3Expr(@X, 0, 0, &X);}
term(A) ::= FLOAT(X). {A = sqlite3Expr(@X, 0, 0, &X);}
term(A) ::= STRING(X). {A = sqlite3Expr(@X, 0, 0, &X);}
expr(A) ::= BLOB(X). {A = sqlite3Expr(@X, 0, 0, &X);}
%ifdef SQLITE_ENABLE_CURSOR
expr(A) ::= CURRENT OF id.
%endif
expr(A) ::= REGISTER(X). {A = sqlite3RegisterExpr(pParse, &X);}
expr(A) ::= VARIABLE(X). {
Token *pToken = &X;
@@ -968,32 +965,3 @@ cmd ::= ALTER TABLE fullname(X) RENAME TO nm(Z). {
sqlite3AlterRenameTable(pParse,X,&Z);
}
%endif
////////////////////////////// CURSORS //////////////////////////////////////
%ifdef SQLITE_ENABLE_CURSOR
cmd ::= DECLARE nm(X) CURSOR FOR select(Y). {sqlite3CursorCreate(pParse,&X,Y);}
cmd ::= CLOSE nm(X). {sqlite3CursorClose(pParse,&X);}
cmd ::= FETCH direction FROM nm(N) into_opt(D).
{sqlite3Fetch(pParse,&N,D);}
%type into_opt {IdList*}
%destructor into_opt {sqlite3IdListDelete($$);}
into_opt(A) ::= . {A = 0;}
into_opt(A) ::= INTO inscollist(X). {A = X;}
direction ::= NEXT(X) count_opt(Y). {pParse->fetchDir=@X; pParse->dirArg1=Y;}
direction ::= PRIOR(X) count_opt(Y). {pParse->fetchDir=@X; pParse->dirArg1=Y;}
direction ::= FIRST(X) count_opt(Y). {pParse->fetchDir=@X; pParse->dirArg1=Y;}
direction ::= LAST(X) count_opt(Y). {pParse->fetchDir=@X; pParse->dirArg1=Y;}
direction ::= ABSOLUTE(X) signed(Z) comma_count_opt(Y).
{pParse->fetchDir=@X; pParse->dirArg1=Y; pParse->dirArg2=Z;}
direction ::= RELATIVE(X) signed(Z) comma_count_opt(Y).
{pParse->fetchDir=@X; pParse->dirArg1=Y; pParse->dirArg2=Z;}
%type count_opt {int}
count_opt(A) ::= . {A = 1;}
count_opt(A) ::= signed(X). {A = X;}
%type comma_count_opt {int}
comma_count_opt(A) ::= . {A = 1;}
comma_count_opt(A) ::= COMMA signed(X). {A = X;}
%endif // SQLITE_ENABLE_CURSOR
+1 -19
View File
@@ -11,7 +11,7 @@
*************************************************************************
** This file contains code used to implement the PRAGMA command.
**
** $Id: pragma.c,v 1.86 2005/01/24 10:25:59 danielk1977 Exp $
** $Id: pragma.c,v 1.87 2005/02/04 04:07:17 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -538,24 +538,6 @@ void sqlite3Pragma(
sqlite3VdbeAddOp(v, OP_Callback, 3, 0);
}
}else
#ifndef SQLITE_OMIT_CURSOR
if( sqlite3StrICmp(zLeft, "cursor_list")==0 ){
int i;
if( sqlite3ReadSchema(pParse) ) goto pragma_out;
sqlite3VdbeSetNumCols(v, 2);
sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC);
sqlite3VdbeSetColName(v, 1, "name", P3_STATIC);
for(i=0; i<db->nSqlCursor; i++){
SqlCursor *p = db->apSqlCursor[i];
if( p==0 ) continue;
assert( p->zName!=0 );
sqlite3VdbeAddOp(v, OP_Integer, i, 0);
sqlite3VdbeOp3(v, OP_String8, 0, 0, p->zName, 0);
sqlite3VdbeAddOp(v, OP_Callback, 2, 0);
}
}else
#endif /* SQLITE_OMIT_CURSOR */
#endif /* SQLITE_OMIT_SCHEMA_PRAGMAS */
#ifndef SQLITE_OMIT_FOREIGN_KEY
+2 -28
View File
@@ -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.237 2005/01/31 12:42:29 danielk1977 Exp $
** $Id: select.c,v 1.238 2005/02/04 04:07:17 danielk1977 Exp $
*/
#include "sqliteInt.h"
@@ -547,7 +547,7 @@ static int selectInnerLoop(
break;
}
#if !defined(SQLITE_OMIT_TRIGGER) || !defined(SQLITE_OMIT_CURSOR)
#if !defined(SQLITE_OMIT_TRIGGER)
/* Discard the results. This is used for SELECT statements inside
** the body of a TRIGGER. The purpose of such selects is to call
** user-defined functions that have side effects. We do not care
@@ -2522,12 +2522,6 @@ int sqlite3Select(
/* If there is are a sequence of queries, do the earlier ones first.
*/
if( p->pPrior ){
#ifndef SQLITE_OMIT_CURSOR
if( p->pFetch ){
sqlite3ErrorMsg(pParse, "cursors cannot be used on compound queries");
goto select_end;
}
#endif
return multiSelect(pParse, p, eDest, iParm, aff);
}
#endif
@@ -2583,26 +2577,6 @@ int sqlite3Select(
break;
}
/* We cannot use a SQL cursor on a join or on a DISTINCT query
*/
#ifndef SQLITE_OMIT_CURSOR
if( p->pFetch ){
if( p->isDistinct ){
sqlite3ErrorMsg(pParse, "cursors cannot be used on DISTINCT queries");
goto select_end;
}
if( pTabList->nSrc>0 ){
sqlite3ErrorMsg(pParse, "cursors cannot be used on joins");
goto select_end;
}
if( pTabList->a[0].pSelect ){
sqlite3ErrorMsg(pParse, "cursor cannot be used with nested queries "
"or views");
goto select_end;
}
}
#endif
/* Begin generating code.
*/
v = sqlite3GetVdbe(pParse);
+1 -50
View File
@@ -11,19 +11,11 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.365 2005/01/31 12:56:44 danielk1977 Exp $
** @(#) $Id: sqliteInt.h,v 1.366 2005/02/04 04:07:17 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
/*
** Cursor support is turned off unless the SQLITE_ENABLE_CURSOR option
** is defined.
*/
#ifndef SQLITE_ENABLE_CURSOR
# define SQLITE_OMIT_CURSOR 1
#endif
/*
** These #defines should enable >2GB file support on Posix if the
** underlying operating system supports it. If the OS lacks
@@ -328,10 +320,8 @@ typedef struct AuthContext AuthContext;
typedef struct KeyClass KeyClass;
typedef struct CollSeq CollSeq;
typedef struct KeyInfo KeyInfo;
typedef struct SqlCursor SqlCursor;
typedef struct NameContext NameContext;
typedef struct Fetch Fetch;
typedef struct CursorSubst CursorSubst;
/*
** Each database file to be accessed by the system is an instance
@@ -444,10 +434,6 @@ struct sqlite3 {
int (*xProgress)(void *); /* The progress callback */
void *pProgressArg; /* Argument to the progress callback */
int nProgressOps; /* Number of opcodes for progress callback */
#endif
#ifndef SQLITE_OMIT_CURSOR
int nSqlCursor; /* Number of slots in apSqlCursor[] */
SqlCursor **apSqlCursor; /* Pointers to all active SQL cursors */
#endif
int errCode; /* Most recent error code (SQLITE_*) */
u8 enc; /* Text encoding for this database. */
@@ -974,16 +960,6 @@ struct WhereInfo {
WhereLevel a[1]; /* Information about each nest loop in the WHERE */
};
/*
** An instance of the following structure is used to store information
** about a single FETCH sql command.
*/
struct Fetch {
SqlCursor *pCursor; /* Cursor used by the fetch */
int isBackwards; /* Cursor moves backwards if true, forward if false */
int doRewind; /* True to rewind cursor before starting */
};
/*
** A NameContext defines a context in which to resolve table and column
** names. The context consists of a list of tables (the pSrcList) field and
@@ -1123,11 +1099,6 @@ struct Parse {
int nVarExprAlloc; /* Number of allocated slots in apVarExpr[] */
Expr **apVarExpr; /* Pointers to :aaa and $aaaa wildcard expressions */
u8 explain; /* True if the EXPLAIN flag is found on the query */
#ifndef SQLITE_OMIT_CURSOR
u8 fetchDir; /* The direction argument to the FETCH command */
int dirArg1; /* First argument to the direction */
int dirArg2; /* Second argument to the direction */
#endif
Token sErrToken; /* The token at which the error occurred */
Token sNameToken; /* Token with unqualified schema object name */
Token sLastToken; /* The last token parsed */
@@ -1312,19 +1283,6 @@ typedef struct {
char **pzErrMsg; /* Error message stored here */
} InitData;
/*
** Each SQL cursor (a cursor created by the DECLARE ... CURSOR syntax)
** is represented by an instance of the following structure.
*/
struct SqlCursor {
char *zName; /* Name of this cursor */
int idx; /* Index of this cursor in db->apSqlCursor[] */
Select *pSelect; /* The SELECT statement that defines this cursor */
int nPtr; /* Number of slots in aPtr[] */
sqlite3_value *aPtr; /* Values that define the current cursor position */
};
/*
* This global flag is set for performance testing of triggers. When it is set
* SQLite will perform the overhead of building new and old trigger references
@@ -1578,11 +1536,4 @@ void sqlite3ExpirePreparedStatements(sqlite3*);
void sqlite3CodeSubselect(Parse *, Expr *);
int sqlite3SelectResolve(Parse *, Select *, NameContext *);
#ifndef SQLITE_OMIT_CURSOR
void sqlite3CursorDelete(SqlCursor*);
void sqlite3CursorCreate(Parse*, Token*, Select*);
void sqlite3CursorClose(Parse*, Token*);
void sqlite3Fetch(Parse*, Token*, IdList*);
#endif /* SQLITE_OMIT_CURSOR */
#endif
+1 -7
View File
@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.128 2005/01/25 04:27:55 danielk1977 Exp $
** $Id: test1.c,v 1.129 2005/02/04 04:07:18 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -2729,12 +2729,6 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "conflict", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_CURSOR
Tcl_SetVar2(interp, "sqlite_options", "cursor", "0", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "cursor", "1", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_DATETIME_FUNCS
Tcl_SetVar2(interp, "sqlite_options", "datetime", "0", TCL_GLOBAL_ONLY);
#else
+1 -49
View File
@@ -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.449 2005/01/29 08:32:45 danielk1977 Exp $
** $Id: vdbe.c,v 1.450 2005/02/04 04:07:18 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -4477,54 +4477,6 @@ case OP_Vacuum: {
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 */
/* Opcode: Expire P1 * *
**
** Cause precompiled statements to become expired. An expired statement