SQLite

Check-in [c0730217a0]
Login

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

Overview
Comment:Changes to the DBBE. Moving toward having many more backend driver choices. (CVS 176)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: c0730217a04323a1a73d125e3e7da32bcc8d58fc
User & Date: drh 2001-01-13 14:34:06.000
Context
2001-01-15
22:51
continued progress toward version 2.0 (CVS 177) (check-in: c6ffb7ec6a user: drh tags: trunk)
2001-01-13
14:34
Changes to the DBBE. Moving toward having many more backend driver choices. (CVS 176) (check-in: c0730217a0 user: drh tags: trunk)
2001-01-04
14:30
Version 1.0.18 (CVS 485) (check-in: 46b86abb1c user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to Makefile.in.
44
45
46
47
48
49
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
# The library that programs using readline() must link against.
#
LIBREADLINE = @TARGET_READLINE_LIBS@

# Object files for the SQLite library.
#
LIBOBJ = build.o dbbe.o dbbegdbm.o dbbemem.o delete.o expr.o insert.o \
         main.o parse.o printf.o select.o table.o tokenize.o update.o \
         util.o vdbe.o where.o tclsqlite.o

# All of the source code files.
#
SRC = \
  $(TOP)/src/build.c \
  $(TOP)/src/dbbe.c \
  $(TOP)/src/dbbegdbm.c \
  $(TOP)/src/dbbemem.c \
  $(TOP)/src/dbbe.h \
  $(TOP)/src/dbbemem.c \
  $(TOP)/src/delete.c \
  $(TOP)/src/expr.c \
  $(TOP)/src/insert.c \
  $(TOP)/src/main.c \
  $(TOP)/src/parse.y \
  $(TOP)/src/printf.c \

  $(TOP)/src/select.c \
  $(TOP)/src/shell.c \
  $(TOP)/src/sqlite.h.in \
  $(TOP)/src/sqliteInt.h \
  $(TOP)/src/table.c \
  $(TOP)/src/tclsqlite.c \
  $(TOP)/src/tokenize.c \







|
|
















>







44
45
46
47
48
49
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
# The library that programs using readline() must link against.
#
LIBREADLINE = @TARGET_READLINE_LIBS@

# Object files for the SQLite library.
#
LIBOBJ = build.o dbbe.o dbbegdbm.o dbbemem.o delete.o expr.o insert.o \
         main.o parse.o printf.o random.o select.o table.o tokenize.o \
         update.o util.o vdbe.o where.o tclsqlite.o

# All of the source code files.
#
SRC = \
  $(TOP)/src/build.c \
  $(TOP)/src/dbbe.c \
  $(TOP)/src/dbbegdbm.c \
  $(TOP)/src/dbbemem.c \
  $(TOP)/src/dbbe.h \
  $(TOP)/src/dbbemem.c \
  $(TOP)/src/delete.c \
  $(TOP)/src/expr.c \
  $(TOP)/src/insert.c \
  $(TOP)/src/main.c \
  $(TOP)/src/parse.y \
  $(TOP)/src/printf.c \
  $(TOP)/src/random.c \
  $(TOP)/src/select.c \
  $(TOP)/src/shell.c \
  $(TOP)/src/sqlite.h.in \
  $(TOP)/src/sqliteInt.h \
  $(TOP)/src/table.c \
  $(TOP)/src/tclsqlite.c \
  $(TOP)/src/tokenize.c \
158
159
160
161
162
163
164



165
166
167
168
169
170
171

expr.o:	$(TOP)/src/expr.c $(HDR)
	$(TCC) $(GDBM_FLAGS) -c $(TOP)/src/expr.c

insert.o:	$(TOP)/src/insert.c $(HDR)
	$(TCC) $(GDBM_FLAGS) -c $(TOP)/src/insert.c




select.o:	$(TOP)/src/select.c $(HDR)
	$(TCC) $(GDBM_FLAGS) -c $(TOP)/src/select.c

table.o:	$(TOP)/src/table.c $(HDR)
	$(TCC) $(GDBM_FLAGS) -c $(TOP)/src/table.c

update.o:	$(TOP)/src/update.c $(HDR)







>
>
>







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175

expr.o:	$(TOP)/src/expr.c $(HDR)
	$(TCC) $(GDBM_FLAGS) -c $(TOP)/src/expr.c

insert.o:	$(TOP)/src/insert.c $(HDR)
	$(TCC) $(GDBM_FLAGS) -c $(TOP)/src/insert.c

random.o:	$(TOP)/src/random.c $(HDR)
	$(TCC) $(GDBM_FLAGS) -c $(TOP)/src/random.c

select.o:	$(TOP)/src/select.c $(HDR)
	$(TCC) $(GDBM_FLAGS) -c $(TOP)/src/select.c

table.o:	$(TOP)/src/table.c $(HDR)
	$(TCC) $(GDBM_FLAGS) -c $(TOP)/src/table.c

update.o:	$(TOP)/src/update.c $(HDR)
Changes to VERSION.
1
1.0.18
|
1
1.1.0
Changes to src/dbbe.c.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses GDBM as the database backend.  It should be
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbe.c,v 1.21 2000/10/19 14:10:09 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine opens a new database.  It looks at the first
** few characters of the database name to try to determine what
** kind of database to open.  If the first characters are "gdbm:",







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses GDBM as the database backend.  It should be
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbe.c,v 1.22 2001/01/13 14:34:06 drh Exp $
*/
#include "sqliteInt.h"

/*
** This routine opens a new database.  It looks at the first
** few characters of the database name to try to determine what
** kind of database to open.  If the first characters are "gdbm:",
58
59
60
61
62
63
64























































































  }
  if( strncmp(zName, "memory:", 7)==0 ){
    extern Dbbe *sqliteMemOpen(const char*,int,int,char**);
    return sqliteMemOpen(&zName[7], writeFlag, createFlag, pzErrMsg);
  }
  return sqliteGdbmOpen(zName, writeFlag, createFlag, pzErrMsg);
}






























































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
  }
  if( strncmp(zName, "memory:", 7)==0 ){
    extern Dbbe *sqliteMemOpen(const char*,int,int,char**);
    return sqliteMemOpen(&zName[7], writeFlag, createFlag, pzErrMsg);
  }
  return sqliteGdbmOpen(zName, writeFlag, createFlag, pzErrMsg);
}

/*
** Open a temporary file.  The file should be deleted when closed.
**
** Note that we can't use the old Unix trick of opening the file
** and then immediately unlinking the file.  That works great
** under Unix, but fails when we try to port to Windows.
*/
int sqliteDbbeOpenTempFile(Dbbe *pBe, FILE **ppFile){
  char *zFile;         /* Full name of the temporary file */
  char zBuf[50];       /* Base name of the temporary file */
  int i;               /* Loop counter */
  int limit;           /* Prevent an infinite loop */
  int rc = SQLITE_OK;  /* Value returned by this function */
  char *zDir;          /* Directory to hold the file */

  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]==0 ) break;
  }
  if( i>=pBe->nTemp ){
    pBe->nTemp++;
    pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) );
    pBe->azTemp = sqliteRealloc(pBe->azTemp, pBe->nTemp*sizeof(char*) );
  }
  if( pBe->apTemp==0 ){
    *ppFile = 0;
    return SQLITE_NOMEM;
  }
  limit = 4;
  zFile = 0;
  zDir = pBe->zDir;
  if( zDir==0 ){
    zDir = "./";
  }
  do{
    sqliteRandomName(zBuf, "/_temp_file_");
    sqliteFree(zFile);
    zFile = 0;
    sqliteSetString(&zFile, zDir, zBuf, 0);
  }while( access(zFile,0)==0 && limit-- >= 0 );
  *ppFile = pBe->apTemp[i] = fopen(zFile, "w+");
  if( pBe->apTemp[i]==0 ){
    rc = SQLITE_ERROR;
    sqliteFree(zFile);
    pBe->azTemp[i] = 0;
  }else{
    pBe->azTemp[i] = zFile;
  }
  return rc;
}

/*
** Close a temporary file opened using sqliteGdbmOpenTempFile()
*/
void sqliteDbbeCloseTempFile(Dbbe *pBe, FILE *f){
  int i;
  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]==f ){
      unlink(pBe->azTemp[i]);
      sqliteFree(pBe->azTemp[i]);
      pBe->apTemp[i] = 0;
      pBe->azTemp[i] = 0;
      break;
    }
  }
  fclose(f);
}

/*
** Close all temporary files that happen to still be open.
** This routine is called when the database is being closed.
*/
void sqliteDbbeCloseAllTempFiles(Dbbe *pBe){
  int i;
  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]!=0 ){
      unlink(pBe->azTemp[i]);
      fclose(pBe->apTemp[i]);
      sqliteFree(pBe->azTemp[i]);
      pBe->apTemp[i] = 0;
      pBe->azTemp[i] = 0;
      break;
    }
  }
  sqliteFree(pBe->azTemp);
  sqliteFree(pBe->apTemp);
}
Changes to src/dbbe.h.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
** This file defines the interface to the database backend (Dbbe).
**
** The database backend is designed to be as general as possible
** so that it can easily be replaced by a different backend.
** This library was originally designed to support the following
** backends: GDBM, NDBM, SDBM, Berkeley DB.
**
** $Id: dbbe.h,v 1.8 2000/10/19 01:49:02 drh Exp $
*/
#ifndef _SQLITE_DBBE_H_
#define _SQLITE_DBBE_H_
#include <stdio.h>

/*
** The database backend supports two opaque structures.  A Dbbe is







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
** This file defines the interface to the database backend (Dbbe).
**
** The database backend is designed to be as general as possible
** so that it can easily be replaced by a different backend.
** This library was originally designed to support the following
** backends: GDBM, NDBM, SDBM, Berkeley DB.
**
** $Id: dbbe.h,v 1.9 2001/01/13 14:34:06 drh Exp $
*/
#ifndef _SQLITE_DBBE_H_
#define _SQLITE_DBBE_H_
#include <stdio.h>

/*
** The database backend supports two opaque structures.  A Dbbe is
49
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
78
** The DbbeCursor structure holds some state information, such as
** the key and data from the last retrieval.  For this reason, 
** the backend must allow the creation of multiple independent
** DbbeCursor structures for each table in the database.
*/
typedef struct Dbbe Dbbe;
typedef struct DbbeCursor DbbeCursor;


/*
** Open a complete database.
**
** If the database name begins with "gdbm:" the GDBM driver is used.
** If the name begins with "memory:" the in-memory driver is used.
** The default driver is GDBM.
*/
Dbbe *sqliteDbbeOpen(const char *zName, int write, int create, char **pzErr);

/*
** This is the structure returned by sqliteDbbeOpen().  It contains pointers
** to all access routines for the database backend.



*/
struct Dbbe {
  /* Close the whole database. */
  void (*Close)(Dbbe*);

  /* Open a cursor into particular file of a previously opened database.
  ** Create the file if it doesn't already exist and writeable!=0.  zName
  ** is the base name of the file to be opened.  This routine will add
  ** an appropriate path and extension to the filename to locate the 







|











|
|
>
>
>

|







49
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
78
79
80
81
** The DbbeCursor structure holds some state information, such as
** the key and data from the last retrieval.  For this reason, 
** the backend must allow the creation of multiple independent
** DbbeCursor structures for each table in the database.
*/
typedef struct Dbbe Dbbe;
typedef struct DbbeCursor DbbeCursor;
typedef struct DbbeMethods DbbeMethods;

/*
** Open a complete database.
**
** If the database name begins with "gdbm:" the GDBM driver is used.
** If the name begins with "memory:" the in-memory driver is used.
** The default driver is GDBM.
*/
Dbbe *sqliteDbbeOpen(const char *zName, int write, int create, char **pzErr);

/*
** Each of the various SQLite backends defines a set of methods for
** accessing the database.  Pointers to the methods are contained in
** an instance of the following structure.  A pointer to a static instance
** of this structure is assigned to the Dbbe structure that sqlileDbbeOpen
** returns.
*/
struct DbbeMethods {
  /* Close the whole database. */
  void (*Close)(Dbbe*);

  /* Open a cursor into particular file of a previously opened database.
  ** Create the file if it doesn't already exist and writeable!=0.  zName
  ** is the base name of the file to be opened.  This routine will add
  ** an appropriate path and extension to the filename to locate the 
144
145
146
147
148
149
150
151


















152

  /* Open a file suitable for temporary storage */
  int (*OpenTempFile)(Dbbe*, FILE**);

  /* Close a temporary file */
  void (*CloseTempFile)(Dbbe *, FILE *);
};



















#endif /* defined(_SQLITE_DBBE_H_) */








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

147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

  /* Open a file suitable for temporary storage */
  int (*OpenTempFile)(Dbbe*, FILE**);

  /* Close a temporary file */
  void (*CloseTempFile)(Dbbe *, FILE *);
};

/*
** This is the structure returned by sqliteDbbeOpen().  It contains
** information common to all the different backend drivers.
**
** The information in this structure (with the exception the method
** pointers in the Dbbe.x field) is intended to be visible to
** the backend drivers only.  Users should not access or modify
** this structure in any way other than the read the method pointers
** in Dbbe.x.
*/
struct Dbbe {
  struct DbbeMethods *x; /* Backend-specific methods for database access */
  char *zDir;            /* The directory containing the database file(s) */
  int nTemp;             /* Number of temporary files created */
  FILE **apTemp;         /* Space to hold temporary file pointers */
  char **azTemp;         /* Names of the temporary files */
};

#endif /* defined(_SQLITE_DBBE_H_) */
Changes to src/dbbegdbm.c.
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses GDBM as the database backend.  It should be
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbegdbm.c,v 1.1 2000/10/19 01:49:02 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses GDBM as the database backend.  It should be
** relatively simple to convert to a different database such
** as NDBM, SDBM, or BerkeleyDB.
**
** $Id: dbbegdbm.c,v 1.2 2001/01/13 14:34:06 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
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
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

141
142
143
144
145
146
147
148
149
  GDBM_FILE dbf;          /* The file itself */
  int nRef;               /* Number of references */
  int delOnClose;         /* Delete when closing */
  int writeable;          /* Opened for writing */
  BeFile *pNext, *pPrev;  /* Next and previous on list of open files */
};

/*
** The following structure holds the current state of the RC4 algorithm.
** We use RC4 as a random number generator.  Each call to RC4 gives
** a random 8-bit number.
**
** Nothing in this file or anywhere else in SQLite does any kind of
** encryption.  The RC4 algorithm is being used as a PRNG (pseudo-random
** number generator) not as an encryption device.
*/
struct rc4 {
  int i, j;
  int s[256];
};

/*
** The following structure contains all information used by GDBM
** database driver.  This is a subclass of the Dbbe structure.
*/
typedef struct Dbbex Dbbex;
struct Dbbex {
  Dbbe dbbe;         /* The base class */
  char *zDir;        /* The directory containing the database */
  int write;         /* True for write permission */
  BeFile *pOpen;     /* List of open files */
  int nTemp;         /* Number of temporary files created */
  FILE **apTemp;     /* Space to hold temporary file pointers */
  char **azTemp;     /* Names of the temporary files */
  struct rc4 rc4;    /* The random number generator */
};

/*
** An cursor into a database file is an instance of the following structure.
** There can only be a single BeFile structure for each disk file, but
** there can be multiple DbbeCursor structures.  Each DbbeCursor represents
** a cursor pointing to a particular part of the open BeFile.  The
** BeFile.nRef field hold a count of the number of DbbeCursor structures
** associated with the same disk file.
*/
struct DbbeCursor {
  Dbbex *pBe;        /* The database of which this record is a part */
  BeFile *pFile;     /* The database file for this table */
  datum key;         /* Most recently used key */
  datum data;        /* Most recent data */
  int needRewind;    /* Next key should be the first */
  int readPending;   /* The fetch hasn't actually been done yet */
};

/*
** Initialize the RC4 PRNG.  "seed" is a pointer to some random
** data used to initialize the PRNG.  
*/
static void rc4init(struct rc4 *p, char *seed, int seedlen){
  int i;
  char k[256];
  p->j = 0;
  p->i = 0;
  for(i=0; i<256; i++){
    p->s[i] = i;
    k[i] = seed[i%seedlen];
  }
  for(i=0; i<256; i++){
    int t;
    p->j = (p->j + p->s[i] + k[i]) & 0xff;
    t = p->s[p->j];
    p->s[p->j] = p->s[i];
    p->s[i] = t;
  }
}

/*
** Get a single 8-bit random value from the RC4 PRNG.
*/
static int rc4byte(struct rc4 *p){
  int t;
  p->i = (p->i + 1) & 0xff;
  p->j = (p->j + p->s[p->i]) & 0xff;
  t = p->s[p->i];
  p->s[p->i] = p->s[p->j];
  p->s[p->j] = t;
  t = p->s[p->i] + p->s[p->j];
  return t & 0xff;

}

/*
** The "mkdir()" function only takes one argument under Windows.
*/
#if OS_WIN
# define mkdir(A,B) mkdir(A)
#endif








<
<
<
<
<
<
<
<
<
<
<
<
<
<







<


<
<
<
<




















<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<

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







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
78
79
80
81
82
83
84
85
86
87
88


89




















90
91
92







93
94

95
96
97
98
99
100
101
  GDBM_FILE dbf;          /* The file itself */
  int nRef;               /* Number of references */
  int delOnClose;         /* Delete when closing */
  int writeable;          /* Opened for writing */
  BeFile *pNext, *pPrev;  /* Next and previous on list of open files */
};















/*
** The following structure contains all information used by GDBM
** database driver.  This is a subclass of the Dbbe structure.
*/
typedef struct Dbbex Dbbex;
struct Dbbex {
  Dbbe dbbe;         /* The base class */

  int write;         /* True for write permission */
  BeFile *pOpen;     /* List of open files */




};

/*
** An cursor into a database file is an instance of the following structure.
** There can only be a single BeFile structure for each disk file, but
** there can be multiple DbbeCursor structures.  Each DbbeCursor represents
** a cursor pointing to a particular part of the open BeFile.  The
** BeFile.nRef field hold a count of the number of DbbeCursor structures
** associated with the same disk file.
*/
struct DbbeCursor {
  Dbbex *pBe;        /* The database of which this record is a part */
  BeFile *pFile;     /* The database file for this table */
  datum key;         /* Most recently used key */
  datum data;        /* Most recent data */
  int needRewind;    /* Next key should be the first */
  int readPending;   /* The fetch hasn't actually been done yet */
};

/*


**




















*/
struct DbbeList {
  FILE *pOut;







  Dbbe *pDbbe;
};

/*
** The "mkdir()" function only takes one argument under Windows.
*/
#if OS_WIN
# define mkdir(A,B) mkdir(A)
#endif

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
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
  int i;
  for(pFile=pBe->pOpen; pFile; pFile=pNext){
    pNext = pFile->pNext;
    gdbm_close(pFile->dbf);
    memset(pFile, 0, sizeof(*pFile));   
    sqliteFree(pFile);
  }
  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]!=0 ){
      unlink(pBe->azTemp[i]);
      fclose(pBe->apTemp[i]);
      sqliteFree(pBe->azTemp[i]);
      pBe->apTemp[i] = 0;
      pBe->azTemp[i] = 0;
      break;
    }
  }
  sqliteFree(pBe->azTemp);
  sqliteFree(pBe->apTemp);
  memset(pBe, 0, sizeof(*pBe));
  sqliteFree(pBe);
}

/*
** Translate the name of an SQL table (or index) into the name 
** of a file that holds the key/data pairs for that table or
** index.  Space to hold the filename is obtained from
** sqliteMalloc() and must be freed by the calling function.
*/
static char *sqliteFileOfTable(Dbbex *pBe, const char *zTable){
  char *zFile = 0;
  int i;
  sqliteSetString(&zFile, pBe->zDir, "/", zTable, ".tbl", 0);
  if( zFile==0 ) return 0;
  for(i=strlen(pBe->zDir)+1; zFile[i]; i++){
    int c = zFile[i];
    if( isupper(c) ){
      zFile[i] = tolower(c);
    }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){
      zFile[i] = '+';
    }
  }
  return zFile;
}

/*
** Generate a random filename with the given prefix.  The new filename
** is written into zBuf[].  The calling function must insure that
** zBuf[] is big enough to hold the prefix plus 20 or so extra
** characters.
**
** Very random names are chosen so that the chance of a
** collision with an existing filename is very very small.
*/
static void randomName(struct rc4 *pRc4, char *zBuf, char *zPrefix){
  int i, j;
  static const char zRandomChars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
  strcpy(zBuf, zPrefix);
  j = strlen(zBuf);
  for(i=0; i<15; i++){
    int c = rc4byte(pRc4) % (sizeof(zRandomChars) - 1);
    zBuf[j++] = zRandomChars[c];
  }
  zBuf[j] = 0;
}

/*
** Open a new table cursor.  Write a pointer to the corresponding
** DbbeCursor structure into *ppCursr.  Return an integer success
** code:
**
**    SQLITE_OK          It worked!
**







<
<
<
<
<
<
<
<
<
<
|
<













|

|










<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







113
114
115
116
117
118
119










120

121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146





















147
148
149
150
151
152
153
  int i;
  for(pFile=pBe->pOpen; pFile; pFile=pNext){
    pNext = pFile->pNext;
    gdbm_close(pFile->dbf);
    memset(pFile, 0, sizeof(*pFile));   
    sqliteFree(pFile);
  }










  sqliteDbbeCloseAllTempFiles(pDbbe);

  memset(pBe, 0, sizeof(*pBe));
  sqliteFree(pBe);
}

/*
** Translate the name of an SQL table (or index) into the name 
** of a file that holds the key/data pairs for that table or
** index.  Space to hold the filename is obtained from
** sqliteMalloc() and must be freed by the calling function.
*/
static char *sqliteFileOfTable(Dbbex *pBe, const char *zTable){
  char *zFile = 0;
  int i;
  sqliteSetString(&zFile, pBe->dbbe.zDir, "/", zTable, ".tbl", 0);
  if( zFile==0 ) return 0;
  for(i=strlen(pBe->dbbe.zDir)+1; zFile[i]; i++){
    int c = zFile[i];
    if( isupper(c) ){
      zFile[i] = tolower(c);
    }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){
      zFile[i] = '+';
    }
  }
  return zFile;
}






















/*
** Open a new table cursor.  Write a pointer to the corresponding
** DbbeCursor structure into *ppCursr.  Return an integer success
** code:
**
**    SQLITE_OK          It worked!
**
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
      if( !writeable || pBe->write ){
        pFile->dbf = gdbm_open(zFile, 0, rw_mask, mode, 0);
      }else{
        pFile->dbf = 0;
      }
    }else{
      int limit;
      struct rc4 *pRc4;
      char zRandom[50];
      pRc4 = &pBe->rc4;
      zFile = 0;
      limit = 5;
      do {
        randomName(&pBe->rc4, zRandom, "_temp_table_");
        sqliteFree(zFile);
        zFile = sqliteFileOfTable(pBe, zRandom);
        pFile->dbf = gdbm_open(zFile, 0, rw_mask, mode, 0);
      }while( pFile->dbf==0 && limit-- >= 0);
      pFile->delOnClose = 1;
    }
    pFile->writeable = writeable;







<

<



|







211
212
213
214
215
216
217

218

219
220
221
222
223
224
225
226
227
228
229
      if( !writeable || pBe->write ){
        pFile->dbf = gdbm_open(zFile, 0, rw_mask, mode, 0);
      }else{
        pFile->dbf = 0;
      }
    }else{
      int limit;

      char zRandom[50];

      zFile = 0;
      limit = 5;
      do {
        sqliteRandomName(zRandom, "_temp_table_");
        sqliteFree(zFile);
        zFile = sqliteFileOfTable(pBe, zRandom);
        pFile->dbf = gdbm_open(zFile, 0, rw_mask, mode, 0);
      }while( pFile->dbf==0 && limit-- >= 0);
      pFile->delOnClose = 1;
    }
    pFile->writeable = writeable;
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
** Get a new integer key.
*/
static int sqliteGdbmNew(DbbeCursor *pCursr){
  int iKey;
  datum key;
  int go = 1;
  int i;
  struct rc4 *pRc4;

  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;
  pRc4 = &pCursr->pBe->rc4;
  while( go ){
    iKey = 0;
    for(i=0; i<4; i++){
      iKey = (iKey<<8) + rc4byte(pRc4);
    }
    if( iKey==0 ) continue;
    key.dptr = (char*)&iKey;
    key.dsize = 4;
    go = gdbm_exists(pCursr->pFile->dbf, key);
  }
  return iKey;
}   







<


<

|
<
<
<







491
492
493
494
495
496
497

498
499

500
501



502
503
504
505
506
507
508
** Get a new integer key.
*/
static int sqliteGdbmNew(DbbeCursor *pCursr){
  int iKey;
  datum key;
  int go = 1;
  int i;


  if( pCursr->pFile==0 || pCursr->pFile->dbf==0 ) return 1;

  while( go ){
    iKey = sqliteRandomInteger();



    if( iKey==0 ) continue;
    key.dptr = (char*)&iKey;
    key.dsize = 4;
    go = gdbm_exists(pCursr->pFile->dbf, key);
  }
  return iKey;
}   
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664

665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
  key.dptr = pKey;
  rc = gdbm_delete(pCursr->pFile->dbf, key);
  if( rc ) rc = SQLITE_ERROR;
  return rc;
}

/*
** Open a temporary file.  The file should be deleted when closed.
**
** Note that we can't use the old Unix trick of opening the file
** and then immediately unlinking the file.  That works great
** under Unix, but fails when we try to port to Windows.
*/
static int sqliteGdbmOpenTempFile(Dbbe *pDbbe, FILE **ppFile){
  char *zFile;         /* Full name of the temporary file */
  char zBuf[50];       /* Base name of the temporary file */
  int i;               /* Loop counter */
  int limit;           /* Prevent an infinite loop */
  int rc = SQLITE_OK;  /* Value returned by this function */
  Dbbex *pBe = (Dbbex*)pDbbe;

  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]==0 ) break;
  }
  if( i>=pBe->nTemp ){
    pBe->nTemp++;
    pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) );
    pBe->azTemp = sqliteRealloc(pBe->azTemp, pBe->nTemp*sizeof(char*) );
  }
  if( pBe->apTemp==0 ){
    *ppFile = 0;
    return SQLITE_NOMEM;
  }
  limit = 4;
  zFile = 0;
  do{
    randomName(&pBe->rc4, zBuf, "/_temp_file_");
    sqliteFree(zFile);

    zFile = 0;
    sqliteSetString(&zFile, pBe->zDir, zBuf, 0);
  }while( access(zFile,0)==0 && limit-- >= 0 );
  *ppFile = pBe->apTemp[i] = fopen(zFile, "w+");
  if( pBe->apTemp[i]==0 ){
    rc = SQLITE_ERROR;
    sqliteFree(zFile);
    pBe->azTemp[i] = 0;
  }else{
    pBe->azTemp[i] = zFile;
  }
  return rc;
}

/*
** Close a temporary file opened using sqliteGdbmOpenTempFile()
*/
static void sqliteGdbmCloseTempFile(Dbbe *pDbbe, FILE *f){
  int i;
  Dbbex *pBe = (Dbbex*)pDbbe;
  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]==f ){
      unlink(pBe->azTemp[i]);
      sqliteFree(pBe->azTemp[i]);
      pBe->apTemp[i] = 0;
      pBe->azTemp[i] = 0;
      break;
    }
  }
  fclose(f);
}


/*
** This routine opens a new database.  For the GDBM driver
** implemented here, the database name is the name of the directory
** containing all the files of the database.
**







|
|
<
<
<

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







540
541
542
543
544
545
546
547
548



549
550

551
552
553


554





555
556









557
558
559
560
561
562


563






564
565
566

567





568
569




570
571
572
573
574
575
576
577
578
  key.dptr = pKey;
  rc = gdbm_delete(pCursr->pFile->dbf, key);
  if( rc ) rc = SQLITE_ERROR;
  return rc;
}

/*
** This variable contains pointers to all of the access methods
** used to implement the GDBM backend.



*/
static struct DbbeMethods gdbmMethods = {

  /* n         Close */   sqliteGdbmClose,
  /*      OpenCursor */   sqliteGdbmOpenCursor,
  /*       DropTable */   sqliteGdbmDropTable,


  /* ReorganizeTable */   sqliteGdbmReorganizeTable,





  /*     CloseCursor */   sqliteGdbmCloseCursor,
  /*           Fetch */   sqliteGdbmFetch,









  /*            Test */   sqliteGdbmTest,
  /*         CopyKey */   sqliteGdbmCopyKey,
  /*        CopyData */   sqliteGdbmCopyData,
  /*         ReadKey */   sqliteGdbmReadKey,
  /*        ReadData */   sqliteGdbmReadData,
  /*       KeyLength */   sqliteGdbmKeyLength,


  /*      DataLength */   sqliteGdbmDataLength,






  /*         NextKey */   sqliteGdbmNextKey,
  /*          Rewind */   sqliteGdbmRewind,
  /*             New */   sqliteGdbmNew,

  /*             Put */   sqliteGdbmPut,





  /*          Delete */   sqliteGdbmDelete,
  /*    OpenTempFile */   sqliteDbbeOpenTempFile,




  /*   CloseTempFile */   sqliteDbbeCloseTempFile
};


/*
** This routine opens a new database.  For the GDBM driver
** implemented here, the database name is the name of the directory
** containing all the files of the database.
**
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
  }
  sqliteFree(zMaster);
  pNew = sqliteMalloc(sizeof(Dbbex) + strlen(zName) + 1);
  if( pNew==0 ){
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }
  pNew->dbbe.Close = sqliteGdbmClose;
  pNew->dbbe.OpenCursor = sqliteGdbmOpenCursor;
  pNew->dbbe.DropTable = sqliteGdbmDropTable;
  pNew->dbbe.ReorganizeTable = sqliteGdbmReorganizeTable;
  pNew->dbbe.CloseCursor = sqliteGdbmCloseCursor;
  pNew->dbbe.Fetch = sqliteGdbmFetch;
  pNew->dbbe.Test = sqliteGdbmTest;
  pNew->dbbe.CopyKey = sqliteGdbmCopyKey;
  pNew->dbbe.CopyData = sqliteGdbmCopyData;
  pNew->dbbe.ReadKey = sqliteGdbmReadKey;
  pNew->dbbe.ReadData = sqliteGdbmReadData;
  pNew->dbbe.KeyLength = sqliteGdbmKeyLength;
  pNew->dbbe.DataLength = sqliteGdbmDataLength;
  pNew->dbbe.NextKey = sqliteGdbmNextKey;
  pNew->dbbe.Rewind = sqliteGdbmRewind;
  pNew->dbbe.New = sqliteGdbmNew;
  pNew->dbbe.Put = sqliteGdbmPut;
  pNew->dbbe.Delete = sqliteGdbmDelete;
  pNew->dbbe.OpenTempFile = sqliteGdbmOpenTempFile;
  pNew->dbbe.CloseTempFile = sqliteGdbmCloseTempFile;
  pNew->zDir = (char*)&pNew[1];
  strcpy(pNew->zDir, zName);
  pNew->write = writeFlag;
  pNew->pOpen = 0;
  time(&statbuf.st_ctime);
  rc4init(&pNew->rc4, (char*)&statbuf, sizeof(statbuf));
  return &pNew->dbbe;
}







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
<
<
<
<
|
|


<
<


618
619
620
621
622
623
624















625




626
627
628
629


630
631
  }
  sqliteFree(zMaster);
  pNew = sqliteMalloc(sizeof(Dbbex) + strlen(zName) + 1);
  if( pNew==0 ){
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }















  pNew->dbbe.x = &gdbmMethods;




  pNew->dbbe.zDir = (char*)&pNew[1];
  strcpy(pNew->dbbe.zDir, zName);
  pNew->write = writeFlag;
  pNew->pOpen = 0;


  return &pNew->dbbe;
}
Changes to src/dbbemem.c.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
** This file contains code to implement the database backend (DBBE)
** for sqlite.  The database backend is the interface between
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses an in-memory hash table as the database backend. 
**
** $Id: dbbemem.c,v 1.5 2000/12/10 18:23:50 drh Exp $
*/
#include "sqliteInt.h"
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>








|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
** This file contains code to implement the database backend (DBBE)
** for sqlite.  The database backend is the interface between
** sqlite and the code that does the actually reading and writing
** of information to the disk.
**
** This file uses an in-memory hash table as the database backend. 
**
** $Id: dbbemem.c,v 1.6 2001/01/13 14:34:06 drh Exp $
*/
#include "sqliteInt.h"
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>

338
339
340
341
342
343
344
345
346
347
348
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
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
typedef struct MTable MTable;
struct MTable {
  char *zName;            /* Name of the table */
  int delOnClose;         /* Delete when closing */
  Array data;             /* The data in this stable */
};

/*
** The following structure holds the current state of the RC4 algorithm.
** We use RC4 as a random number generator.  Each call to RC4 gives
** a random 8-bit number.
**
** Nothing in this file or anywhere else in SQLite does any kind of
** encryption.  The RC4 algorithm is being used as a PRNG (pseudo-random
** number generator) not as an encryption device.
*/
struct rc4 {
  int i, j;
  int s[256];
};

/*
** The following structure contains all information used by GDBM
** database driver.  This is a subclass of the Dbbe structure.
*/
typedef struct Dbbex Dbbex;
struct Dbbex {
  Dbbe dbbe;         /* The base class */
  Array tables;      /* All tables of the database */
  int nTemp;         /* Number of temporary files created */
  FILE **apTemp;     /* Space to hold temporary file pointers */
  char **azTemp;     /* Names of the temporary files */
  struct rc4 rc4;    /* The random number generator */
};

/*
** An cursor into a database file is an instance of the following structure.
** There can only be a single MTable structure for each disk file, but
** there can be multiple DbbeCursor structures.  Each DbbeCursor represents
** a cursor pointing to a particular part of the open MTable.  The
** MTable.nRef field hold a count of the number of DbbeCursor structures
** associated with the same disk file.
*/
struct DbbeCursor {
  Dbbex *pBe;        /* The database of which this record is a part */
  MTable *pTble;     /* The database file for this table */
  ArrayElem *elem;   /* Most recently accessed record */
  int needRewind;    /* Next key should be the first */
};

/*
** Initialize the RC4 PRNG.  "seed" is a pointer to some random
** data used to initialize the PRNG.  
*/
static void rc4init(struct rc4 *p, char *seed, int seedlen){
  int i;
  char k[256];
  p->j = 0;
  p->i = 0;
  for(i=0; i<256; i++){
    p->s[i] = i;
    k[i] = seed[i%seedlen];
  }
  for(i=0; i<256; i++){
    int t;
    p->j = (p->j + p->s[i] + k[i]) & 0xff;
    t = p->s[p->j];
    p->s[p->j] = p->s[i];
    p->s[i] = t;
  }
}

/*
** Get a single 8-bit random value from the RC4 PRNG.
*/
static int rc4byte(struct rc4 *p){
  int t;
  p->i = (p->i + 1) & 0xff;
  p->j = (p->j + p->s[p->i]) & 0xff;
  t = p->s[p->i];
  p->s[p->i] = p->s[p->j];
  p->s[p->j] = t;
  t = p->s[p->i] + p->s[p->j];
  return t & 0xff;
}

/*
** Forward declaration
*/
static void sqliteMemCloseCursor(DbbeCursor *pCursr);

/*
** Erase all the memory of an MTable







<
<
<
<
<
<
<
<
<
<
<
<
<
<








<
<
<
<

















<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







338
339
340
341
342
343
344














345
346
347
348
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
typedef struct MTable MTable;
struct MTable {
  char *zName;            /* Name of the table */
  int delOnClose;         /* Delete when closing */
  Array data;             /* The data in this stable */
};















/*
** The following structure contains all information used by GDBM
** database driver.  This is a subclass of the Dbbe structure.
*/
typedef struct Dbbex Dbbex;
struct Dbbex {
  Dbbe dbbe;         /* The base class */
  Array tables;      /* All tables of the database */




};

/*
** An cursor into a database file is an instance of the following structure.
** There can only be a single MTable structure for each disk file, but
** there can be multiple DbbeCursor structures.  Each DbbeCursor represents
** a cursor pointing to a particular part of the open MTable.  The
** MTable.nRef field hold a count of the number of DbbeCursor structures
** associated with the same disk file.
*/
struct DbbeCursor {
  Dbbex *pBe;        /* The database of which this record is a part */
  MTable *pTble;     /* The database file for this table */
  ArrayElem *elem;   /* Most recently accessed record */
  int needRewind;    /* Next key should be the first */
};





































/*
** Forward declaration
*/
static void sqliteMemCloseCursor(DbbeCursor *pCursr);

/*
** Erase all the memory of an MTable
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
  int i;
  ArrayElem *j, *k;
  for(j=ArrayFirst(&pBe->tables); j; j=ArrayNext(j)){
    pTble = ArrayData(j);
    deleteMTable(pTble);
  }
  ArrayClear(&pBe->tables);
  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]!=0 ){
      unlink(pBe->azTemp[i]);
      fclose(pBe->apTemp[i]);
      sqliteFree(pBe->azTemp[i]);
      pBe->apTemp[i] = 0;
      pBe->azTemp[i] = 0;
      break;
    }
  }
  sqliteFree(pBe->azTemp);
  sqliteFree(pBe->apTemp);
  memset(pBe, 0, sizeof(*pBe));
  sqliteFree(pBe);
}

/*
** Generate a random filename with the given prefix.  The new filename
** is written into zBuf[].  The calling function must insure that
** zBuf[] is big enough to hold the prefix plus 20 or so extra
** characters.
**
** Very random names are chosen so that the chance of a
** collision with an existing filename is very very small.
*/
static void randomName(struct rc4 *pRc4, char *zBuf, char *zPrefix){
  int i, j;
  static const char zRandomChars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
  strcpy(zBuf, zPrefix);
  j = strlen(zBuf);
  for(i=0; i<15; i++){
    int c = rc4byte(pRc4) % (sizeof(zRandomChars) - 1);
    zBuf[j++] = zRandomChars[c];
  }
  zBuf[j] = 0;
}

/*
** Translate the name of an SQL table (or index) into its
** canonical name.
** 
** Space to hold the canonical name is obtained from
** sqliteMalloc() and must be freed by the calling function.
*/







<
<
<
<
<
<
<
<
<
<
|
<




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







395
396
397
398
399
400
401










402

403
404
405
406





















407
408
409
410
411
412
413
  int i;
  ArrayElem *j, *k;
  for(j=ArrayFirst(&pBe->tables); j; j=ArrayNext(j)){
    pTble = ArrayData(j);
    deleteMTable(pTble);
  }
  ArrayClear(&pBe->tables);










  sqliteDbbeCloseAllTempFiles(pDbbe);

  memset(pBe, 0, sizeof(*pBe));
  sqliteFree(pBe);
}






















/*
** Translate the name of an SQL table (or index) into its
** canonical name.
** 
** Space to hold the canonical name is obtained from
** sqliteMalloc() and must be freed by the calling function.
*/
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
** Get a new integer key.
*/
static int sqliteMemNew(DbbeCursor *pCursr){
  int iKey;
  Datum key;
  int go = 1;
  int i;
  struct rc4 *pRc4;

  pRc4 = &pCursr->pBe->rc4;
  while( go ){
    iKey = 0;
    for(i=0; i<4; i++){
      iKey = (iKey<<8) + rc4byte(pRc4);
    }
    if( iKey==0 ) continue;
    key.p = (char*)&iKey;
    key.n = 4;
    go = ArrayFindElement(&pCursr->pTble->data, key)!=0;
  }
  return iKey;
}   







<

<

|
<
<
<







662
663
664
665
666
667
668

669

670
671



672
673
674
675
676
677
678
** Get a new integer key.
*/
static int sqliteMemNew(DbbeCursor *pCursr){
  int iKey;
  Datum key;
  int go = 1;
  int i;



  while( go ){
    iKey = sqliteRandomInteger();



    if( iKey==0 ) continue;
    key.p = (char*)&iKey;
    key.n = 4;
    go = ArrayFindElement(&pCursr->pTble->data, key)!=0;
  }
  return iKey;
}   
800
801
802
803
804
805
806
807
808
809
810
811
812


813
814

815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
  if( data.p ){
    sqliteFree(data.p);
  }
  return SQLITE_OK;
}

/*
** Open a temporary file.  The file should be deleted when closed.
**
** Note that we can't use the old Unix trick of opening the file
** and then immediately unlinking the file.  That works great
** under Unix, but fails when we try to port to Windows.
*/


static int sqliteMemOpenTempFile(Dbbe *pDbbe, FILE **ppTble){
  char *zName;         /* Full name of the temporary file */

  char zBuf[50];       /* Base name of the temporary file */
  int i;               /* Loop counter */
  int limit;           /* Prevent an infinite loop */
  int rc = SQLITE_OK;  /* Value returned by this function */
  Dbbex *pBe = (Dbbex*)pDbbe;

  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]==0 ) break;
  }
  if( i>=pBe->nTemp ){
    pBe->nTemp++;
    pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) );
    pBe->azTemp = sqliteRealloc(pBe->azTemp, pBe->nTemp*sizeof(char*) );
  }
  if( pBe->apTemp==0 ){
    *ppTble = 0;
    return SQLITE_NOMEM;
  }
  limit = 4;
  zName = 0;
  do{
    randomName(&pBe->rc4, zBuf, "/tmp/_temp_file_");
    sqliteFree(zName);
    zName = 0;
    sqliteSetString(&zName, zBuf, 0);
  }while( access(zName,0)==0 && limit-- >= 0 );
  *ppTble = pBe->apTemp[i] = fopen(zName, "w+");
  if( pBe->apTemp[i]==0 ){
    rc = SQLITE_ERROR;
    sqliteFree(zName);
    pBe->azTemp[i] = 0;
  }else{
    pBe->azTemp[i] = zName;
  }
  return rc;
}

/*
** Close a temporary file opened using sqliteMemOpenTempFile()
*/
static void sqliteMemCloseTempFile(Dbbe *pDbbe, FILE *f){
  int i;
  Dbbex *pBe = (Dbbex*)pDbbe;
  for(i=0; i<pBe->nTemp; i++){
    if( pBe->apTemp[i]==f ){
      unlink(pBe->azTemp[i]);
      sqliteFree(pBe->azTemp[i]);
      pBe->apTemp[i] = 0;
      pBe->azTemp[i] = 0;
      break;
    }
  }
  fclose(f);
}


/*
** This routine opens a new database.  For the GDBM driver
** implemented here, the database name is the name of the directory
** containing all the files of the database.
**
** If successful, a pointer to the Dbbe structure is returned.
** If there are errors, an appropriate error message is left
** in *pzErrMsg and NULL is returned.
*/
Dbbe *sqliteMemOpen(
  const char *zName,     /* The name of the database */
  int writeFlag,         /* True if we will be writing to the database */
  int createFlag,        /* True to create database if it doesn't exist */
  char **pzErrMsg        /* Write error messages (if any) here */
){
  Dbbex *pNew;
  long now;

  pNew = sqliteMalloc( sizeof(*pNew) );
  if( pNew==0 ){
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }
  ArrayInit(&pNew->tables);
  pNew->dbbe.Close = sqliteMemClose;
  pNew->dbbe.OpenCursor = sqliteMemOpenCursor;
  pNew->dbbe.DropTable = sqliteMemDropTable;
  pNew->dbbe.ReorganizeTable = sqliteMemReorganizeTable;
  pNew->dbbe.CloseCursor = sqliteMemCloseCursor;
  pNew->dbbe.Fetch = sqliteMemFetch;
  pNew->dbbe.Test = sqliteMemTest;
  pNew->dbbe.CopyKey = sqliteMemCopyKey;
  pNew->dbbe.CopyData = sqliteMemCopyData;
  pNew->dbbe.ReadKey = sqliteMemReadKey;
  pNew->dbbe.ReadData = sqliteMemReadData;
  pNew->dbbe.KeyLength = sqliteMemKeyLength;
  pNew->dbbe.DataLength = sqliteMemDataLength;
  pNew->dbbe.NextKey = sqliteMemNextKey;
  pNew->dbbe.Rewind = sqliteMemRewind;
  pNew->dbbe.New = sqliteMemNew;
  pNew->dbbe.Put = sqliteMemPut;
  pNew->dbbe.Delete = sqliteMemDelete;
  pNew->dbbe.OpenTempFile = sqliteMemOpenTempFile;
  pNew->dbbe.CloseTempFile = sqliteMemCloseTempFile;
  time(&now);
  rc4init(&pNew->rc4, (char*)&now, sizeof(now));
  return &pNew->dbbe;
}







|
|
<
<
<

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

















<







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
<
<
<
<
<


709
710
711
712
713
714
715
716
717



718
719
720
721
722
723
724
725
726


727

















728
729
730



731






732
733
734
735
736





737
738




739
740

741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757

758
759
760
761
762
763
764















765
766





767
768
  if( data.p ){
    sqliteFree(data.p);
  }
  return SQLITE_OK;
}

/*
** This variable contains pointers to all of the access methods
** used to implement the MEMORY backend.



*/
static struct DbbeMethods memoryMethods = {
  /* n         Close */   sqliteMemClose,
  /*      OpenCursor */   sqliteMemOpenCursor,
  /*       DropTable */   sqliteMemDropTable,
  /* ReorganizeTable */   sqliteMemReorganizeTable,
  /*     CloseCursor */   sqliteMemCloseCursor,
  /*           Fetch */   sqliteMemFetch,
  /*            Test */   sqliteMemTest,


  /*         CopyKey */   sqliteMemCopyKey,

















  /*        CopyData */   sqliteMemCopyData,
  /*         ReadKey */   sqliteMemReadKey,
  /*        ReadData */   sqliteMemReadData,



  /*       KeyLength */   sqliteMemKeyLength,






  /*      DataLength */   sqliteMemDataLength,
  /*         NextKey */   sqliteMemNextKey,
  /*          Rewind */   sqliteMemRewind,
  /*             New */   sqliteMemNew,
  /*             Put */   sqliteMemPut,





  /*          Delete */   sqliteMemDelete,
  /*    OpenTempFile */   sqliteDbbeOpenTempFile,




  /*   CloseTempFile */   sqliteDbbeCloseTempFile
};


/*
** This routine opens a new database.  For the GDBM driver
** implemented here, the database name is the name of the directory
** containing all the files of the database.
**
** If successful, a pointer to the Dbbe structure is returned.
** If there are errors, an appropriate error message is left
** in *pzErrMsg and NULL is returned.
*/
Dbbe *sqliteMemOpen(
  const char *zName,     /* The name of the database */
  int writeFlag,         /* True if we will be writing to the database */
  int createFlag,        /* True to create database if it doesn't exist */
  char **pzErrMsg        /* Write error messages (if any) here */
){
  Dbbex *pNew;


  pNew = sqliteMalloc( sizeof(*pNew) );
  if( pNew==0 ){
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }
  ArrayInit(&pNew->tables);















  pNew->dbbe.x = &memoryMethods;
  pNew->dbbe.zDir = 0;





  return &pNew->dbbe;
}
Changes to src/main.c.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.22 2000/12/10 18:23:50 drh Exp $
*/
#include "sqliteInt.h"

/*
** This is the callback routine for the code that initializes the
** database.  Each callback contains text of a CREATE TABLE or
** CREATE INDEX statement that must be parsed to yield the internal







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
**
*************************************************************************
** Main file for the SQLite library.  The routines in this file
** implement the programmer interface to the library.  Routines in
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
** $Id: main.c,v 1.23 2001/01/13 14:34:06 drh Exp $
*/
#include "sqliteInt.h"

/*
** This is the callback routine for the code that initializes the
** database.  Each callback contains text of a CREATE TABLE or
** CREATE INDEX statement that must be parsed to yield the internal
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
}

/*
** Close an existing SQLite database
*/
void sqlite_close(sqlite *db){
  int i;
  db->pBe->Close(db->pBe);
  for(i=0; i<N_HASH; i++){
    Table *pNext, *pList = db->apTblHash[i];
    db->apTblHash[i] = 0;
    while( pList ){
      pNext = pList->pHash;
      pList->pHash = 0;
      sqliteDeleteTable(db, pList);







|







235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
}

/*
** Close an existing SQLite database
*/
void sqlite_close(sqlite *db){
  int i;
  db->pBe->x->Close(db->pBe);
  for(i=0; i<N_HASH; i++){
    Table *pNext, *pList = db->apTblHash[i];
    db->apTblHash[i] = 0;
    while( pList ){
      pNext = pList->pHash;
      pList->pHash = 0;
      sqliteDeleteTable(db, pList);
Added src/random.c.






























































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
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
38
39
40
41
42
43
44
45
46
47
48
49
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
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
** Copyright (c) 2000 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** General Public License for more details.
** 
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA  02111-1307, USA.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains code to implement a pseudo-random number
** generator (PRNG) for SQLite.
**
** Random numbers are used by some of the database backends in order
** to generate random integer keys for tables or random filenames.
**
** $Id: random.c,v 1.1 2001/01/13 14:34:07 drh Exp $
*/
#include "sqliteInt.h"


/*
** Get a single 8-bit random value from the RC4 PRNG.
*/
int sqliteRandomByte(void){
  int t;

  /*
  ** The following structure holds the current state of the RC4 algorithm.
  ** We use RC4 as a random number generator.  Each call to RC4 gives
  ** a random 8-bit number.
  **
  ** Nothing in this file or anywhere else in SQLite does any kind of
  ** encryption.  The RC4 algorithm is being used as a PRNG (pseudo-random
  ** number generator) not as an encryption device.
  */
  static struct {
    int isInit;
    int i, j;
    int s[256];
  } prng_state;
 
  /* Initialize the state of the random number generator once,
  ** the first time this routine is called.  The seed value does
  ** not need to contain a lot of randomness since we are not
  ** trying to do secure encryption or anything like that...
  */
  if( !prng_state.isInit ){
    int i;
    static char seed[] = "    sqlite random seed";
    char k[256];
    time((time_t*)seed);
    prng_state.j = 0;
    prng_state.i = 0;
    for(i=0; i<256; i++){
      prng_state.s[i] = i;
      k[i] = seed[i%sizeof(seed)];
    }
    for(i=0; i<256; i++){
      int t;
      prng_state.j = (prng_state.j + prng_state.s[i] + k[i]) & 0xff;
      t = prng_state.s[prng_state.j];
      prng_state.s[prng_state.j] = prng_state.s[i];
      prng_state.s[i] = t;
    }
    prng_state.isInit = 1;
  }

  /* Generate and return single random byte
  */
  prng_state.i = (prng_state.i + 1) & 0xff;
  prng_state.j = (prng_state.j + prng_state.s[prng_state.i]) & 0xff;
  t = prng_state.s[prng_state.i];
  prng_state.s[prng_state.i] = prng_state.s[prng_state.j];
  prng_state.s[prng_state.j] = t;
  t = prng_state.s[prng_state.i] + prng_state.s[prng_state.j];
  return t & 0xff;
}

/*
** Return a random 32-bit integer.  The integer is generated by making
** 4 calls to sqliteRandomByte().
*/
int sqliteRandomInteger(void){
  int r;
  int i;
  r = sqliteRandomByte();
  for(i=1; i<4; i++){
    r = (r<<8) + sqliteRandomByte();
  }
  return r;
}


/*
** Generate a random filename with the given prefix.  The new filename
** is written into zBuf[].  The calling function must insure that
** zBuf[] is big enough to hold the prefix plus 20 or so extra
** characters.
**
** Very random names are chosen so that the chance of a
** collision with an existing filename is very very small.
*/
void sqliteRandomName(char *zBuf, char *zPrefix){
  int i, j;
  static const char zRandomChars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
  strcpy(zBuf, zPrefix);
  j = strlen(zBuf);
  for(i=0; i<15; i++){
    int c = sqliteRandomByte() % (sizeof(zRandomChars) - 1);
    zBuf[j++] = zRandomChars[c];
  }
  zBuf[j] = 0;
}
Changes to src/sqliteInt.h.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.33 2000/12/10 18:23:51 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.34 2001/01/13 14:34:07 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>
415
416
417
418
419
420
421





int sqliteExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, IdList*, Expr*);
void sqliteExprResolveInSelect(Parse*, Expr*);
int sqliteExprAnalyzeAggregates(Parse*, Expr*);
void sqliteParseInfoReset(Parse*);
Vdbe *sqliteGetVdbe(Parse*);












>
>
>
>
>
415
416
417
418
419
420
421
422
423
424
425
426
int sqliteExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, IdList*, Expr*);
void sqliteExprResolveInSelect(Parse*, Expr*);
int sqliteExprAnalyzeAggregates(Parse*, Expr*);
void sqliteParseInfoReset(Parse*);
Vdbe *sqliteGetVdbe(Parse*);
int sqliteRandomByte(void);
int sqliteRandomInteger(void);
void sqliteRandomName(char*,char*);
int sqliteDbbeOpenTempFile(Dbbe*, FILE**);
void sqliteDbbeCloseTempFile(Dbbe*, FILE*);
Changes to src/vdbe.c.
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
** inplicit conversion from one type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.49 2000/12/10 18:35:20 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>
#include <ctype.h>

/*
** SQL is translated into a sequence of instructions to be







|







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
** inplicit conversion from one type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.50 2001/01/13 14:34:07 drh Exp $
*/
#include "sqliteInt.h"
#include <unistd.h>
#include <ctype.h>

/*
** SQL is translated into a sequence of instructions to be
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
static void Cleanup(Vdbe *p){
  int i;
  PopStack(p, p->tos+1);
  sqliteFree(p->azColName);
  p->azColName = 0;
  for(i=0; i<p->nCursor; i++){
    if( p->aCsr[i].pCursor ){
      p->pBe->CloseCursor(p->aCsr[i].pCursor);
      p->aCsr[i].pCursor = 0;
    }
  }
  sqliteFree(p->aCsr);
  p->aCsr = 0;
  p->nCursor = 0;
  for(i=0; i<p->nMem; i++){
    if( p->aMem[i].s.flags & STK_Dyn ){
      sqliteFree(p->aMem[i].z);
    }
  }
  sqliteFree(p->aMem);
  p->aMem = 0;
  p->nMem = 0;
  for(i=0; i<p->nList; i++){
    if( p->apList[i] ){
      p->pBe->CloseTempFile(p->pBe, p->apList[i]);
      p->apList[i] = 0;
    }
  }
  sqliteFree(p->apList);
  p->apList = 0;
  p->nList = 0;
  for(i=0; i<p->nSort; i++){







|
















|







692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
static void Cleanup(Vdbe *p){
  int i;
  PopStack(p, p->tos+1);
  sqliteFree(p->azColName);
  p->azColName = 0;
  for(i=0; i<p->nCursor; i++){
    if( p->aCsr[i].pCursor ){
      p->pBe->x->CloseCursor(p->aCsr[i].pCursor);
      p->aCsr[i].pCursor = 0;
    }
  }
  sqliteFree(p->aCsr);
  p->aCsr = 0;
  p->nCursor = 0;
  for(i=0; i<p->nMem; i++){
    if( p->aMem[i].s.flags & STK_Dyn ){
      sqliteFree(p->aMem[i].z);
    }
  }
  sqliteFree(p->aMem);
  p->aMem = 0;
  p->nMem = 0;
  for(i=0; i<p->nList; i++){
    if( p->apList[i] ){
      p->pBe->x->CloseTempFile(p->pBe, p->apList[i]);
      p->apList[i] = 0;
    }
  }
  sqliteFree(p->apList);
  p->apList = 0;
  p->nList = 0;
  for(i=0; i<p->nSort; i++){
949
950
951
952
953
954
955

956
957
958
959
960
961
962
  void *pBusyArg,            /* 1st argument to the busy callback */
  int (*xBusy)(void*,const char*,int)  /* Called when a file is busy */
){
  int pc;                    /* The program counter */
  Op *pOp;                   /* Current operation */
  int rc;                    /* Value to return */
  Dbbe *pBe = p->pBe;        /* The backend driver */

  sqlite *db = p->db;        /* The database */
  char **zStack;
  Stack *aStack;
  char zBuf[100];            /* Space to sprintf() and integer */


  /* No instruction ever pushes more than a single element onto the







>







949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
  void *pBusyArg,            /* 1st argument to the busy callback */
  int (*xBusy)(void*,const char*,int)  /* Called when a file is busy */
){
  int pc;                    /* The program counter */
  Op *pOp;                   /* Current operation */
  int rc;                    /* Value to return */
  Dbbe *pBe = p->pBe;        /* The backend driver */
  DbbeMethods *pBex = pBe->x;  /* The backend driver methods */
  sqlite *db = p->db;        /* The database */
  char **zStack;
  Stack *aStack;
  char zBuf[100];            /* Space to sprintf() and integer */


  /* No instruction ever pushes more than a single element onto the
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
        if( i>=p->nCursor ){
          int j;
          p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) );
          if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; }
          for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0;
          p->nCursor = i+1;
        }else if( p->aCsr[i].pCursor ){
          pBe->CloseCursor(p->aCsr[i].pCursor);
        }
        do {
          rc = pBe->OpenCursor(pBe,pOp->p3,pOp->p2,&p->aCsr[i].pCursor);
          switch( rc ){
            case SQLITE_BUSY: {
              if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){
                sqliteSetString(pzErrMsg,"table ", pOp->p3, " is locked", 0);
                busy = 0;
              }
              break;







|


|







1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
        if( i>=p->nCursor ){
          int j;
          p->aCsr = sqliteRealloc( p->aCsr, (i+1)*sizeof(Cursor) );
          if( p->aCsr==0 ){ p->nCursor = 0; goto no_mem; }
          for(j=p->nCursor; j<=i; j++) p->aCsr[j].pCursor = 0;
          p->nCursor = i+1;
        }else if( p->aCsr[i].pCursor ){
          pBex->CloseCursor(p->aCsr[i].pCursor);
        }
        do {
          rc = pBex->OpenCursor(pBe,pOp->p3,pOp->p2,&p->aCsr[i].pCursor);
          switch( rc ){
            case SQLITE_BUSY: {
              if( xBusy==0 || (*xBusy)(pBusyArg, pOp->p3, ++busy)==0 ){
                sqliteSetString(pzErrMsg,"table ", pOp->p3, " is locked", 0);
                busy = 0;
              }
              break;
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
      **
      ** 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 ){
          pBe->CloseCursor(p->aCsr[i].pCursor);
          p->aCsr[i].pCursor = 0;
        }
        break;
      }

      /* Opcode: Fetch P1 * *
      **
      ** Pop the top of the stack and use its value as a key to fetch
      ** a record from cursor P1.  The key/data pair is held
      ** in the P1 cursor until needed.
      */
      case OP_Fetch: {
        int i = pOp->p1;
        int tos = p->tos;
        VERIFY( if( tos<0 ) goto not_enough_stack; )
        if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){
          if( aStack[tos].flags & STK_Int ){
            pBe->Fetch(p->aCsr[i].pCursor, sizeof(int), 
                           (char*)&aStack[tos].i);
          }else{
            if( Stringify(p, tos) ) goto no_mem;
            pBe->Fetch(p->aCsr[i].pCursor, aStack[tos].n, 
                           zStack[tos]);
          }
          p->nFetch++;
        }
        POPSTACK;
        break;
      }







|

















|



|







1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
      **
      ** 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 ){
          pBex->CloseCursor(p->aCsr[i].pCursor);
          p->aCsr[i].pCursor = 0;
        }
        break;
      }

      /* Opcode: Fetch P1 * *
      **
      ** Pop the top of the stack and use its value as a key to fetch
      ** a record from cursor P1.  The key/data pair is held
      ** in the P1 cursor until needed.
      */
      case OP_Fetch: {
        int i = pOp->p1;
        int tos = p->tos;
        VERIFY( if( tos<0 ) goto not_enough_stack; )
        if( i>=0 && i<p->nCursor && p->aCsr[i].pCursor ){
          if( aStack[tos].flags & STK_Int ){
            pBex->Fetch(p->aCsr[i].pCursor, sizeof(int), 
                           (char*)&aStack[tos].i);
          }else{
            if( Stringify(p, tos) ) goto no_mem;
            pBex->Fetch(p->aCsr[i].pCursor, aStack[tos].n, 
                           zStack[tos]);
          }
          p->nFetch++;
        }
        POPSTACK;
        break;
      }
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
      case OP_Found: {
        int i = pOp->p1;
        int tos = p->tos;
        int alreadyExists = 0;
        VERIFY( if( tos<0 ) goto not_enough_stack; )
        if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor ){
          if( aStack[tos].flags & STK_Int ){
            alreadyExists = pBe->Test(p->aCsr[i].pCursor, sizeof(int), 
                                          (char*)&aStack[tos].i);
          }else{
            if( Stringify(p, tos) ) goto no_mem;
            alreadyExists = pBe->Test(p->aCsr[i].pCursor,aStack[tos].n, 
                                           zStack[tos]);
          }
        }
        if( pOp->opcode==OP_Found ){
          if( alreadyExists ) pc = pOp->p2 - 1;
        }else{
          if( !alreadyExists ) pc = pOp->p2 - 1;







|



|







1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
      case OP_Found: {
        int i = pOp->p1;
        int tos = p->tos;
        int alreadyExists = 0;
        VERIFY( if( tos<0 ) goto not_enough_stack; )
        if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor ){
          if( aStack[tos].flags & STK_Int ){
            alreadyExists = pBex->Test(p->aCsr[i].pCursor, sizeof(int), 
                                          (char*)&aStack[tos].i);
          }else{
            if( Stringify(p, tos) ) goto no_mem;
            alreadyExists = pBex->Test(p->aCsr[i].pCursor,aStack[tos].n, 
                                           zStack[tos]);
          }
        }
        if( pOp->opcode==OP_Found ){
          if( alreadyExists ) pc = pOp->p2 - 1;
        }else{
          if( !alreadyExists ) pc = pOp->p2 - 1;
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
      */
      case OP_New: {
        int i = pOp->p1;
        int v;
        if( VERIFY( i<0 || i>=p->nCursor || ) p->aCsr[i].pCursor==0 ){
          v = 0;
        }else{
          v = pBe->New(p->aCsr[i].pCursor);
        }
        VERIFY( NeedStack(p, p->tos+1); )
        p->tos++;
        aStack[p->tos].i = v;
        aStack[p->tos].flags = STK_Int;
        break;
      }







|







1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
      */
      case OP_New: {
        int i = pOp->p1;
        int v;
        if( VERIFY( i<0 || i>=p->nCursor || ) p->aCsr[i].pCursor==0 ){
          v = 0;
        }else{
          v = pBex->New(p->aCsr[i].pCursor);
        }
        VERIFY( NeedStack(p, p->tos+1); )
        p->tos++;
        aStack[p->tos].i = v;
        aStack[p->tos].flags = STK_Int;
        break;
      }
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
            if( Stringify(p, nos) ) goto no_mem;
            nKey = aStack[nos].n;
            zKey = zStack[nos];
          }else{
            nKey = sizeof(int);
            zKey = (char*)&aStack[nos].i;
          }
          pBe->Put(p->aCsr[i].pCursor, nKey, zKey,
                        aStack[tos].n, zStack[tos]);
        }
        POPSTACK;
        POPSTACK;
        break;
      }








|







1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
            if( Stringify(p, nos) ) goto no_mem;
            nKey = aStack[nos].n;
            zKey = zStack[nos];
          }else{
            nKey = sizeof(int);
            zKey = (char*)&aStack[nos].i;
          }
          pBex->Put(p->aCsr[i].pCursor, nKey, zKey,
                        aStack[tos].n, zStack[tos]);
        }
        POPSTACK;
        POPSTACK;
        break;
      }

2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
            nKey = sizeof(int);
            zKey = (char*)&aStack[tos].i;
          }else{
            if( Stringify(p, tos) ) goto no_mem;
            nKey = aStack[tos].n;
            zKey = zStack[tos];
          }
          pBe->Delete(p->aCsr[i].pCursor, nKey, zKey);
        }
        POPSTACK;
        break;
      }

      /* Opcode: KeyAsData P1 P2 *
      **







|







2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
            nKey = sizeof(int);
            zKey = (char*)&aStack[tos].i;
          }else{
            if( Stringify(p, tos) ) goto no_mem;
            nKey = aStack[tos].n;
            zKey = zStack[tos];
          }
          pBex->Delete(p->aCsr[i].pCursor, nKey, zKey);
        }
        POPSTACK;
        break;
      }

      /* Opcode: KeyAsData P1 P2 *
      **
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
        int tos = ++p->tos;
        DbbeCursor *pCrsr;
        char *z;

        VERIFY( if( NeedStack(p, tos) ) goto no_mem; )
        if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
          if( p->aCsr[i].keyAsData ){
            amt = pBe->KeyLength(pCrsr);
            if( amt<=sizeof(int)*(p2+1) ){
              aStack[tos].flags = STK_Null;
              break;
            }
            pAddr = (int*)pBe->ReadKey(pCrsr, sizeof(int)*p2);
            if( *pAddr==0 ){
              aStack[tos].flags = STK_Null;
              break;
            }
            z = pBe->ReadKey(pCrsr, *pAddr);
          }else{
            amt = pBe->DataLength(pCrsr);
            if( amt<=sizeof(int)*(p2+1) ){
              aStack[tos].flags = STK_Null;
              break;
            }
            pAddr = (int*)pBe->ReadData(pCrsr, sizeof(int)*p2);
            if( *pAddr==0 ){
              aStack[tos].flags = STK_Null;
              break;
            }
            z = pBe->ReadData(pCrsr, *pAddr);
          }
          zStack[tos] = z;
          aStack[tos].n = strlen(z) + 1;
          aStack[tos].flags = STK_Str;
        }
        break;
      }







|




|




|

|




|




|







2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
        int tos = ++p->tos;
        DbbeCursor *pCrsr;
        char *z;

        VERIFY( if( NeedStack(p, tos) ) goto no_mem; )
        if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
          if( p->aCsr[i].keyAsData ){
            amt = pBex->KeyLength(pCrsr);
            if( amt<=sizeof(int)*(p2+1) ){
              aStack[tos].flags = STK_Null;
              break;
            }
            pAddr = (int*)pBex->ReadKey(pCrsr, sizeof(int)*p2);
            if( *pAddr==0 ){
              aStack[tos].flags = STK_Null;
              break;
            }
            z = pBex->ReadKey(pCrsr, *pAddr);
          }else{
            amt = pBex->DataLength(pCrsr);
            if( amt<=sizeof(int)*(p2+1) ){
              aStack[tos].flags = STK_Null;
              break;
            }
            pAddr = (int*)pBex->ReadData(pCrsr, sizeof(int)*p2);
            if( *pAddr==0 ){
              aStack[tos].flags = STK_Null;
              break;
            }
            z = pBex->ReadData(pCrsr, *pAddr);
          }
          zStack[tos] = z;
          aStack[tos].n = strlen(z) + 1;
          aStack[tos].flags = STK_Str;
        }
        break;
      }
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
      case OP_Key: {
        int i = pOp->p1;
        int tos = ++p->tos;
        DbbeCursor *pCrsr;

        VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
        if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
          char *z = pBe->ReadKey(pCrsr, 0);
          if( p->aCsr[i].keyAsData ){
            zStack[tos] = z;
            aStack[tos].flags = STK_Str;
            aStack[tos].n = pBe->KeyLength(pCrsr);
          }else{
            memcpy(&aStack[tos].i, z, sizeof(int));
            aStack[tos].flags = STK_Int;
          }
        }
        break;
      }

      /* Opcode: Rewind P1 * *
      **
      ** The next use of the Key or Field or Next instruction for P1 
      ** will refer to the first entry in the database file.
      */
      case OP_Rewind: {
        int i = pOp->p1;
        if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){
          pBe->Rewind(p->aCsr[i].pCursor);
        }
        break;
      }

      /* Opcode: Next P1 P2 *
      **
      ** Advance P1 to the next key/data pair in the file.  Or, if there are no
      ** more key/data pairs, rewind P1 and jump to location P2.
      */
      case OP_Next: {
        int i = pOp->p1;
        if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){
          if( pBe->NextKey(p->aCsr[i].pCursor)==0 ){
            pc = pOp->p2 - 1;
          }else{
            p->nFetch++;
          }
        }
        break;
      }







|



|
















|












|







2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
      case OP_Key: {
        int i = pOp->p1;
        int tos = ++p->tos;
        DbbeCursor *pCrsr;

        VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
        if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
          char *z = pBex->ReadKey(pCrsr, 0);
          if( p->aCsr[i].keyAsData ){
            zStack[tos] = z;
            aStack[tos].flags = STK_Str;
            aStack[tos].n = pBex->KeyLength(pCrsr);
          }else{
            memcpy(&aStack[tos].i, z, sizeof(int));
            aStack[tos].flags = STK_Int;
          }
        }
        break;
      }

      /* Opcode: Rewind P1 * *
      **
      ** The next use of the Key or Field or Next instruction for P1 
      ** will refer to the first entry in the database file.
      */
      case OP_Rewind: {
        int i = pOp->p1;
        if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){
          pBex->Rewind(p->aCsr[i].pCursor);
        }
        break;
      }

      /* Opcode: Next P1 P2 *
      **
      ** Advance P1 to the next key/data pair in the file.  Or, if there are no
      ** more key/data pairs, rewind P1 and jump to location P2.
      */
      case OP_Next: {
        int i = pOp->p1;
        if( VERIFY( i>=0 && i<p->nCursor && ) p->aCsr[i].pCursor!=0 ){
          if( pBex->NextKey(p->aCsr[i].pCursor)==0 ){
            pc = pOp->p2 - 1;
          }else{
            p->nFetch++;
          }
        }
        break;
      }
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222

        VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
        zStack[tos] = 0;
        if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
          int *aIdx;
          int nIdx;
          int j, k;
          nIdx = pBe->DataLength(pCrsr)/sizeof(int);
          aIdx = (int*)pBe->ReadData(pCrsr, 0);
          if( nIdx>1 ){
            k = *(aIdx++);
            if( k>nIdx-1 ) k = nIdx-1;
          }else{
            k = nIdx;
          }
          for(j=p->aCsr[i].index; j<k; j++){







|
|







2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223

        VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
        zStack[tos] = 0;
        if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
          int *aIdx;
          int nIdx;
          int j, k;
          nIdx = pBex->DataLength(pCrsr)/sizeof(int);
          aIdx = (int*)pBex->ReadData(pCrsr, 0);
          if( nIdx>1 ){
            k = *(aIdx++);
            if( k>nIdx-1 ) k = nIdx-1;
          }else{
            k = nIdx;
          }
          for(j=p->aCsr[i].index; j<k; j++){
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
        VERIFY( if( nos<0 ) goto not_enough_stack; )
        if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
          int r;
          int newVal;
          Integerify(p, nos);
          newVal = aStack[nos].i;
          if( Stringify(p, tos) ) goto no_mem;
          r = pBe->Fetch(pCrsr, aStack[tos].n, zStack[tos]);
          if( r==0 ){
            /* Create a new record for this index */
            pBe->Put(pCrsr, aStack[tos].n, zStack[tos],
                          sizeof(int), (char*)&newVal);
          }else{
            /* Extend the existing record */
            int nIdx;
            int *aIdx;
            int k;
            
            nIdx = pBe->DataLength(pCrsr)/sizeof(int);
            if( nIdx==1 ){
              aIdx = sqliteMalloc( sizeof(int)*4 );
              if( aIdx==0 ) goto no_mem;
              aIdx[0] = 2;
              pBe->CopyData(pCrsr, 0, sizeof(int), (char*)&aIdx[1]);
              aIdx[2] = newVal;
              pBe->Put(pCrsr, aStack[tos].n, zStack[tos],
                    sizeof(int)*4, (char*)aIdx);
              sqliteFree(aIdx);
            }else{
              aIdx = (int*)pBe->ReadData(pCrsr, 0);
              k = aIdx[0];
              if( k<nIdx-1 ){
                aIdx[k+1] = newVal;
                aIdx[0]++;
                pBe->Put(pCrsr, aStack[tos].n, zStack[tos],
                    sizeof(int)*nIdx, (char*)aIdx);
              }else{
                nIdx *= 2;
                aIdx = sqliteMalloc( sizeof(int)*nIdx );
                if( aIdx==0 ) goto no_mem;
                pBe->CopyData(pCrsr, 0, sizeof(int)*(k+1), (char*)aIdx);
                aIdx[k+1] = newVal;
                aIdx[0]++;
                pBe->Put(pCrsr, aStack[tos].n, zStack[tos],
                      sizeof(int)*nIdx, (char*)aIdx);
                sqliteFree(aIdx);
              }
            }              
          }
        }
        POPSTACK;







|


|







|




|

|



|




|





|


|







2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
        VERIFY( if( nos<0 ) goto not_enough_stack; )
        if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
          int r;
          int newVal;
          Integerify(p, nos);
          newVal = aStack[nos].i;
          if( Stringify(p, tos) ) goto no_mem;
          r = pBex->Fetch(pCrsr, aStack[tos].n, zStack[tos]);
          if( r==0 ){
            /* Create a new record for this index */
            pBex->Put(pCrsr, aStack[tos].n, zStack[tos],
                          sizeof(int), (char*)&newVal);
          }else{
            /* Extend the existing record */
            int nIdx;
            int *aIdx;
            int k;
            
            nIdx = pBex->DataLength(pCrsr)/sizeof(int);
            if( nIdx==1 ){
              aIdx = sqliteMalloc( sizeof(int)*4 );
              if( aIdx==0 ) goto no_mem;
              aIdx[0] = 2;
              pBex->CopyData(pCrsr, 0, sizeof(int), (char*)&aIdx[1]);
              aIdx[2] = newVal;
              pBex->Put(pCrsr, aStack[tos].n, zStack[tos],
                    sizeof(int)*4, (char*)aIdx);
              sqliteFree(aIdx);
            }else{
              aIdx = (int*)pBex->ReadData(pCrsr, 0);
              k = aIdx[0];
              if( k<nIdx-1 ){
                aIdx[k+1] = newVal;
                aIdx[0]++;
                pBex->Put(pCrsr, aStack[tos].n, zStack[tos],
                    sizeof(int)*nIdx, (char*)aIdx);
              }else{
                nIdx *= 2;
                aIdx = sqliteMalloc( sizeof(int)*nIdx );
                if( aIdx==0 ) goto no_mem;
                pBex->CopyData(pCrsr, 0, sizeof(int)*(k+1), (char*)aIdx);
                aIdx[k+1] = newVal;
                aIdx[0]++;
                pBex->Put(pCrsr, aStack[tos].n, zStack[tos],
                      sizeof(int)*nIdx, (char*)aIdx);
                sqliteFree(aIdx);
              }
            }              
          }
        }
        POPSTACK;
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
          int nIdx;
          int j, k;
          int r;
          int oldVal;
          Integerify(p, nos);
          oldVal = aStack[nos].i;
          if( Stringify(p, tos) ) goto no_mem;
          r = pBe->Fetch(pCrsr, aStack[tos].n, zStack[tos]);
          if( r==0 ) break;
          nIdx = pBe->DataLength(pCrsr)/sizeof(int);
          aIdx = (int*)pBe->ReadData(pCrsr, 0);
          if( (nIdx==1 && aIdx[0]==oldVal) || (aIdx[0]==1 && aIdx[1]==oldVal) ){
            pBe->Delete(pCrsr, aStack[tos].n, zStack[tos]);
          }else{
            k = aIdx[0];
            for(j=1; j<=k && aIdx[j]!=oldVal; j++){}
            if( j>k ) break;
            aIdx[j] = aIdx[k];
            aIdx[k] = 0;
            aIdx[0]--;
            if( aIdx[0]*3 + 1 < nIdx ){
              nIdx /= 2;
            }
            pBe->Put(pCrsr, aStack[tos].n, zStack[tos], 
                          sizeof(int)*nIdx, (char*)aIdx);
          }
        }
        POPSTACK;
        POPSTACK;
        break;
      }

      /* Opcode: Destroy * * P3
      **
      ** Drop the disk file whose name is P3.  All key/data pairs in
      ** the file are deleted and the file itself is removed
      ** from the disk.
      */
      case OP_Destroy: {
        pBe->DropTable(pBe, pOp->p3);
        break;
      }

      /* Opcode: Reorganize * * P3
      **
      ** Compress, optimize, and tidy up the GDBM file named by P3.
      */
      case OP_Reorganize: {
        pBe->ReorganizeTable(pBe, pOp->p3);
        break;
      }

      /* Opcode: ListOpen P1 * *
      **
      ** Open a file used for temporary storage of integer table keys.  P1
      ** will server as a handle to this temporary file for future







|

|
|

|










|















|








|







2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
          int nIdx;
          int j, k;
          int r;
          int oldVal;
          Integerify(p, nos);
          oldVal = aStack[nos].i;
          if( Stringify(p, tos) ) goto no_mem;
          r = pBex->Fetch(pCrsr, aStack[tos].n, zStack[tos]);
          if( r==0 ) break;
          nIdx = pBex->DataLength(pCrsr)/sizeof(int);
          aIdx = (int*)pBex->ReadData(pCrsr, 0);
          if( (nIdx==1 && aIdx[0]==oldVal) || (aIdx[0]==1 && aIdx[1]==oldVal) ){
            pBex->Delete(pCrsr, aStack[tos].n, zStack[tos]);
          }else{
            k = aIdx[0];
            for(j=1; j<=k && aIdx[j]!=oldVal; j++){}
            if( j>k ) break;
            aIdx[j] = aIdx[k];
            aIdx[k] = 0;
            aIdx[0]--;
            if( aIdx[0]*3 + 1 < nIdx ){
              nIdx /= 2;
            }
            pBex->Put(pCrsr, aStack[tos].n, zStack[tos], 
                          sizeof(int)*nIdx, (char*)aIdx);
          }
        }
        POPSTACK;
        POPSTACK;
        break;
      }

      /* Opcode: Destroy * * P3
      **
      ** Drop the disk file whose name is P3.  All key/data pairs in
      ** the file are deleted and the file itself is removed
      ** from the disk.
      */
      case OP_Destroy: {
        pBex->DropTable(pBe, pOp->p3);
        break;
      }

      /* Opcode: Reorganize * * P3
      **
      ** Compress, optimize, and tidy up the GDBM file named by P3.
      */
      case OP_Reorganize: {
        pBex->ReorganizeTable(pBe, pOp->p3);
        break;
      }

      /* Opcode: ListOpen P1 * *
      **
      ** Open a file used for temporary storage of integer table keys.  P1
      ** will server as a handle to this temporary file for future
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
        if( i>=p->nList ){
          int j;
          p->apList = sqliteRealloc( p->apList, (i+1)*sizeof(FILE*) );
          if( p->apList==0 ){ p->nList = 0; goto no_mem; }
          for(j=p->nList; j<=i; j++) p->apList[j] = 0;
          p->nList = i+1;
        }else if( p->apList[i] ){
          pBe->CloseTempFile(pBe, p->apList[i]);
        }
        rc = pBe->OpenTempFile(pBe, &p->apList[i]);
        if( rc!=SQLITE_OK ){
          sqliteSetString(pzErrMsg, "unable to open a temporary file", 0);
        }
        break;
      }

      /* Opcode: ListWrite P1 * *







|

|







2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
        if( i>=p->nList ){
          int j;
          p->apList = sqliteRealloc( p->apList, (i+1)*sizeof(FILE*) );
          if( p->apList==0 ){ p->nList = 0; goto no_mem; }
          for(j=p->nList; j<=i; j++) p->apList[j] = 0;
          p->nList = i+1;
        }else if( p->apList[i] ){
          pBex->CloseTempFile(pBe, p->apList[i]);
        }
        rc = pBex->OpenTempFile(pBe, &p->apList[i]);
        if( rc!=SQLITE_OK ){
          sqliteSetString(pzErrMsg, "unable to open a temporary file", 0);
        }
        break;
      }

      /* Opcode: ListWrite P1 * *
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
      **
      ** Close the temporary storage buffer and discard its contents.
      */
      case OP_ListClose: {
        int i = pOp->p1;
        VERIFY( if( i<0 ) goto bad_instruction; )
        if( VERIFY( i<p->nList && ) p->apList[i]!=0 ){
          pBe->CloseTempFile(pBe, p->apList[i]);
          p->apList[i] = 0;
        }
        break;
      }

      /* Opcode: SortOpen P1 * *
      **







|







2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
      **
      ** Close the temporary storage buffer and discard its contents.
      */
      case OP_ListClose: {
        int i = pOp->p1;
        VERIFY( if( i<0 ) goto bad_instruction; )
        if( VERIFY( i<p->nList && ) p->apList[i]!=0 ){
          pBex->CloseTempFile(pBe, p->apList[i]);
          p->apList[i] = 0;
        }
        break;
      }

      /* Opcode: SortOpen P1 * *
      **