/ Check-in [0b996959]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Get triggers working on tables with INTEGER PRIMARY KEYs. Ticket #291. This may also fix #159. Still need to add tests so both bugs remain open for the time being. (CVS 908)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0b996959b8d8bc2c82eab9cccc190befd0056505
User & Date: drh 2003-04-15 19:22:23
Context
2003-04-16
01:28
Remove some unnecessary code and complication from the btree interface. (CVS 909) check-in: 35cc7c7d user: drh tags: trunk
2003-04-15
19:22
Get triggers working on tables with INTEGER PRIMARY KEYs. Ticket #291. This may also fix #159. Still need to add tests so both bugs remain open for the time being. (CVS 908) check-in: 0b996959 user: drh tags: trunk
17:22
Added btree_rb.c (CVS 907) check-in: 93eb6c52 user: paul tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to main.mk.

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

70
71
72
73
74
75
76
...
160
161
162
163
164
165
166



167
168
169
170
171
172
173

# This is how we compile
#
TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src

# Object files for the SQLite library.
#
LIBOBJ = attach.o auth.o btree.o build.o copy.o delete.o \
         expr.o func.o hash.o insert.o \
         main.o opcodes.o os.o pager.o parse.o pragma.o printf.o random.o \
         select.o table.o tokenize.o trigger.o update.o util.o \
         vacuum.o vdbe.o where.o tclsqlite.o

# All of the source code files.
#
SRC = \
  $(TOP)/src/attach.c \
  $(TOP)/src/auth.c \
  $(TOP)/src/btree.c \
  $(TOP)/src/btree.h \

  $(TOP)/src/build.c \
  $(TOP)/src/copy.c \
  $(TOP)/src/delete.c \
  $(TOP)/src/expr.c \
  $(TOP)/src/func.c \
  $(TOP)/src/hash.c \
  $(TOP)/src/hash.h \
................................................................................
#
lemon:	$(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
	$(BCC) -o lemon $(TOP)/tool/lemon.c
	cp $(TOP)/tool/lempar.c .

btree.o:	$(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h
	$(TCCX) -c $(TOP)/src/btree.c




build.o:	$(TOP)/src/build.c $(HDR)
	$(TCCX) -c $(TOP)/src/build.c

main.o:	$(TOP)/src/main.c $(HDR)
	$(TCCX) -c $(TOP)/src/main.c








|












>







 







>
>
>







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

# This is how we compile
#
TCCX = $(TCC) $(OPTS) $(THREADSAFE) $(USLEEP) -I. -I$(TOP)/src

# Object files for the SQLite library.
#
LIBOBJ = attach.o auth.o btree.o btree_rb.o build.o copy.o delete.o \
         expr.o func.o hash.o insert.o \
         main.o opcodes.o os.o pager.o parse.o pragma.o printf.o random.o \
         select.o table.o tokenize.o trigger.o update.o util.o \
         vacuum.o vdbe.o where.o tclsqlite.o

# All of the source code files.
#
SRC = \
  $(TOP)/src/attach.c \
  $(TOP)/src/auth.c \
  $(TOP)/src/btree.c \
  $(TOP)/src/btree.h \
  $(TOP)/src/btree_rb.c \
  $(TOP)/src/build.c \
  $(TOP)/src/copy.c \
  $(TOP)/src/delete.c \
  $(TOP)/src/expr.c \
  $(TOP)/src/func.c \
  $(TOP)/src/hash.c \
  $(TOP)/src/hash.h \
................................................................................
#
lemon:	$(TOP)/tool/lemon.c $(TOP)/tool/lempar.c
	$(BCC) -o lemon $(TOP)/tool/lemon.c
	cp $(TOP)/tool/lempar.c .

btree.o:	$(TOP)/src/btree.c $(HDR) $(TOP)/src/pager.h
	$(TCCX) -c $(TOP)/src/btree.c

btree_rb.o:	$(TOP)/src/btree_rb.c $(HDR)
	$(TCCX) -c $(TOP)/src/btree_rb.c

build.o:	$(TOP)/src/build.c $(HDR)
	$(TCCX) -c $(TOP)/src/build.c

main.o:	$(TOP)/src/main.c $(HDR)
	$(TCCX) -c $(TOP)/src/main.c

Changes to src/attach.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
115
116
117
118
119
120
121

122
123
124
125
126
127
128
129
**    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 ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.2 2003/04/13 18:26:51 paul Exp $
*/
#include "sqliteInt.h"

/*
** This routine is called by the parser to process an ATTACH statement:
**
**     ATTACH DATABASE filename AS dbname
................................................................................
  }
  if( i<2 ){
    sqliteErrorMsg(pParse, "cannot detach database %T", pDbname);
    return;
  }
  sqliteBtreeClose(db->aDb[i].pBt);
  db->aDb[i].pBt = 0;

  sqliteResetInternalSchema(db, i);
  db->nDb--;
  if( i<db->nDb ){
    db->aDb[i] = db->aDb[db->nDb];
    memset(&db->aDb[db->nDb], 0, sizeof(db->aDb[0]));
    sqliteResetInternalSchema(db, i);
  }
}







|







 







>








7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
**    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 ATTACH and DETACH commands.
**
** $Id: attach.c,v 1.3 2003/04/15 19:22:23 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is called by the parser to process an ATTACH statement:
**
**     ATTACH DATABASE filename AS dbname
................................................................................
  }
  if( i<2 ){
    sqliteErrorMsg(pParse, "cannot detach database %T", pDbname);
    return;
  }
  sqliteBtreeClose(db->aDb[i].pBt);
  db->aDb[i].pBt = 0;
  sqliteFree(db->aDb[i].zName);
  sqliteResetInternalSchema(db, i);
  db->nDb--;
  if( i<db->nDb ){
    db->aDb[i] = db->aDb[db->nDb];
    memset(&db->aDb[db->nDb], 0, sizeof(db->aDb[0]));
    sqliteResetInternalSchema(db, i);
  }
}

Changes to src/btree_rb.c.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24








25
26
27
28
29
30
31
...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
...
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
...
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
....
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
....
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
....
1387
1388
1389
1390
1391
1392
1393


** 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.
**
*************************************************************************
** $Id: btree_rb.c,v 1.1 2003/04/15 17:22:30 paul Exp $
**
** This file implements an in-core database using Red-Black balanced
** binary trees.
**
** It was contributed to SQLite by anonymous on 2003-Feb-04 23:24:49 UTC.
*/

#define SQLITE_NO_BTREE_DEFS

#include "btree.h"
#include "sqliteInt.h"
#include <assert.h>









typedef struct BtRbTree BtRbTree;
typedef struct BtRbNode BtRbNode;
typedef struct BtRollbackOp BtRollbackOp;

/* Forward declarations */
static BtOps sqliteBtreeOps;
................................................................................
    pRollbackOp->pNext = pBtree->pCheckRollback;
    pBtree->pCheckRollback = pRollbackOp;
  }
}

int sqliteRBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree)
{
  int tnum;
  *ppBtree = (Btree *)sqliteMalloc(sizeof(Btree));
  sqliteHashInit(&(*ppBtree)->tblHash, SQLITE_HASH_INT, 0);

  /* Create binary trees for tables 0, 1 and 2. SQLite assumes these
   * tables always exist. At least I think so? */
  btreeCreateTable(*ppBtree, 0);
  btreeCreateTable(*ppBtree, 1);
................................................................................

/*
 * Create a new table in the supplied Btree. Set *n to the new table number.
 * Return SQLITE_OK if the operation is a success.
 */
static int sqliteBtreeCreateTable(Btree* tree, int* n)
{
  BtRbTree *pNewTbl;
  assert( tree->eTransState != TRANS_NONE );

  *n = tree->next_idx++;
  btreeCreateTable(tree, *n);

  /* Set up the rollback structure (if we are not doing this as part of a
   * rollback) */
................................................................................
 * is left pointing at the new record.
 *
 * If the key exists already in the tree, just replace the data. 
 */
static int sqliteBtreeInsert(BtCursor* pCur, const void *pKey, int nKey,
			     const void *pDataInput, int nData)
{
  BtRbNode *pNode; /* The new node that is begin inserted */
  void * pData;
  int match;

  /* It is illegal to call sqliteBtreeInsert() if we are not in a transaction */
  assert( pCur->pBtree->eTransState != TRANS_NONE );

  /* Take a copy of the input data now, in case we need it for the 
................................................................................
/*
 * Close the supplied Btree. Delete everything associated with it.
 */
static int sqliteBtreeClose(Btree* tree)
{
  HashElem *p;
  for(p=sqliteHashFirst(&tree->tblHash); p; p=sqliteHashNext(p)){
    BtRbTree *pTree = sqliteHashData(p);
    tree->eTransState = TRANS_ROLLBACK;
    sqliteBtreeClearTable(tree, sqliteHashKeysize(p));
    sqliteFree(sqliteHashData(p));
  }
  sqliteFree(tree);
  return SQLITE_OK;
}
................................................................................
/*
 * Execute and delete the supplied rollback-list on pBtree.
 */
static void execute_rollback_list(Btree *pBtree, BtRollbackOp *pList)
{
  BtRollbackOp *pTmp;
  BtCursor cur;
  cur.pBtree = pBtree;

  int res;
  while( pList ){
    switch( pList->eOp ){
      case ROLLBACK_INSERT:
	cur.pTree  = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab );
	assert(cur.pTree);
	cur.iTree  = pList->iTab;
	cur.eSkip  = SKIP_NONE;
................................................................................
    sqliteBtreeData,
    sqliteBtreeCloseCursor,
#ifdef SQLITE_TEST
    sqliteBtreeCursorDump,
#endif

};









|






<

<



>
>
>
>
>
>
>
>







 







<







 







<







 







<







 







<







 







|

|







 







>
>
5
6
7
8
9
10
11
12
13
14
15
16
17
18

19

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
...
567
568
569
570
571
572
573

574
575
576
577
578
579
580
...
591
592
593
594
595
596
597

598
599
600
601
602
603
604
...
690
691
692
693
694
695
696

697
698
699
700
701
702
703
....
1160
1161
1162
1163
1164
1165
1166

1167
1168
1169
1170
1171
1172
1173
....
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
....
1389
1390
1391
1392
1393
1394
1395
1396
1397
** 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.
**
*************************************************************************
** $Id: btree_rb.c,v 1.2 2003/04/15 19:22:23 drh Exp $
**
** This file implements an in-core database using Red-Black balanced
** binary trees.
**
** It was contributed to SQLite by anonymous on 2003-Feb-04 23:24:49 UTC.
*/

#define SQLITE_NO_BTREE_DEFS

#include "btree.h"
#include "sqliteInt.h"
#include <assert.h>

/*
** Omit this whole file if the SQLITE_OMIT_INMEMORYDB macro is
** defined.  This allows a lot of code to be omitted for installations
** that do not need it.
*/
#ifndef SQLITE_OMIT_INMEMORYDB


typedef struct BtRbTree BtRbTree;
typedef struct BtRbNode BtRbNode;
typedef struct BtRollbackOp BtRollbackOp;

/* Forward declarations */
static BtOps sqliteBtreeOps;
................................................................................
    pRollbackOp->pNext = pBtree->pCheckRollback;
    pBtree->pCheckRollback = pRollbackOp;
  }
}

int sqliteRBtreeOpen(const char *zFilename, int mode, int nPg, Btree **ppBtree)
{

  *ppBtree = (Btree *)sqliteMalloc(sizeof(Btree));
  sqliteHashInit(&(*ppBtree)->tblHash, SQLITE_HASH_INT, 0);

  /* Create binary trees for tables 0, 1 and 2. SQLite assumes these
   * tables always exist. At least I think so? */
  btreeCreateTable(*ppBtree, 0);
  btreeCreateTable(*ppBtree, 1);
................................................................................

/*
 * Create a new table in the supplied Btree. Set *n to the new table number.
 * Return SQLITE_OK if the operation is a success.
 */
static int sqliteBtreeCreateTable(Btree* tree, int* n)
{

  assert( tree->eTransState != TRANS_NONE );

  *n = tree->next_idx++;
  btreeCreateTable(tree, *n);

  /* Set up the rollback structure (if we are not doing this as part of a
   * rollback) */
................................................................................
 * is left pointing at the new record.
 *
 * If the key exists already in the tree, just replace the data. 
 */
static int sqliteBtreeInsert(BtCursor* pCur, const void *pKey, int nKey,
			     const void *pDataInput, int nData)
{

  void * pData;
  int match;

  /* It is illegal to call sqliteBtreeInsert() if we are not in a transaction */
  assert( pCur->pBtree->eTransState != TRANS_NONE );

  /* Take a copy of the input data now, in case we need it for the 
................................................................................
/*
 * Close the supplied Btree. Delete everything associated with it.
 */
static int sqliteBtreeClose(Btree* tree)
{
  HashElem *p;
  for(p=sqliteHashFirst(&tree->tblHash); p; p=sqliteHashNext(p)){

    tree->eTransState = TRANS_ROLLBACK;
    sqliteBtreeClearTable(tree, sqliteHashKeysize(p));
    sqliteFree(sqliteHashData(p));
  }
  sqliteFree(tree);
  return SQLITE_OK;
}
................................................................................
/*
 * Execute and delete the supplied rollback-list on pBtree.
 */
static void execute_rollback_list(Btree *pBtree, BtRollbackOp *pList)
{
  BtRollbackOp *pTmp;
  BtCursor cur;
  int res;

  cur.pBtree = pBtree;
  while( pList ){
    switch( pList->eOp ){
      case ROLLBACK_INSERT:
	cur.pTree  = sqliteHashFind( &pBtree->tblHash, 0, pList->iTab );
	assert(cur.pTree);
	cur.iTree  = pList->iTab;
	cur.eSkip  = SKIP_NONE;
................................................................................
    sqliteBtreeData,
    sqliteBtreeCloseCursor,
#ifdef SQLITE_TEST
    sqliteBtreeCursorDump,
#endif

};

#endif /* SQLITE_OMIT_INMEMORYDB */

Changes to src/copy.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
**    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 COPY command.
**
** $Id: copy.c,v 1.1 2003/04/06 21:08:24 drh Exp $
*/
#include "sqliteInt.h"

/*
** The COPY command is for compatibility with PostgreSQL and specificially
** for the ability to read the output of pg_dump.  The format is as
** follows:
................................................................................
        ** value is always pulled from the record number */
        sqliteVdbeAddOp(v, OP_String, 0, 0);
      }else{
        sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
      }
    }
    sqliteGenerateConstraintChecks(pParse, pTab, 0, 0, 0, 0, onError, addr);
    sqliteCompleteInsertion(pParse, pTab, 0, 0, 0, 0);
    if( (db->flags & SQLITE_CountRows)!=0 ){
      sqliteVdbeAddOp(v, OP_AddImm, 1, 0);  /* Increment row count */
    }
    sqliteVdbeAddOp(v, OP_Goto, 0, addr);
    sqliteVdbeResolveLabel(v, end);
    sqliteVdbeAddOp(v, OP_Noop, 0, 0);
    sqliteEndWriteOperation(pParse);







|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
**    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 COPY command.
**
** $Id: copy.c,v 1.2 2003/04/15 19:22:23 drh Exp $
*/
#include "sqliteInt.h"

/*
** The COPY command is for compatibility with PostgreSQL and specificially
** for the ability to read the output of pg_dump.  The format is as
** follows:
................................................................................
        ** value is always pulled from the record number */
        sqliteVdbeAddOp(v, OP_String, 0, 0);
      }else{
        sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
      }
    }
    sqliteGenerateConstraintChecks(pParse, pTab, 0, 0, 0, 0, onError, addr);
    sqliteCompleteInsertion(pParse, pTab, 0, 0, 0, 0, -1);
    if( (db->flags & SQLITE_CountRows)!=0 ){
      sqliteVdbeAddOp(v, OP_AddImm, 1, 0);  /* Increment row count */
    }
    sqliteVdbeAddOp(v, OP_Goto, 0, addr);
    sqliteVdbeResolveLabel(v, end);
    sqliteVdbeAddOp(v, OP_Noop, 0, 0);
    sqliteEndWriteOperation(pParse);

Changes to src/delete.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
67
68
69
70
71
72
73
74
75


76
77
78
79
80
81
82
..
85
86
87
88
89
90
91
92
93
94
95
96

97
98
99
100
101
102
103
...
190
191
192
193
194
195
196






197
198
199
200
201
202
203
...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.50 2003/03/31 02:12:47 drh Exp $
*/
#include "sqliteInt.h"

/*
** Look up every table that is named in pSrc.  If any table is not found,
** add an error message to pParse->zErrMsg and return NULL.  If all tables
** are found, return a pointer to the last table.
................................................................................
  int end, addr;         /* A couple addresses of generated code */
  int i;                 /* Loop counter */
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Index *pIdx;           /* For looping over indices of the table */
  int base;              /* Index of the first available table cursor */
  sqlite *db;            /* Main database structure */

  int row_triggers_exist = 0;
  int oldIdx = -1;



  if( pParse->nErr || sqlite_malloc_failed ){
    pTabList = 0;
    goto delete_from_cleanup;
  }
  db = pParse->db;
  assert( pTabList->nSrc==1 );
................................................................................
  ** defined 
  */
  zTab = pTabList->a[0].zName;
  zDb = pTabList->a[0].zDatabase;
  if( zTab != 0 ){
    pTab = sqliteFindTable(pParse->db, zTab, zDb);
    if( pTab ){
      row_triggers_exist = 
        sqliteTriggersExist(pParse, pTab->pTrigger, 
            TK_DELETE, TK_BEFORE, TK_ROW, 0) ||
        sqliteTriggersExist(pParse, pTab->pTrigger, 
            TK_DELETE, TK_AFTER, TK_ROW, 0);

    }
    if( row_triggers_exist &&  pTab->pSelect ){
      /* Just fire VIEW triggers */
      sqliteSrcListDelete(pTabList);
      sqliteViewTriggers(pParse, pTab, pWhere, OE_Replace, 0);
      return;
    }
................................................................................
    if( db->flags & SQLITE_CountRows ){
      sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
    }

    /* End the database scan loop.
    */
    sqliteWhereEnd(pWInfo);







    /* Delete every item whose key was written to the list during the
    ** database scan.  We have to delete items after the scan is complete
    ** because deleting an item can change the scan order.
    */
    sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
    end = sqliteVdbeMakeLabel(v);
................................................................................
    */
    if( row_triggers_exist ){
      addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
      sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
      sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
      sqliteVdbeAddOp(v, OP_MoveTo, base, 0);
      sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);

      sqliteVdbeAddOp(v, OP_Integer, 13, 0);
      for(i = 0; i<pTab->nCol; i++){
        if( i==pTab->iPKey ){ 
          sqliteVdbeAddOp(v, OP_Recno, base, 0);
	} else {
          sqliteVdbeAddOp(v, OP_Column, base, i);
	}
      }
      sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
      sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
      sqliteVdbeAddOp(v, OP_Close, base, 0);
      sqliteVdbeAddOp(v, OP_Rewind, oldIdx, 0);

      sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, 
          oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
	  addr);
    }

    /* Open cursors for the table we are deleting from and all its







|







 







|
|
>
>







 







<
|
|
|
|
>







 







>
>
>
>
>
>







 







<

<
<
<
|
<
|
<
<
<


<







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
..
87
88
89
90
91
92
93

94
95
96
97
98
99
100
101
102
103
104
105
...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
...
215
216
217
218
219
220
221

222



223

224



225
226

227
228
229
230
231
232
233
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle DELETE FROM statements.
**
** $Id: delete.c,v 1.51 2003/04/15 19:22:23 drh Exp $
*/
#include "sqliteInt.h"

/*
** Look up every table that is named in pSrc.  If any table is not found,
** add an error message to pParse->zErrMsg and return NULL.  If all tables
** are found, return a pointer to the last table.
................................................................................
  int end, addr;         /* A couple addresses of generated code */
  int i;                 /* Loop counter */
  WhereInfo *pWInfo;     /* Information about the WHERE clause */
  Index *pIdx;           /* For looping over indices of the table */
  int base;              /* Index of the first available table cursor */
  sqlite *db;            /* Main database structure */

  int row_triggers_exist = 0;  /* True if any triggers exist */
  int before_triggers;         /* True if there are BEFORE triggers */
  int after_triggers;          /* True if there are AFTER triggers */
  int oldIdx = -1;             /* Cursor for the OLD table of AFTER triggers */

  if( pParse->nErr || sqlite_malloc_failed ){
    pTabList = 0;
    goto delete_from_cleanup;
  }
  db = pParse->db;
  assert( pTabList->nSrc==1 );
................................................................................
  ** defined 
  */
  zTab = pTabList->a[0].zName;
  zDb = pTabList->a[0].zDatabase;
  if( zTab != 0 ){
    pTab = sqliteFindTable(pParse->db, zTab, zDb);
    if( pTab ){

      before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
                             TK_DELETE, TK_BEFORE, TK_ROW, 0);
      after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, 
                             TK_DELETE, TK_AFTER, TK_ROW, 0);
      row_triggers_exist = before_triggers || after_triggers;
    }
    if( row_triggers_exist &&  pTab->pSelect ){
      /* Just fire VIEW triggers */
      sqliteSrcListDelete(pTabList);
      sqliteViewTriggers(pParse, pTab, pWhere, OE_Replace, 0);
      return;
    }
................................................................................
    if( db->flags & SQLITE_CountRows ){
      sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
    }

    /* End the database scan loop.
    */
    sqliteWhereEnd(pWInfo);

    /* Open the pseudo-table used to store OLD if there are triggers.
    */
    if( row_triggers_exist ){
      sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
    }

    /* Delete every item whose key was written to the list during the
    ** database scan.  We have to delete items after the scan is complete
    ** because deleting an item can change the scan order.
    */
    sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
    end = sqliteVdbeMakeLabel(v);
................................................................................
    */
    if( row_triggers_exist ){
      addr = sqliteVdbeAddOp(v, OP_ListRead, 0, end);
      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
      sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
      sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
      sqliteVdbeAddOp(v, OP_MoveTo, base, 0);





      sqliteVdbeAddOp(v, OP_Recno, base, 0);

      sqliteVdbeAddOp(v, OP_RowData, base, 0);



      sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);
      sqliteVdbeAddOp(v, OP_Close, base, 0);


      sqliteCodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, 
          oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default,
	  addr);
    }

    /* Open cursors for the table we are deleting from and all its

Changes to src/expr.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
...
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.91 2003/03/31 02:12:47 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Construct a new expression node and return a pointer to it.  Memory
** for this node is obtained from sqliteMalloc().  The calling function
................................................................................
          }
        }
        if( 0==(cntTab++) ) pExpr->iTable = i + base;
        for(j=0; j<pTab->nCol; j++){
          if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
            cnt++;
            pExpr->iTable = i + base;
            if( j==pTab->iPKey ){
              /* Substitute the record number for the INTEGER PRIMARY KEY */
              pExpr->iColumn = -1;
            }else{
              pExpr->iColumn = j;
            }
            pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK;
          }
        }
      }

      /* If we have not already resolved this *.* expression, then maybe 
       * it is a new.* or old.* trigger argument reference */
................................................................................

        if( t ){ 
	  int j;
          Table *pTab = pTriggerStack->pTab;
          for(j=0; j < pTab->nCol; j++) {
            if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
              cnt++;
              pExpr->iColumn = j;
              pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK;
            }
          }
	}
      }

      if( cnt==0 && cntTab==1 && sqliteIsRowid(zRight) ){







|







 







<
|
<
<
|
<







 







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
543
544
545
546
547
548
549

550


551

552
553
554
555
556
557
558
...
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
** $Id: expr.c,v 1.92 2003/04/15 19:22:23 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** Construct a new expression node and return a pointer to it.  Memory
** for this node is obtained from sqliteMalloc().  The calling function
................................................................................
          }
        }
        if( 0==(cntTab++) ) pExpr->iTable = i + base;
        for(j=0; j<pTab->nCol; j++){
          if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
            cnt++;
            pExpr->iTable = i + base;

            /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */


            pExpr->iColumn = j==pTab->iPKey ? -1 : j;

            pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK;
          }
        }
      }

      /* If we have not already resolved this *.* expression, then maybe 
       * it is a new.* or old.* trigger argument reference */
................................................................................

        if( t ){ 
	  int j;
          Table *pTab = pTriggerStack->pTab;
          for(j=0; j < pTab->nCol; j++) {
            if( sqliteStrICmp(pTab->aCol[j].zName, zRight)==0 ){
              cnt++;
              pExpr->iColumn = j==pTab->iPKey ? -1 : j;
              pExpr->dataType = pTab->aCol[j].sortOrder & SQLITE_SO_TYPEMASK;
            }
          }
	}
      }

      if( cnt==0 && cntTab==1 && sqliteIsRowid(zRight) ){

Changes to src/insert.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
106
107
108
109
110
111
112


113
114
115
116
117
118
119
120
...
128
129
130
131
132
133
134
135
136
137
138


139
140
141
142
143
144
145
...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
...
346
347
348
349
350
351
352


353
354
355
356







357














358
359
360
361
362
363
364
...
379
380
381
382
383
384
385
386
387





388
389
390
391
392
393
394
...
455
456
457
458
459
460
461
462

463
464
465
466
467
468
469
...
803
804
805
806
807
808
809
810

811
812
813
814
815
816
817
...
819
820
821
822
823
824
825





826
827
828
829
830
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.78 2003/04/03 01:50:44 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................
  int srcTab;           /* Data comes from this temporary cursor if >=0 */
  int iSelectLoop;      /* Address of code that implements the SELECT */
  int iCleanup;         /* Address of the cleanup code */
  int iInsertBlock;     /* Address of the subroutine used to insert data */
  int iCntMem;          /* Memory cell used for the row counter */

  int row_triggers_exist = 0; /* True if there are FOR EACH ROW triggers */


  int newIdx = -1;

  if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
  db = pParse->db;

  /* Locate the table into which we will be inserting new information.
  */
  assert( pTabList->nSrc==1 );
................................................................................
    goto insert_cleanup;
  }

  /* Ensure that:
  *  (a) the table is not read-only, 
  *  (b) that if it is a view then ON INSERT triggers exist
  */
  row_triggers_exist = 
    sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT, 
        TK_BEFORE, TK_ROW, 0) ||
    sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT, TK_AFTER, TK_ROW, 0);


  if( pTab->readOnly || (pTab->pSelect && !row_triggers_exist) ){
    sqliteErrorMsg(pParse, "%s %s may not be modified",
      pTab->pSelect ? "view" : "table",
      zTab);
    goto insert_cleanup;
  }

................................................................................
  if( pColumn==0 ){
    keyColumn = pTab->iPKey;
  }

  /* Open the temp table for FOR EACH ROW triggers
  */
  if( row_triggers_exist ){
    sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);
  }
    
  /* Initialize the count of rows to be inserted
  */
  if( db->flags & SQLITE_CountRows ){
    iCntMem = pParse->nMem++;
    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
................................................................................
    sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak);
    iCont = sqliteVdbeCurrentAddr(v);
  }else if( pSelect ){
    sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop);
    sqliteVdbeResolveLabel(v, iInsertBlock);
  }



  endOfLoop = sqliteVdbeMakeLabel(v);
  if( row_triggers_exist ){

    /* build the new.* reference row */







    sqliteVdbeAddOp(v, OP_Integer, 13, 0);














    for(i=0; i<pTab->nCol; i++){
      if( pColumn==0 ){
        j = i;
      }else{
        for(j=0; j<pColumn->nId; j++){
          if( pColumn->a[j].idx==i ) break;
        }
................................................................................
    sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);

    /* Fire BEFORE triggers */
    if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_BEFORE, pTab, newIdx, -1, 
        onError, endOfLoop) ){
      goto insert_cleanup;
    }

    /* Open the tables and indices for the INSERT */





    if( !pTab->pSelect ){
      base = pParse->nTab;
      sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
      sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
      sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
      for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
        sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
................................................................................
      }
    }

    /* Generate code to check constraints and generate index keys and
    ** do the insertion.
    */
    sqliteGenerateConstraintChecks(pParse, pTab, base, 0,0,0,onError,endOfLoop);
    sqliteCompleteInsertion(pParse, pTab, base, 0,0,0);


    /* Update the count of rows that are inserted
    */
    if( (db->flags & SQLITE_CountRows)!=0 ){
      sqliteVdbeAddOp(v, OP_MemIncr, iCntMem, 0);
    }
  }
................................................................................
*/
void sqliteCompleteInsertion(
  Parse *pParse,      /* The parser context */
  Table *pTab,        /* the table into which we are inserting */
  int base,           /* Index of a read/write cursor pointing at pTab */
  char *aIdxUsed,     /* Which indices are used.  NULL means all are used */
  int recnoChng,      /* True if the record number will change */
  int isUpdate        /* True for UPDATE, False for INSERT */

){
  int i;
  Vdbe *v;
  int nIdx;
  Index *pIdx;

  v = sqliteGetVdbe(pParse);
................................................................................
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
  for(i=nIdx-1; i>=0; i--){
    if( aIdxUsed && aIdxUsed[i]==0 ) continue;
    sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, 0);
  }
  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);





  sqliteVdbeAddOp(v, OP_PutIntKey, base, pParse->trigStack?0:1);
  if( isUpdate && recnoChng ){
    sqliteVdbeAddOp(v, OP_Pop, 1, 0);
  }
}







|







 







>
>
|







 







<
|
|
|
>
>







 







|







 







>
>

|

<
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
<
>
>
>
>
>







 







|
>







 







|
>







 







>
>
>
>
>





8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
...
130
131
132
133
134
135
136

137
138
139
140
141
142
143
144
145
146
147
148
...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
...
349
350
351
352
353
354
355
356
357
358
359
360

361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
...
404
405
406
407
408
409
410
411

412
413
414
415
416
417
418
419
420
421
422
423
...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
...
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
...
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
** $Id: insert.c,v 1.79 2003/04/15 19:22:23 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine is call to handle SQL of the following forms:
**
**    insert into TABLE (IDLIST) values(EXPRLIST)
................................................................................
  int srcTab;           /* Data comes from this temporary cursor if >=0 */
  int iSelectLoop;      /* Address of code that implements the SELECT */
  int iCleanup;         /* Address of the cleanup code */
  int iInsertBlock;     /* Address of the subroutine used to insert data */
  int iCntMem;          /* Memory cell used for the row counter */

  int row_triggers_exist = 0; /* True if there are FOR EACH ROW triggers */
  int before_triggers;        /* True if there are BEFORE triggers */
  int after_triggers;         /* True if there are AFTER triggers */
  int newIdx = -1;            /* Cursor for the NEW table */

  if( pParse->nErr || sqlite_malloc_failed ) goto insert_cleanup;
  db = pParse->db;

  /* Locate the table into which we will be inserting new information.
  */
  assert( pTabList->nSrc==1 );
................................................................................
    goto insert_cleanup;
  }

  /* Ensure that:
  *  (a) the table is not read-only, 
  *  (b) that if it is a view then ON INSERT triggers exist
  */

  before_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT, 
                                       TK_BEFORE, TK_ROW, 0);
  after_triggers = sqliteTriggersExist(pParse, pTab->pTrigger, TK_INSERT,
                                       TK_AFTER, TK_ROW, 0);
  row_triggers_exist = before_triggers || after_triggers;
  if( pTab->readOnly || (pTab->pSelect && !row_triggers_exist) ){
    sqliteErrorMsg(pParse, "%s %s may not be modified",
      pTab->pSelect ? "view" : "table",
      zTab);
    goto insert_cleanup;
  }

................................................................................
  if( pColumn==0 ){
    keyColumn = pTab->iPKey;
  }

  /* Open the temp table for FOR EACH ROW triggers
  */
  if( row_triggers_exist ){
    sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
  }
    
  /* Initialize the count of rows to be inserted
  */
  if( db->flags & SQLITE_CountRows ){
    iCntMem = pParse->nMem++;
    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
................................................................................
    sqliteVdbeAddOp(v, OP_Rewind, srcTab, iBreak);
    iCont = sqliteVdbeCurrentAddr(v);
  }else if( pSelect ){
    sqliteVdbeAddOp(v, OP_Goto, 0, iSelectLoop);
    sqliteVdbeResolveLabel(v, iInsertBlock);
  }

  /* Run the BEFORE triggers, if there are any
  */
  endOfLoop = sqliteVdbeMakeLabel(v);
  if( before_triggers ){


    /* build the NEW.* reference row.  Note that if there is an INTEGER
    ** PRIMARY KEY into which a NULL is being inserted, that NULL will be
    ** translated into a unique ID for the row.  But on a BEFORE trigger,
    ** we do not know what the unique ID will be (because the insert has
    ** not happened yet) so we substitute a rowid of -1
    */
    if( keyColumn<0 ){
      sqliteVdbeAddOp(v, OP_Integer, -1, 0);
    }else if( useTempTable ){
      sqliteVdbeAddOp(v, OP_Column, srcTab, keyColumn);
    }else if( pSelect ){
      sqliteVdbeAddOp(v, OP_Dup, nColumn - keyColumn - 1, 1);
    }else{
      sqliteExprCode(pParse, pList->a[keyColumn].pExpr);
      sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3);
      sqliteVdbeAddOp(v, OP_Pop, 1, 0);
      sqliteVdbeAddOp(v, OP_Integer, -1, 0);
      sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
    }

    /* Create the new column data
    */
    for(i=0; i<pTab->nCol; i++){
      if( pColumn==0 ){
        j = i;
      }else{
        for(j=0; j<pColumn->nId; j++){
          if( pColumn->a[j].idx==i ) break;
        }
................................................................................
    sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);

    /* Fire BEFORE triggers */
    if( sqliteCodeRowTrigger(pParse, TK_INSERT, 0, TK_BEFORE, pTab, newIdx, -1, 
        onError, endOfLoop) ){
      goto insert_cleanup;
    }
  }


  /* If any triggers exists, the opening of tables and indices is deferred
  ** until now.
  */
  if( row_triggers_exist ){
    if( !pTab->pSelect ){
      base = pParse->nTab;
      sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
      sqliteVdbeAddOp(v, OP_OpenWrite, base, pTab->tnum);
      sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC);
      for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
        sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
................................................................................
      }
    }

    /* Generate code to check constraints and generate index keys and
    ** do the insertion.
    */
    sqliteGenerateConstraintChecks(pParse, pTab, base, 0,0,0,onError,endOfLoop);
    sqliteCompleteInsertion(pParse, pTab, base, 0,0,0,
                            after_triggers ? newIdx : -1);

    /* Update the count of rows that are inserted
    */
    if( (db->flags & SQLITE_CountRows)!=0 ){
      sqliteVdbeAddOp(v, OP_MemIncr, iCntMem, 0);
    }
  }
................................................................................
*/
void sqliteCompleteInsertion(
  Parse *pParse,      /* The parser context */
  Table *pTab,        /* the table into which we are inserting */
  int base,           /* Index of a read/write cursor pointing at pTab */
  char *aIdxUsed,     /* Which indices are used.  NULL means all are used */
  int recnoChng,      /* True if the record number will change */
  int isUpdate,       /* True for UPDATE, False for INSERT */
  int newIdx          /* Index of NEW table for triggers.  -1 if none */
){
  int i;
  Vdbe *v;
  int nIdx;
  Index *pIdx;

  v = sqliteGetVdbe(pParse);
................................................................................
  assert( pTab->pSelect==0 );  /* This table is not a VIEW */
  for(nIdx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, nIdx++){}
  for(i=nIdx-1; i>=0; i--){
    if( aIdxUsed && aIdxUsed[i]==0 ) continue;
    sqliteVdbeAddOp(v, OP_IdxPut, base+i+1, 0);
  }
  sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
  if( newIdx>=0 ){
    sqliteVdbeAddOp(v, OP_Dup, 1, 0);
    sqliteVdbeAddOp(v, OP_Dup, 1, 0);
    sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
  }
  sqliteVdbeAddOp(v, OP_PutIntKey, base, pParse->trigStack?0:1);
  if( isUpdate && recnoChng ){
    sqliteVdbeAddOp(v, OP_Pop, 1, 0);
  }
}

Changes to src/sqliteInt.h.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
....
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.172 2003/04/15 01:19:49 drh Exp $
*/
#include "config.h"
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
................................................................................
/*
** When building SQLite for embedded systems where memory is scarce,
** you can define one or more of the following macros to omit extra
** features of the library and thus keep the size of the library to
** a minimum.
*/
/* #define SQLITE_OMIT_AUTHORIZATION  1 */
#define SQLITE_OMIT_INMEMORYDB     1
/* #define SQLITE_OMIT_TRACE          1 */
/* #define SQLITE_OMIT_VACUUM         1 */

/*
** Integers of known sizes.  These typedefs might change for architectures
** where the sizes very.  Preprocessor macros are available so that the
** types can be conveniently redefined at compile-type.  Like this:
................................................................................
void sqliteRollbackTransaction(Parse*);
int sqliteExprIsConstant(Expr*);
int sqliteExprIsInteger(Expr*, int*);
int sqliteIsRowid(const char*);
void sqliteGenerateRowDelete(sqlite*, Vdbe*, Table*, int, int);
void sqliteGenerateRowIndexDelete(sqlite*, Vdbe*, Table*, int, char*);
void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int);
void sqliteBeginWriteOperation(Parse*, int, int);
void sqliteEndWriteOperation(Parse*);
Expr *sqliteExprDup(Expr*);
void sqliteTokenCopy(Token*, Token*);
ExprList *sqliteExprListDup(ExprList*);
SrcList *sqliteSrcListDup(SrcList*);
IdList *sqliteIdListDup(IdList*);







|







 







|







 







|







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
..
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
....
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
**    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.
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.173 2003/04/15 19:22:24 drh Exp $
*/
#include "config.h"
#include "sqlite.h"
#include "hash.h"
#include "vdbe.h"
#include "parse.h"
#include "btree.h"
................................................................................
/*
** When building SQLite for embedded systems where memory is scarce,
** you can define one or more of the following macros to omit extra
** features of the library and thus keep the size of the library to
** a minimum.
*/
/* #define SQLITE_OMIT_AUTHORIZATION  1 */
/* #define SQLITE_OMIT_INMEMORYDB     1 */
/* #define SQLITE_OMIT_TRACE          1 */
/* #define SQLITE_OMIT_VACUUM         1 */

/*
** Integers of known sizes.  These typedefs might change for architectures
** where the sizes very.  Preprocessor macros are available so that the
** types can be conveniently redefined at compile-type.  Like this:
................................................................................
void sqliteRollbackTransaction(Parse*);
int sqliteExprIsConstant(Expr*);
int sqliteExprIsInteger(Expr*, int*);
int sqliteIsRowid(const char*);
void sqliteGenerateRowDelete(sqlite*, Vdbe*, Table*, int, int);
void sqliteGenerateRowIndexDelete(sqlite*, Vdbe*, Table*, int, char*);
void sqliteGenerateConstraintChecks(Parse*,Table*,int,char*,int,int,int,int);
void sqliteCompleteInsertion(Parse*, Table*, int, char*, int, int, int);
void sqliteBeginWriteOperation(Parse*, int, int);
void sqliteEndWriteOperation(Parse*);
Expr *sqliteExprDup(Expr*);
void sqliteTokenCopy(Token*, Token*);
ExprList *sqliteExprListDup(ExprList*);
SrcList *sqliteSrcListDup(SrcList*);
IdList *sqliteIdListDup(IdList*);

Changes to src/trigger.c.

710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727

  v = sqliteGetVdbe(pParse);
  assert(v);
  sqliteBeginWriteOperation(pParse, 1, 0);

  /* Allocate temp tables */
  oldIdx = pParse->nTab++;
  sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
  if( pChanges ){
    newIdx = pParse->nTab++;
    sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);
  }

  /* Snapshot the view */
  if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){
    goto trigger_cleanup;
  }








|


|







710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727

  v = sqliteGetVdbe(pParse);
  assert(v);
  sqliteBeginWriteOperation(pParse, 1, 0);

  /* Allocate temp tables */
  oldIdx = pParse->nTab++;
  sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
  if( pChanges ){
    newIdx = pParse->nTab++;
    sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0);
  }

  /* Snapshot the view */
  if( sqliteSelect(pParse, &theSelect, SRT_Table, oldIdx, 0, 0, 0) ){
    goto trigger_cleanup;
  }

Changes to src/update.c.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
43
44
45
46
47
48
49


50
51
52
53
54
55
56
57
..
60
61
62
63
64
65
66
67
68
69

70
71

72
73
74
75
76
77
78
...
215
216
217
218
219
220
221
222
223

224
225
226


227
228
229
230



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256


257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
...
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.58 2003/03/31 02:12:48 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process an UPDATE statement.
*/
void sqliteUpdate(
................................................................................
  int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
                         ** an expression for the i-th column of the table.
                         ** aXRef[i]==-1 if the i-th column is not changed. */
  int chngRecno;         /* True if the record number is being changed */
  Expr *pRecnoExpr;      /* Expression defining the new record number */
  int openAll;           /* True if all indices need to be opened */



  int row_triggers_exist = 0;

  int newIdx      = -1;  /* index of trigger "new" temp table       */
  int oldIdx      = -1;  /* index of trigger "old" temp table       */

  if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
  db = pParse->db;
  assert( pTabList->nSrc==1 );
................................................................................
   * defined 
   */
  zTab = pTabList->a[0].zName;
  zDb = pTabList->a[0].zDatabase;
  if( zTab != 0 ){
    pTab = sqliteFindTable(pParse->db, zTab, zDb);
    if( pTab ){
      row_triggers_exist = 
        sqliteTriggersExist(pParse, pTab->pTrigger, 
            TK_UPDATE, TK_BEFORE, TK_ROW, pChanges) ||

        sqliteTriggersExist(pParse, pTab->pTrigger, 
            TK_UPDATE, TK_AFTER, TK_ROW, pChanges);

    }

    if( row_triggers_exist &&  pTab->pSelect ){
      /* Just fire VIEW triggers */
      sqliteSrcListDelete(pTabList);
      sqliteViewTriggers(pParse, pTab, pWhere, onError, pChanges);
      return;
................................................................................
  /* Initialize the count of updated rows
  */
  if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
  }

  if( row_triggers_exist ){
    int ii;


    sqliteVdbeAddOp(v, OP_OpenTemp, oldIdx, 0);
    sqliteVdbeAddOp(v, OP_OpenTemp, newIdx, 0);



    sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
    addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
    sqliteVdbeAddOp(v, OP_Dup, 0, 0);




    sqliteVdbeAddOp(v, OP_Dup, 0, 0);
    sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
    sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
    sqliteVdbeAddOp(v, OP_MoveTo, base, 0);

    sqliteVdbeAddOp(v, OP_Integer, 13, 0);
    for(ii = 0; ii < pTab->nCol; ii++){
      if( ii == pTab->iPKey ){
	sqliteVdbeAddOp(v, OP_Recno, base, 0);
      }else{
	sqliteVdbeAddOp(v, OP_Column, base, ii);
      }
    }
    sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
    sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);

    sqliteVdbeAddOp(v, OP_Integer, 13, 0);
    for(ii = 0; ii < pTab->nCol; ii++){
      if( aXRef[ii] < 0 ){
        if( ii == pTab->iPKey ){
          sqliteVdbeAddOp(v, OP_Recno, base, 0);
	}else{
          sqliteVdbeAddOp(v, OP_Column, base, ii);
	}
      }else{
        sqliteExprCode(pParse, pChanges->a[aXRef[ii]].pExpr);


      }
    }
    sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
    sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
    sqliteVdbeAddOp(v, OP_Close, base, 0);

    sqliteVdbeAddOp(v, OP_Rewind, oldIdx, 0);
    sqliteVdbeAddOp(v, OP_Rewind, newIdx, 0);

    if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab, 
          newIdx, oldIdx, onError, addr) ){
      goto update_cleanup;
    }
  }

  /* Rewind the list of records that need to be updated and
................................................................................
  */
  if( chngRecno ){
    sqliteVdbeAddOp(v, OP_Delete, base, 0);
  }

  /* Create the new index entries and the new record.
  */
  sqliteCompleteInsertion(pParse, pTab, base, aIdxUsed, chngRecno, 1);

  /* Increment the row counter 
  */
  if( db->flags & SQLITE_CountRows && !pParse->trigStack){
    sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
  }








|







 







>
>
|







 







|

|
>


>







 







|
<
>
|
|

>
>




>
>
>





|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>






|
|
<







 







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
..
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
..
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
...
219
220
221
222
223
224
225
226

227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275

276
277
278
279
280
281
282
...
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle UPDATE statements.
**
** $Id: update.c,v 1.59 2003/04/15 19:22:24 drh Exp $
*/
#include "sqliteInt.h"

/*
** Process an UPDATE statement.
*/
void sqliteUpdate(
................................................................................
  int *aXRef = 0;        /* aXRef[i] is the index in pChanges->a[] of the
                         ** an expression for the i-th column of the table.
                         ** aXRef[i]==-1 if the i-th column is not changed. */
  int chngRecno;         /* True if the record number is being changed */
  Expr *pRecnoExpr;      /* Expression defining the new record number */
  int openAll;           /* True if all indices need to be opened */

  int before_triggers;         /* True if there are any BEFORE triggers */
  int after_triggers;          /* True if there are any AFTER triggers */
  int row_triggers_exist = 0;  /* True if any row triggers exist */

  int newIdx      = -1;  /* index of trigger "new" temp table       */
  int oldIdx      = -1;  /* index of trigger "old" temp table       */

  if( pParse->nErr || sqlite_malloc_failed ) goto update_cleanup;
  db = pParse->db;
  assert( pTabList->nSrc==1 );
................................................................................
   * defined 
   */
  zTab = pTabList->a[0].zName;
  zDb = pTabList->a[0].zDatabase;
  if( zTab != 0 ){
    pTab = sqliteFindTable(pParse->db, zTab, zDb);
    if( pTab ){
      before_triggers =
        sqliteTriggersExist(pParse, pTab->pTrigger, 
            TK_UPDATE, TK_BEFORE, TK_ROW, pChanges);
      after_triggers = 
        sqliteTriggersExist(pParse, pTab->pTrigger, 
            TK_UPDATE, TK_AFTER, TK_ROW, pChanges);
      row_triggers_exist = before_triggers || after_triggers;
    }

    if( row_triggers_exist &&  pTab->pSelect ){
      /* Just fire VIEW triggers */
      sqliteSrcListDelete(pTabList);
      sqliteViewTriggers(pParse, pTab, pWhere, onError, pChanges);
      return;
................................................................................
  /* Initialize the count of updated rows
  */
  if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
    sqliteVdbeAddOp(v, OP_Integer, 0, 0);
  }

  if( row_triggers_exist ){
    /* Create pseudo-tables for NEW and OLD

    */
    sqliteVdbeAddOp(v, OP_OpenPseudo, oldIdx, 0);
    sqliteVdbeAddOp(v, OP_OpenPseudo, newIdx, 0);

    /* The top of the update loop for when there are triggers.
    */
    sqliteVdbeAddOp(v, OP_ListRewind, 0, 0);
    addr = sqliteVdbeAddOp(v, OP_ListRead, 0, 0);
    sqliteVdbeAddOp(v, OP_Dup, 0, 0);

    /* Open a cursor and make it point to the record that is
    ** being updated.
    */
    sqliteVdbeAddOp(v, OP_Dup, 0, 0);
    sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
    sqliteVdbeAddOp(v, OP_OpenRead, base, pTab->tnum);
    sqliteVdbeAddOp(v, OP_MoveTo, base, 0);

    /* Generate the OLD table
    */
    sqliteVdbeAddOp(v, OP_Recno, base, 0);
    sqliteVdbeAddOp(v, OP_RowData, base, 0);
    sqliteVdbeAddOp(v, OP_PutIntKey, oldIdx, 0);

    /* Generate the NEW table
    */
    if( chngRecno ){
      sqliteExprCode(pParse, pRecnoExpr);
    }else{
      sqliteVdbeAddOp(v, OP_Recno, base, 0);
    }
    for(i=0; i<pTab->nCol; i++){
      if( i==pTab->iPKey ){
        sqliteVdbeAddOp(v, OP_String, 0, 0);
        continue;
      }
      j = aXRef[i];
      if( j<0 ){
        sqliteVdbeAddOp(v, OP_Column, base, i);
      }else{
        sqliteExprCode(pParse, pChanges->a[j].pExpr);
      }
    }
    sqliteVdbeAddOp(v, OP_MakeRecord, pTab->nCol, 0);
    sqliteVdbeAddOp(v, OP_PutIntKey, newIdx, 0);
    sqliteVdbeAddOp(v, OP_Close, base, 0);

    /* Fire the BEFORE triggers
    */

    if( sqliteCodeRowTrigger(pParse, TK_UPDATE, pChanges, TK_BEFORE, pTab, 
          newIdx, oldIdx, onError, addr) ){
      goto update_cleanup;
    }
  }

  /* Rewind the list of records that need to be updated and
................................................................................
  */
  if( chngRecno ){
    sqliteVdbeAddOp(v, OP_Delete, base, 0);
  }

  /* Create the new index entries and the new record.
  */
  sqliteCompleteInsertion(pParse, pTab, base, aIdxUsed, chngRecno, 1, -1);

  /* Increment the row counter 
  */
  if( db->flags & SQLITE_CountRows && !pParse->trigStack){
    sqliteVdbeAddOp(v, OP_AddImm, 1, 0);
  }

Changes to src/vdbe.c.

32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
..
75
76
77
78
79
80
81





82
83
84
85
86
87
88
89
90
91
92

93



94
95
96
97
98
99
100
....
1119
1120
1121
1122
1123
1124
1125

1126
1127
1128
1129
1130
1131
1132
....
3517
3518
3519
3520
3521
3522
3523























3524
3525
3526
3527
3528
3529
3530
....
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
....
3580
3581
3582
3583
3584
3585
3586
3587


3588
3589
3590
3591
3592
3593
3594
....
3922
3923
3924
3925
3926
3927
3928


3929
3930
3931
3932
3933
3934
3935
3936
3937

3938
3939
3940
3941
3942
3943
3944
....
3950
3951
3952
3953
3954
3955
3956





















3957
3958

3959
3960
3961
3962
3963
3964
3965
....
3970
3971
3972
3973
3974
3975
3976


3977
3978
3979
3980
3981


3982
3983
3984
3985
3986
3987
3988
....
3991
3992
3993
3994
3995
3996
3997
3998
3999





















































4000
4001
4002
4003
4004
4005
4006
....
4027
4028
4029
4030
4031
4032
4033

4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048




4049
4050
4051
4052
4053
4054
4055
....
4131
4132
4133
4134
4135
4136
4137
4138

4139
4140
4141
4142
4143
4144
4145
4146


4147

4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164


4165
4166
4167
4168
4169
4170
4171

4172
4173
4174
4175
4176
4177
4178
....
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222

4223
4224
4225


4226
4227
4228
4229
4230
4231


4232
4233
4234
4235
4236
4237
4238
....
4239
4240
4241
4242
4243
4244
4245

4246
4247
4248


4249
4250
4251
4252
4253
4254
4255


4256
4257
4258
4259
4260
4261
4262
....
4275
4276
4277
4278
4279
4280
4281
4282
4283

4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296

4297

4298
4299
4300
4301
4302
4303
4304
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** 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.214 2003/04/15 14:01:43 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The makefile scans this source file and creates the following
** array of string constants which are the names of all VDBE opcodes.
................................................................................
** The cursor can seek to a BTree entry with a particular key, or
** loop over all entries of the Btree.  You can also insert new BTree
** entries or retrieve the key or data from the entry that the cursor
** is currently pointing to.
** 
** Every cursor that the virtual machine has open is represented by an
** instance of the following structure.





*/
struct Cursor {
  BtCursor *pCursor;    /* The cursor structure of the backend */
  int lastRecno;        /* Last recno from a Next or NextIdx operation */
  int nextRowid;        /* Next rowid returned by OP_NewRowid */
  Bool recnoIsValid;    /* True if lastRecno is valid */
  Bool keyAsData;       /* The OP_Column command works on key instead of data */
  Bool atFirst;         /* True if pointing to first entry */
  Bool useRandomRowid;  /* Generate new record numbers semi-randomly */
  Bool nullRow;         /* True if pointing to a row with no data */
  Bool nextRowidValid;  /* True if the nextRowid field is valid */

  Btree *pBt;           /* Separate file holding temporary table */



};
typedef struct Cursor Cursor;

/*
** A sorter builds a list of elements to be sorted.  Each element of
** the list is an instance of the following structure.
*/
................................................................................
static void cleanupCursor(Cursor *pCx){
  if( pCx->pCursor ){
    sqliteBtreeCloseCursor(pCx->pCursor);
  }
  if( pCx->pBt ){
    sqliteBtreeClose(pCx->pBt);
  }

  memset(pCx, 0, sizeof(Cursor));
}

/*
** Close all cursors
*/
static void closeAllCursors(Vdbe *p){
................................................................................
      }
    }else{
      rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor);
    }
  }
  break;
}
























/*
** Opcode: RenameCursor P1 P2 *
**
** Rename cursor number P1 as cursor number P2.  If P2 was previously
** opened is is closed before the renaming occurs.
*/
................................................................................
/* Opcode: Close P1 * *
**
** Close a cursor previously opened as P1.  If P1 is not
** currently open, this instruction is a no-op.
*/
case OP_Close: {
  int i = pOp->p1;
  if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){
    cleanupCursor(&p->aCsr[i]);
  }
  break;
}

/* Opcode: MoveTo P1 P2 *
**
................................................................................
case OP_MoveLt:
case OP_MoveTo: {
  int i = pOp->p1;
  int tos = p->tos;
  Cursor *pC;

  VERIFY( if( tos<0 ) goto not_enough_stack; )
  if( i>=0 && i<p->nCursor && (pC = &p->aCsr[i])->pCursor!=0 ){


    int res, oc;
    if( aStack[tos].flags & STK_Int ){
      int iKey = intToKey(aStack[tos].i);
      sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res);
      pC->lastRecno = aStack[tos].i;
      pC->recnoIsValid = res==0;
    }else{
................................................................................
/* Opcode: PutStrKey P1 * *
**
** Write an entry into the database file P1.  A new entry is
** created if it doesn't already exist or the data for an existing
** entry is overwritten.  The data is the value on the top of the
** stack.  The key is the next value down on the stack.  The key must
** be a string.  The stack is popped twice by this instruction.


*/
case OP_PutIntKey:
case OP_PutStrKey: {
  int tos = p->tos;
  int nos = p->tos-1;
  int i = pOp->p1;
  Cursor *pC;
  VERIFY( if( nos<0 ) goto not_enough_stack; )
  if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){

    char *zKey;
    int nKey, iKey;
    if( pOp->opcode==OP_PutStrKey ){
      Stringify(p, nos);
      nKey = aStack[nos].n;
      zKey = zStack[nos];
    }else{
................................................................................
        db->nChange++;
        db->lastRowid = aStack[nos].i;
      }
      if( pC->nextRowidValid && aStack[nos].i>=pC->nextRowid ){
        pC->nextRowidValid = 0;
      }
    }





















    rc = sqliteBtreeInsert(pC->pCursor, zKey, nKey,
                        zStack[tos], aStack[tos].n);

    pC->recnoIsValid = 0;
  }
  POPSTACK;
  POPSTACK;
  break;
}

................................................................................
** The cursor will be left pointing at either the next or the previous
** record in the table. If it is left pointing at the next record, then
** the next Next instruction will be a no-op.  Hence it is OK to delete
** a record from within an Next loop.
**
** The row change counter is incremented if P2==1 and is unmodified
** if P2==0.


*/
case OP_Delete: {
  int i = pOp->p1;
  Cursor *pC;
  if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){


    rc = sqliteBtreeDelete(pC->pCursor);
    pC->nextRowidValid = 0;
  }
  if( pOp->p2 ) db->nChange++;
  break;
}

................................................................................
** Turn the key-as-data mode for cursor P1 either on (if P2==1) or
** off (if P2==0).  In key-as-data mode, the Field opcode pulls
** data off of the key rather than the data.  This is useful for
** processing compound selects.
*/
case OP_KeyAsData: {
  int i = pOp->p1;
  if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){
    p->aCsr[i].keyAsData = pOp->p2;





















































  }
  break;
}

/* Opcode: Column P1 P2 *
**
** Interpret the data that cursor P1 points to as
................................................................................
  int tos = p->tos+1;
  Cursor *pC;
  char *zRec;
  BtCursor *pCrsr;
  int idxWidth;
  unsigned char aHdr[10];


  if( i<0 ){
    VERIFY( if( tos+i<0 ) goto bad_instruction; )
    VERIFY( if( (aStack[tos+i].flags & STK_Str)==0 ) goto bad_instruction; )
    zRec = zStack[tos+i];
    payloadSize = aStack[tos+i].n;
  }else if( VERIFY( i>=0 && i<p->nCursor && ) (pC = &p->aCsr[i])->pCursor!=0 ){
    zRec = 0;
    pCrsr = pC->pCursor;
    if( pC->nullRow ){
      payloadSize = 0;
    }else if( pC->keyAsData ){
      sqliteBtreeKeySize(pCrsr, &payloadSize);
    }else{
      sqliteBtreeDataSize(pCrsr, &payloadSize);
    }




  }else{
    payloadSize = 0;
  }

  /* Figure out how many bytes in the column data and where the column
  ** data begins.
  */
................................................................................
** the key to the current entry in a sequential scan of the database
** file P1.  The sequential scan should have been started using the 
** Next opcode.
*/
case OP_Recno: {
  int i = pOp->p1;
  int tos = ++p->tos;
  BtCursor *pCrsr;


  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
    int v;
    if( p->aCsr[i].recnoIsValid ){
      v = p->aCsr[i].lastRecno;
    }else if( p->aCsr[i].nullRow ){
      aStack[tos].flags = STK_Null;
      break;


    }else{

      sqliteBtreeKey(pCrsr, 0, sizeof(u32), (char*)&v);
      v = keyToInt(v);
    }
    aStack[tos].i = v;
    aStack[tos].flags = STK_Int;
  }
  break;
}

/* Opcode: FullKey P1 * *
**
** Extract the complete key from the record that cursor P1 is currently
** pointing to and push the key onto the stack as a string.
**
** Compare this opcode to Recno.  The Recno opcode extracts the first
** 4 bytes of the key and pushes those bytes onto the stack as an
** integer.  This instruction pushes the entire key as a string.


*/
case OP_FullKey: {
  int i = pOp->p1;
  int tos = ++p->tos;
  BtCursor *pCrsr;

  VERIFY( if( !p->aCsr[i].keyAsData ) goto bad_instruction; )

  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
    int amt;
    char *z;

    sqliteBtreeKeySize(pCrsr, &amt);
    if( amt<=0 ){
      rc = SQLITE_CORRUPT;
................................................................................
**
** Move the cursor P1 to a null row.  Any OP_Column operations
** that occur while the cursor is on the null row will always push 
** a NULL onto the stack.
*/
case OP_NullRow: {
  int i = pOp->p1;
  BtCursor *pCrsr;

  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
    p->aCsr[i].nullRow = 1;
    p->aCsr[i].recnoIsValid = 0;
  }
  break;
}

/* Opcode: Last P1 P2 *
**
** The next use of the Recno or Column or Next instruction for P1 
** will refer to the last entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
case OP_Last: {
  int i = pOp->p1;

  BtCursor *pCrsr;

  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){


    int res;
    sqliteBtreeLast(pCrsr, &res);
    p->aCsr[i].nullRow = res;
    if( res && pOp->p2>0 ){
      pc = pOp->p2 - 1;
    }


  }
  break;
}

/* Opcode: Rewind P1 P2 *
**
** The next use of the Recno or Column or Next instruction for P1 
................................................................................
** will refer to the first entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
case OP_Rewind: {
  int i = pOp->p1;

  BtCursor *pCrsr;

  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){


    int res;
    sqliteBtreeFirst(pCrsr, &res);
    p->aCsr[i].atFirst = res==0;
    p->aCsr[i].nullRow = res;
    if( res && pOp->p2>0 ){
      pc = pOp->p2 - 1;
    }


  }
  break;
}

/* Opcode: Next P1 P2 *
**
** Advance cursor P1 so that it points to the next key/data pair in its
................................................................................
*/
case OP_Prev:
case OP_Next: {
  Cursor *pC;
  BtCursor *pCrsr;

  CHECK_FOR_INTERRUPT;
  if( VERIFY( pOp->p1>=0 && pOp->p1<p->nCursor && ) 
      (pCrsr = (pC = &p->aCsr[pOp->p1])->pCursor)!=0 ){

    int res;
    if( pC->nullRow ){
      res = 1;
    }else{
      rc = pOp->opcode==OP_Next ? sqliteBtreeNext(pCrsr, &res) :
                                  sqliteBtreePrevious(pCrsr, &res);
      pC->nullRow = res;
    }
    if( res==0 ){
      pc = pOp->p2 - 1;
      sqlite_search_count++;
    }
    pC->recnoIsValid = 0;

  }

  break;
}

/* Opcode: IdxPut P1 P2 P3
**
** The top of the stack hold an SQL index key made using the
** MakeIdxKey instruction.  This opcode writes that key into the







|







 







>
>
>
>
>











>

>
>
>







 







>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







|
>
>







 







>
>








|
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
>







 







>
>




|
>
>







 







|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>





|









>
>
>
>







 







|
>

|
<
|
|
|
|
|
>
>
|
>
|
|
|
|
|
<











>
>







>







 







<

|
|
|
<













>


|
>
>






>
>







 







>


|
>
>


|
|



>
>







 







|
|
>












|
>

>







32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
..
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
....
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
....
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
....
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
....
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
....
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
....
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
....
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
....
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
....
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
....
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263

4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277

4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
....
4324
4325
4326
4327
4328
4329
4330

4331
4332
4333
4334

4335
4336
4337
4338
4339
4340
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
....
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
4392
4393
4394
4395
4396
4397
....
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
4428
4429
4430
4431
4432
4433
4434
4435
4436
4437
4438
4439
4440
4441
4442
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** 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.215 2003/04/15 19:22:24 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The makefile scans this source file and creates the following
** array of string constants which are the names of all VDBE opcodes.
................................................................................
** The cursor can seek to a BTree entry with a particular key, or
** loop over all entries of the Btree.  You can also insert new BTree
** entries or retrieve the key or data from the entry that the cursor
** is currently pointing to.
** 
** Every cursor that the virtual machine has open is represented by an
** instance of the following structure.
**
** If the Cursor.isTriggerRow flag is set it means that this cursor is
** really a single row that represents the NEW or OLD pseudo-table of
** a row trigger.  The data for the row is stored in Cursor.pData and
** the rowid is in Cursor.iKey.
*/
struct Cursor {
  BtCursor *pCursor;    /* The cursor structure of the backend */
  int lastRecno;        /* Last recno from a Next or NextIdx operation */
  int nextRowid;        /* Next rowid returned by OP_NewRowid */
  Bool recnoIsValid;    /* True if lastRecno is valid */
  Bool keyAsData;       /* The OP_Column command works on key instead of data */
  Bool atFirst;         /* True if pointing to first entry */
  Bool useRandomRowid;  /* Generate new record numbers semi-randomly */
  Bool nullRow;         /* True if pointing to a row with no data */
  Bool nextRowidValid;  /* True if the nextRowid field is valid */
  Bool pseudoTable;     /* This is a NEW or OLD pseudo-tables of a trigger */
  Btree *pBt;           /* Separate file holding temporary table */
  int nData;            /* Number of bytes in pData */
  char *pData;          /* Data for a NEW or OLD pseudo-table */
  int iKey;             /* Key for the NEW or OLD pseudo-table row */
};
typedef struct Cursor Cursor;

/*
** A sorter builds a list of elements to be sorted.  Each element of
** the list is an instance of the following structure.
*/
................................................................................
static void cleanupCursor(Cursor *pCx){
  if( pCx->pCursor ){
    sqliteBtreeCloseCursor(pCx->pCursor);
  }
  if( pCx->pBt ){
    sqliteBtreeClose(pCx->pBt);
  }
  sqliteFree(pCx->pData);
  memset(pCx, 0, sizeof(Cursor));
}

/*
** Close all cursors
*/
static void closeAllCursors(Vdbe *p){
................................................................................
      }
    }else{
      rc = sqliteBtreeCursor(pCx->pBt, 2, 1, &pCx->pCursor);
    }
  }
  break;
}

/* Opcode: OpenPseudo P1 * *
**
** Open a new cursor that points to a fake table that contains a single
** row of data.  Any attempt to write a second row of data causes the
** first row to be deleted.  All data is deleted when the cursor is
** closed.
**
** A pseudo-table created by this opcode is useful for holding the
** NEW or OLD tables in a trigger.
*/
case OP_OpenPseudo: {
  int i = pOp->p1;
  Cursor *pCx;
  VERIFY( if( i<0 ) goto bad_instruction; )
  if( expandCursorArraySize(p, i) ) goto no_mem;
  pCx = &p->aCsr[i];
  cleanupCursor(pCx);
  memset(pCx, 0, sizeof(*pCx));
  pCx->nullRow = 1;
  pCx->pseudoTable = 1;
  break;
}

/*
** Opcode: RenameCursor P1 P2 *
**
** Rename cursor number P1 as cursor number P2.  If P2 was previously
** opened is is closed before the renaming occurs.
*/
................................................................................
/* Opcode: Close P1 * *
**
** Close a cursor previously opened as P1.  If P1 is not
** currently open, this instruction is a no-op.
*/
case OP_Close: {
  int i = pOp->p1;
  if( i>=0 && i<p->nCursor ){
    cleanupCursor(&p->aCsr[i]);
  }
  break;
}

/* Opcode: MoveTo P1 P2 *
**
................................................................................
case OP_MoveLt:
case OP_MoveTo: {
  int i = pOp->p1;
  int tos = p->tos;
  Cursor *pC;

  VERIFY( if( tos<0 ) goto not_enough_stack; )
  assert( i>=0 && i<p->nCursor );
  pC = &p->aCsr[i];
  if( pC->pCursor!=0 ){
    int res, oc;
    if( aStack[tos].flags & STK_Int ){
      int iKey = intToKey(aStack[tos].i);
      sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res);
      pC->lastRecno = aStack[tos].i;
      pC->recnoIsValid = res==0;
    }else{
................................................................................
/* Opcode: PutStrKey P1 * *
**
** Write an entry into the database file P1.  A new entry is
** created if it doesn't already exist or the data for an existing
** entry is overwritten.  The data is the value on the top of the
** stack.  The key is the next value down on the stack.  The key must
** be a string.  The stack is popped twice by this instruction.
**
** P1 may not be a pseudo-table opened using the OpenPseudo opcode.
*/
case OP_PutIntKey:
case OP_PutStrKey: {
  int tos = p->tos;
  int nos = p->tos-1;
  int i = pOp->p1;
  Cursor *pC;
  VERIFY( if( nos<0 ) goto not_enough_stack; )
  if( VERIFY( i>=0 && i<p->nCursor && )
      ((pC = &p->aCsr[i])->pCursor!=0 || pC->pseudoTable) ){
    char *zKey;
    int nKey, iKey;
    if( pOp->opcode==OP_PutStrKey ){
      Stringify(p, nos);
      nKey = aStack[nos].n;
      zKey = zStack[nos];
    }else{
................................................................................
        db->nChange++;
        db->lastRowid = aStack[nos].i;
      }
      if( pC->nextRowidValid && aStack[nos].i>=pC->nextRowid ){
        pC->nextRowidValid = 0;
      }
    }
    if( pC->pseudoTable ){
      /* PutStrKey does not work for pseudo-tables.
      ** The following assert makes sure we are not trying to use
      ** PutStrKey on a pseudo-table
      */
      assert( pOp->opcode==OP_PutIntKey );
      sqliteFree(pC->pData);
      pC->iKey = iKey;
      pC->nData = aStack[tos].n;
      if( aStack[tos].flags & STK_Dyn ){
        pC->pData = zStack[tos];
        zStack[tos] = 0;
        aStack[tos].flags = STK_Null;
      }else{
        pC->pData = sqliteMallocRaw( pC->nData );
        if( pC->pData ){
          memcpy(pC->pData, zStack[tos], pC->nData);
        }
      }
      pC->nullRow = 0;
    }else{
      rc = sqliteBtreeInsert(pC->pCursor, zKey, nKey,
                          zStack[tos], aStack[tos].n);
    }
    pC->recnoIsValid = 0;
  }
  POPSTACK;
  POPSTACK;
  break;
}

................................................................................
** The cursor will be left pointing at either the next or the previous
** record in the table. If it is left pointing at the next record, then
** the next Next instruction will be a no-op.  Hence it is OK to delete
** a record from within an Next loop.
**
** The row change counter is incremented if P2==1 and is unmodified
** if P2==0.
**
** If P1 is a pseudo-table, then this instruction is a no-op.
*/
case OP_Delete: {
  int i = pOp->p1;
  Cursor *pC;
  assert( i>=0 && i<p->nCursor );
  pC = &p->aCsr[i];
  if( pC->pCursor!=0 ){
    rc = sqliteBtreeDelete(pC->pCursor);
    pC->nextRowidValid = 0;
  }
  if( pOp->p2 ) db->nChange++;
  break;
}

................................................................................
** Turn the key-as-data mode for cursor P1 either on (if P2==1) or
** off (if P2==0).  In key-as-data mode, the Field opcode pulls
** data off of the key rather than the data.  This is useful for
** processing compound selects.
*/
case OP_KeyAsData: {
  int i = pOp->p1;
  assert( i>=0 && i<p->nCursor );
  p->aCsr[i].keyAsData = pOp->p2;
  break;
}

/* Opcode: RowData P1 * *
**
** Push onto the stack the complete row data for cursor P1.
** There is no interpretation of the data.  It is just copied
** onto the stack exactly as it is found in the database file.
**
** If the cursor is not pointing to a valid row, a NULL is pushed
** onto the stack.
*/
case OP_RowData: {
  int i = pOp->p1;
  int tos = ++p->tos;
  Cursor *pC;
  int n;

  assert( i>=0 && i<p->nCursor );
  pC = &p->aCsr[i];
  if( pC->nullRow ){
    aStack[tos].flags = STK_Null;
  }else if( pC->pCursor!=0 ){
    BtCursor *pCrsr = pC->pCursor;
    if( pC->nullRow ){
      aStack[tos].flags = STK_Null;
      break;
    }else if( pC->keyAsData ){
      sqliteBtreeKeySize(pCrsr, &n);
    }else{
      sqliteBtreeDataSize(pCrsr, &n);
    }
    aStack[tos].n = n;
    if( n<=NBFS ){
      aStack[tos].flags = STK_Str;
      zStack[tos] = aStack[tos].z;
    }else{
      char *z = sqliteMallocRaw( n );
      if( z==0 ) goto no_mem;
      aStack[tos].flags = STK_Str | STK_Dyn;
      zStack[tos] = z;
    }
    if( pC->keyAsData ){
      sqliteBtreeKey(pCrsr, 0, n, zStack[tos]);
    }else{
      sqliteBtreeData(pCrsr, 0, n, zStack[tos]);
    }
  }else if( pC->pseudoTable ){
    aStack[tos].n = pC->nData;
    zStack[tos] = pC->pData;
    aStack[tos].flags = STK_Str|STK_Ephem;
  }else{
    aStack[tos].flags = STK_Null;
  }
  break;
}

/* Opcode: Column P1 P2 *
**
** Interpret the data that cursor P1 points to as
................................................................................
  int tos = p->tos+1;
  Cursor *pC;
  char *zRec;
  BtCursor *pCrsr;
  int idxWidth;
  unsigned char aHdr[10];

  assert( i<p->nCursor );
  if( i<0 ){
    VERIFY( if( tos+i<0 ) goto bad_instruction; )
    VERIFY( if( (aStack[tos+i].flags & STK_Str)==0 ) goto bad_instruction; )
    zRec = zStack[tos+i];
    payloadSize = aStack[tos+i].n;
  }else if( (pC = &p->aCsr[i])->pCursor!=0 ){
    zRec = 0;
    pCrsr = pC->pCursor;
    if( pC->nullRow ){
      payloadSize = 0;
    }else if( pC->keyAsData ){
      sqliteBtreeKeySize(pCrsr, &payloadSize);
    }else{
      sqliteBtreeDataSize(pCrsr, &payloadSize);
    }
  }else if( pC->pseudoTable ){
    payloadSize = pC->nData;
    zRec = pC->pData;
    assert( payloadSize==0 || zRec!=0 );
  }else{
    payloadSize = 0;
  }

  /* Figure out how many bytes in the column data and where the column
  ** data begins.
  */
................................................................................
** the key to the current entry in a sequential scan of the database
** file P1.  The sequential scan should have been started using the 
** Next opcode.
*/
case OP_Recno: {
  int i = pOp->p1;
  int tos = ++p->tos;
  Cursor *pC;
  int v;

  assert( i>=0 && i<p->nCursor );

  if( (pC = &p->aCsr[i])->recnoIsValid ){
    v = pC->lastRecno;
  }else if( pC->nullRow ){
    aStack[tos].flags = STK_Null;
    break;
  }else if( pC->pseudoTable ){
    v = keyToInt(pC->iKey);
  }else{
    assert( pC->pCursor!=0 );
    sqliteBtreeKey(pC->pCursor, 0, sizeof(u32), (char*)&v);
    v = keyToInt(v);
  }
  aStack[tos].i = v;
  aStack[tos].flags = STK_Int;

  break;
}

/* Opcode: FullKey P1 * *
**
** Extract the complete key from the record that cursor P1 is currently
** pointing to and push the key onto the stack as a string.
**
** Compare this opcode to Recno.  The Recno opcode extracts the first
** 4 bytes of the key and pushes those bytes onto the stack as an
** integer.  This instruction pushes the entire key as a string.
**
** This opcode may not be used on a pseudo-table.
*/
case OP_FullKey: {
  int i = pOp->p1;
  int tos = ++p->tos;
  BtCursor *pCrsr;

  VERIFY( if( !p->aCsr[i].keyAsData ) goto bad_instruction; )
  VERIFY( if( p->aCsr[i].pseudoTable ) goto bad_instruction; )
  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
    int amt;
    char *z;

    sqliteBtreeKeySize(pCrsr, &amt);
    if( amt<=0 ){
      rc = SQLITE_CORRUPT;
................................................................................
**
** Move the cursor P1 to a null row.  Any OP_Column operations
** that occur while the cursor is on the null row will always push 
** a NULL onto the stack.
*/
case OP_NullRow: {
  int i = pOp->p1;


  assert( i>=0 && i<p->nCursor );
  p->aCsr[i].nullRow = 1;
  p->aCsr[i].recnoIsValid = 0;

  break;
}

/* Opcode: Last P1 P2 *
**
** The next use of the Recno or Column or Next instruction for P1 
** will refer to the last entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
case OP_Last: {
  int i = pOp->p1;
  Cursor *pC;
  BtCursor *pCrsr;

  assert( i>=0 && i<p->nCursor );
  pC = &p->aCsr[i];
  if( (pCrsr = pC->pCursor)!=0 ){
    int res;
    sqliteBtreeLast(pCrsr, &res);
    p->aCsr[i].nullRow = res;
    if( res && pOp->p2>0 ){
      pc = pOp->p2 - 1;
    }
  }else{
    pC->nullRow = 0;
  }
  break;
}

/* Opcode: Rewind P1 P2 *
**
** The next use of the Recno or Column or Next instruction for P1 
................................................................................
** will refer to the first entry in the database table or index.
** If the table or index is empty and P2>0, then jump immediately to P2.
** If P2 is 0 or if the table or index is not empty, fall through
** to the following instruction.
*/
case OP_Rewind: {
  int i = pOp->p1;
  Cursor *pC;
  BtCursor *pCrsr;

  assert( i>=0 && i<p->nCursor );
  pC = &p->aCsr[i];
  if( (pCrsr = pC->pCursor)!=0 ){
    int res;
    sqliteBtreeFirst(pCrsr, &res);
    pC->atFirst = res==0;
    pC->nullRow = res;
    if( res && pOp->p2>0 ){
      pc = pOp->p2 - 1;
    }
  }else{
    pC->nullRow = 0;
  }
  break;
}

/* Opcode: Next P1 P2 *
**
** Advance cursor P1 so that it points to the next key/data pair in its
................................................................................
*/
case OP_Prev:
case OP_Next: {
  Cursor *pC;
  BtCursor *pCrsr;

  CHECK_FOR_INTERRUPT;
  assert( pOp->p1>=0 && pOp->p1<p->nCursor );
  pC = &p->aCsr[pOp->p1];
  if( (pCrsr = pC->pCursor)!=0 ){
    int res;
    if( pC->nullRow ){
      res = 1;
    }else{
      rc = pOp->opcode==OP_Next ? sqliteBtreeNext(pCrsr, &res) :
                                  sqliteBtreePrevious(pCrsr, &res);
      pC->nullRow = res;
    }
    if( res==0 ){
      pc = pOp->p2 - 1;
      sqlite_search_count++;
    }
  }else{
    pC->nullRow = 1;
  }
  pC->recnoIsValid = 0;
  break;
}

/* Opcode: IdxPut P1 P2 P3
**
** The top of the stack hold an SQL index key made using the
** MakeIdxKey instruction.  This opcode writes that key into the

Changes to test/rowid.test.

8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
399
400
401
402
403
404
405
406
407
408
409
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the magic ROWID column that is
# found on all tables.
#
# $Id: rowid.test,v 1.9 2003/04/15 14:01:44 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Basic ROWID functionality tests.
#
do_test rowid-1.1 {
................................................................................
    SELECT * FROM t3;
  }
} {123 124}
do_test rowid-8.8 {
  execsql {
    SELECT rowid, * FROM t4;
  }
} {1 1 2 133 3 {}}


finish_test







|







 







|



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
399
400
401
402
403
404
405
406
407
408
409
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing the magic ROWID column that is
# found on all tables.
#
# $Id: rowid.test,v 1.10 2003/04/15 19:22:24 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Basic ROWID functionality tests.
#
do_test rowid-1.1 {
................................................................................
    SELECT * FROM t3;
  }
} {123 124}
do_test rowid-8.8 {
  execsql {
    SELECT rowid, * FROM t4;
  }
} {1 1 2 133 3 134}


finish_test