/ Check-in [1f0c4ffd]
Login

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

Overview
Comment:added DISTINCT on select (CVS 27)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1f0c4ffd98591e506201b6b0e6e60b9216ceb596
User & Date: drh 2000-05-31 20:00:52
Context
2000-05-31
21:06
:-) (CVS 28) check-in: 57c5add1 user: drh tags: trunk
20:00
added DISTINCT on select (CVS 27) check-in: 1f0c4ffd user: drh tags: trunk
18:33
:-) (CVS 26) check-in: 0b7d9eb8 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/dbbe.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
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
...
101
102
103
104
105
106
107


108
109
110
111
112
113
114
...
139
140
141
142
143
144
145
















146
147
148
149
150
151
152
...
154
155
156
157
158
159
160

161
162
163




164
165
166
167
168
169
170
...
172
173
174
175
176
177
178

179
















180
181
182
183
184
185
186
...
235
236
237
238
239
240
241



242
243
244
245
246
247
248
...
270
271
272
273
274
275
276















277
278
279
280
281
282
283
...
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
431
432
433
434
435
436
437
438
439
440
441
442

443
444
445
446
447
448
449
450
451
452
453
...
484
485
486
487
488
489
490
491
492

493
494
495
496
497
498
499
500
501
502
503



504

505
506
507
508
509
510
511
** 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.3 2000/05/31 02:27:49 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
................................................................................
** Each open database file is an instance of this structure.
*/
typedef struct BeFile BeFile;
struct BeFile {
  char *zName;            /* Name of the file */
  GDBM_FILE dbf;          /* The file itself */
  int nRef;               /* Number of references */

  BeFile *pNext, *pPrev;  /* Next and previous on list of open files */
};











/*
** The complete database is an instance of the following structure.
*/
struct Dbbe {
  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 */

};

/*
** Each file within the database is an instance of this
** structure.
*/
struct DbbeTable {
................................................................................
  Dbbe *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 */
};




































/*
** This routine opens a new database.  For the current driver scheme,
** the database name is the name of the directory
** containing all the files of the database.
*/
Dbbe *sqliteDbbeOpen(
................................................................................
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }
  pNew->zDir = (char*)&pNew[1];
  strcpy(pNew->zDir, zName);
  pNew->write = write;
  pNew->pOpen = 0;


  return pNew;
}

/*
** Completely shutdown the given database.  Close all files.  Free all memory.
*/
void sqliteDbbeClose(Dbbe *pBe){
................................................................................
      zFile[i] = tolower(c);
    }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){
      zFile[i] = '+';
    }
  }
  return zFile;
}

















/*
** Open a new table cursor
*/
DbbeTable *sqliteDbbeOpenTable(
  Dbbe *pBe,              /* The database the table belongs to */
  const char *zTable,     /* The name of the table */
................................................................................
){
  char *zFile;            /* Name of the table file */
  DbbeTable *pTable;      /* The new table cursor */
  BeFile *pFile;          /* The underlying data file for this table */

  pTable = sqliteMalloc( sizeof(*pTable) );
  if( pTable==0 ) return 0;

  zFile = sqliteFileOfTable(pBe, zTable);
  for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){
    if( strcmp(pFile->zName,zFile)==0 ) break;




  }
  if( pFile==0 ){
    pFile = sqliteMalloc( sizeof(*pFile) );
    if( pFile==0 ){
      sqliteFree(zFile);
      return 0;
    }
................................................................................
    pFile->nRef = 1;
    pFile->pPrev = 0;
    if( pBe->pOpen ){
      pBe->pOpen->pPrev = pFile;
    }
    pFile->pNext = pBe->pOpen;
    pBe->pOpen = pFile;

    pFile->dbf = gdbm_open(pFile->zName, 0, GDBM_WRCREAT|GDBM_FAST, 0640, 0);
















  }else{
    sqliteFree(zFile);
    pFile->nRef++;
  }
  pTable->pBe = pBe;
  pTable->pFile = pFile;
  pTable->readPending = 0;
................................................................................
    if( pFile->pPrev ){
      pFile->pPrev->pNext = pFile->pNext;
    }else{
      pBe->pOpen = pFile->pNext;
    }
    if( pFile->pNext ){
      pFile->pNext->pPrev = pFile->pPrev;



    }
    sqliteFree(pFile->zName);
    memset(pFile, 0, sizeof(*pFile));
    sqliteFree(pFile);
  }
  if( pTable->key.dptr ) free(pTable->key.dptr);
  if( pTable->data.dptr ) free(pTable->data.dptr);
................................................................................
  datumClear(&pTable->key);
  datumClear(&pTable->data);
  if( pTable->pFile && pTable->pFile->dbf ){
    pTable->data = gdbm_fetch(pTable->pFile->dbf, key);
  }
  return pTable->data.dptr!=0;
}
















/*
** Copy bytes from the current key or data into a buffer supplied by
** the calling function.  Return the number of bytes copied.
*/
int sqliteDbbeCopyKey(DbbeTable *pTable, int offset, int size, char *zBuf){
  int n;
................................................................................
    pTable->needRewind = 1;
    pTable->readPending = 0;
    rc = 0;
  }
  return rc;
}

/*
** The following are state variables for the RC4 algorithm.  We
** use RC4 as a random number generator.  Each call to RC4 gives
** a random 8-bit number.
*/
static struct {
  int i, j;
  int s[256];
} rc4;

/*
** Initialize the RC4 algorithm.
*/
static void rc4init(char *key, int keylen){
  int i;
  char k[256];
  rc4.j = 0;
  rc4.i = 0;
  for(i=0; i<256; i++){
    rc4.s[i] = i;
    k[i] = key[i%keylen];
  }
  for(i=0; i<256; i++){
    int t;
    rc4.j = (rc4.j + rc4.s[i] + k[i]) & 0xff;
    t = rc4.s[rc4.j];
    rc4.s[rc4.j] = rc4.s[i];
    rc4.s[i] = t;
  }
}

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

/*
** Get a new integer key.
*/
int sqliteDbbeNew(DbbeTable *pTable){
  static int isInit = 0;
  int iKey;
  datum key;
  int go = 1;
  int i;

  if( !isInit ){
    struct stat statbuf;
    stat(pTable->pFile->zName, &statbuf);
    time(&statbuf.st_ctime);
    rc4init((char*)&statbuf, sizeof(statbuf));
    isInit = 1;
  }
  if( pTable->pFile==0 || pTable->pFile->dbf==0 ) return 1;

  while( go ){
    iKey = 0;
    for(i=0; i<4; i++){
      iKey = (iKey<<8) + rc4byte();
    }
    key.dptr = (char*)&iKey;
    key.dsize = 4;
    go = gdbm_exists(pTable->pFile->dbf, key);
  }
  return iKey;
}   
................................................................................
}

/*
** Open a temporary file.
*/
FILE *sqliteDbbeOpenTempFile(Dbbe *pBe){
  char *zFile;
  char zBuf[30];
  int i;


  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*) );
  }
  if( pBe->apTemp==0 ) return 0;
  sprintf(zBuf, "/_temp_%d~", i);
  zFile = 0;



  sqliteSetString(&zFile, pBe->zDir, zBuf, 0);

  pBe->apTemp[i] = fopen(zFile, "w+");
  sqliteFree(zFile);
  return pBe->apTemp[i];
}

/*
** Close a temporary file opened using sqliteDbbeOpenTempFile()







|







 







>


>
>
>
>
>
>
>
>
>
>










>







 







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







 







>
>







 







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







 







>
|
|
|
>
>
>
>







 







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







 







>
>
>







 







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







 








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



<




<
<
|
<
<
<
<
|

>



|







 







|
|
>









|

>
>
>
|
>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
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
128
129
...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
...
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
...
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
...
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
...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
...
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
...
478
479
480
481
482
483
484
485













































486
487
488

489
490
491
492


493




494
495
496
497
498
499
500
501
502
503
504
505
506
507
...
538
539
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
** 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.4 2000/05/31 20:00:52 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include <time.h>
................................................................................
** Each open database file is an instance of this structure.
*/
typedef struct BeFile BeFile;
struct BeFile {
  char *zName;            /* Name of the file */
  GDBM_FILE dbf;          /* The file itself */
  int nRef;               /* Number of references */
  int delOnClose;         /* Delete when closing */
  BeFile *pNext, *pPrev;  /* Next and previous on list of open files */
};

/*
** The following are state variables for the RC4 algorithm.  We
** use RC4 as a random number generator.  Each call to RC4 gives
** a random 8-bit number.
*/
struct rc4 {
  int i, j;
  int s[256];
};

/*
** The complete database is an instance of the following structure.
*/
struct Dbbe {
  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 */
  struct rc4 rc4;    /* The random number generator */
};

/*
** Each file within the database is an instance of this
** structure.
*/
struct DbbeTable {
................................................................................
  Dbbe *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 algorithm.
*/
static void rc4init(struct rc4 *p, char *key, int keylen){
  int i;
  char k[256];
  p->j = 0;
  p->i = 0;
  for(i=0; i<256; i++){
    p->s[i] = i;
    k[i] = key[i%keylen];
  }
  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 algorithm.
*/
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;
}

/*
** This routine opens a new database.  For the current driver scheme,
** the database name is the name of the directory
** containing all the files of the database.
*/
Dbbe *sqliteDbbeOpen(
................................................................................
    sqliteSetString(pzErrMsg, "out of memory", 0);
    return 0;
  }
  pNew->zDir = (char*)&pNew[1];
  strcpy(pNew->zDir, zName);
  pNew->write = write;
  pNew->pOpen = 0;
  time(&statbuf.st_ctime);
  rc4init(&pNew->rc4, (char*)&statbuf, sizeof(statbuf));
  return pNew;
}

/*
** Completely shutdown the given database.  Close all files.  Free all memory.
*/
void sqliteDbbeClose(Dbbe *pBe){
................................................................................
      zFile[i] = tolower(c);
    }else if( !isalnum(c) && c!='-' && c!='_' && c!='.' ){
      zFile[i] = '+';
    }
  }
  return zFile;
}

/*
** Generate a random filename with the given prefix.
*/
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) & 0x7f) % (sizeof(zRandomChars) - 1);
    zBuf[j++] = zRandomChars[c];
  }
  zBuf[j] = 0;
}


/*
** Open a new table cursor
*/
DbbeTable *sqliteDbbeOpenTable(
  Dbbe *pBe,              /* The database the table belongs to */
  const char *zTable,     /* The name of the table */
................................................................................
){
  char *zFile;            /* Name of the table file */
  DbbeTable *pTable;      /* The new table cursor */
  BeFile *pFile;          /* The underlying data file for this table */

  pTable = sqliteMalloc( sizeof(*pTable) );
  if( pTable==0 ) return 0;
  if( zTable ){
    zFile = sqliteFileOfTable(pBe, zTable);
    for(pFile=pBe->pOpen; pFile; pFile=pFile->pNext){
      if( strcmp(pFile->zName,zFile)==0 ) break;
    }
  }else{
    pFile = 0;
    zFile = 0;
  }
  if( pFile==0 ){
    pFile = sqliteMalloc( sizeof(*pFile) );
    if( pFile==0 ){
      sqliteFree(zFile);
      return 0;
    }
................................................................................
    pFile->nRef = 1;
    pFile->pPrev = 0;
    if( pBe->pOpen ){
      pBe->pOpen->pPrev = pFile;
    }
    pFile->pNext = pBe->pOpen;
    pBe->pOpen = pFile;
    if( pFile->zName ){
      pFile->dbf = gdbm_open(pFile->zName, 0, GDBM_WRCREAT|GDBM_FAST, 0640, 0);
    }else{
      int i, j, 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, GDBM_WRCREAT|GDBM_FAST, 0640, 0);
      }while( pFile->dbf==0 && limit-- >= 0);
      pFile->zName = zFile;
      pFile->delOnClose = 1;
    }
  }else{
    sqliteFree(zFile);
    pFile->nRef++;
  }
  pTable->pBe = pBe;
  pTable->pFile = pFile;
  pTable->readPending = 0;
................................................................................
    if( pFile->pPrev ){
      pFile->pPrev->pNext = pFile->pNext;
    }else{
      pBe->pOpen = pFile->pNext;
    }
    if( pFile->pNext ){
      pFile->pNext->pPrev = pFile->pPrev;
    }
    if( pFile->delOnClose ){
      unlink(pFile->zName);
    }
    sqliteFree(pFile->zName);
    memset(pFile, 0, sizeof(*pFile));
    sqliteFree(pFile);
  }
  if( pTable->key.dptr ) free(pTable->key.dptr);
  if( pTable->data.dptr ) free(pTable->data.dptr);
................................................................................
  datumClear(&pTable->key);
  datumClear(&pTable->data);
  if( pTable->pFile && pTable->pFile->dbf ){
    pTable->data = gdbm_fetch(pTable->pFile->dbf, key);
  }
  return pTable->data.dptr!=0;
}

/*
** Return 1 if the given key is already in the table.  Return 0
** if it is not.
*/
int sqliteDbbeTest(DbbeTable *pTable, int nKey, char *pKey){
  datum key;
  int result = 0;
  key.dsize = nKey;
  key.dptr = pKey;
  if( pTable->pFile && pTable->pFile->dbf ){
    result = gdbm_exists(pTable->pFile->dbf, key);
  }
  return result;
}

/*
** Copy bytes from the current key or data into a buffer supplied by
** the calling function.  Return the number of bytes copied.
*/
int sqliteDbbeCopyKey(DbbeTable *pTable, int offset, int size, char *zBuf){
  int n;
................................................................................
    pTable->needRewind = 1;
    pTable->readPending = 0;
    rc = 0;
  }
  return rc;
}

/*













































** Get a new integer key.
*/
int sqliteDbbeNew(DbbeTable *pTable){

  int iKey;
  datum key;
  int go = 1;
  int i;


  struct rc4 *pRc4;





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

/*
** Open a temporary file.
*/
FILE *sqliteDbbeOpenTempFile(Dbbe *pBe){
  char *zFile;
  char zBuf[50];
  int i, j;
  int limit;

  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*) );
  }
  if( pBe->apTemp==0 ) return 0;
  limit = 4;
  zFile = 0;
  do{
    randomName(&pBe->rc4, zBuf, "/_temp_file_");
    sqliteFree(zFile);
    sqliteSetString(&zFile, pBe->zDir, zBuf, 0);
  }while( access(zFile,0) && limit-- >= 0 );
  pBe->apTemp[i] = fopen(zFile, "w+");
  sqliteFree(zFile);
  return pBe->apTemp[i];
}

/*
** Close a temporary file opened using sqliteDbbeOpenTempFile()

Changes to src/dbbe.h.

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
55
56
57
58
59
60
61



62
63
64
65
66
67
68
..
71
72
73
74
75
76
77





78
79
80
81
82
83
84
** 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.2 2000/05/31 02:27:49 drh Exp $
*/
#ifndef _SQLITE_DBBE_H_
#define _SQLITE_DBBE_H_
#include <stdio.h>

/*
** The database backend supports two opaque structures.  A Dbbe is
................................................................................
Dbbe *sqliteDbbeOpen(const char *zName, int write, int create, char **pzErr);

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

/* Open a particular table of a previously opened database.
** Create the table if it doesn't already exist and writeable!=0.



*/
DbbeTable *sqliteDbbeOpenTable(Dbbe*, const char *zTableName, int writeable);

/* Delete a table from the database */
void sqliteDbbeDropTable(Dbbe*, const char *zTableName);

/* Reorganize a table to speed access or reduce its disk usage */
................................................................................
/* Close a table */
void sqliteDbbeCloseTable(DbbeTable*);

/* Fetch an entry from a table with the given key.  Return 1 if
** successful and 0 if no such entry exists.
*/
int sqliteDbbeFetch(DbbeTable*, int nKey, char *pKey);






/* Retrieve the key or data used for the last fetch.  Only size
** bytes are read beginning with the offset-th byte.  The return
** value is the actual number of bytes read.
*/
int sqliteDbbeCopyKey(DbbeTable*, int offset, int size, char *zBuf);
int sqliteDbbeCopyData(DbbeTable*, int offset, int size, char *zBuf);







|







 







>
>
>







 







>
>
>
>
>







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
** 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.3 2000/05/31 20:00:52 drh Exp $
*/
#ifndef _SQLITE_DBBE_H_
#define _SQLITE_DBBE_H_
#include <stdio.h>

/*
** The database backend supports two opaque structures.  A Dbbe is
................................................................................
Dbbe *sqliteDbbeOpen(const char *zName, int write, int create, char **pzErr);

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

/* Open a particular table of a previously opened database.
** Create the table if it doesn't already exist and writeable!=0.
**
** If zTableName is 0 or "", then a temporary table is created that
** will be deleted when closed.
*/
DbbeTable *sqliteDbbeOpenTable(Dbbe*, const char *zTableName, int writeable);

/* Delete a table from the database */
void sqliteDbbeDropTable(Dbbe*, const char *zTableName);

/* Reorganize a table to speed access or reduce its disk usage */
................................................................................
/* Close a table */
void sqliteDbbeCloseTable(DbbeTable*);

/* Fetch an entry from a table with the given key.  Return 1 if
** successful and 0 if no such entry exists.
*/
int sqliteDbbeFetch(DbbeTable*, int nKey, char *pKey);

/* Return 1 if the given key is already in the table.  Return 0
** if it is not.
*/
int sqliteDbbeTest(DbbeTable*, int nKey, char *pKey);

/* Retrieve the key or data used for the last fetch.  Only size
** bytes are read beginning with the offset-th byte.  The return
** value is the actual number of bytes read.
*/
int sqliteDbbeCopyKey(DbbeTable*, int offset, int size, char *zBuf);
int sqliteDbbeCopyData(DbbeTable*, int offset, int size, char *zBuf);

Changes to src/parse.y.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
...
121
122
123
124
125
126
127
128
129
130
131





132
133
134
135
136
137
138
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.5 2000/05/31 18:20:14 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
  sqliteSetNString(&pParse->zErrMsg,"syntax error near \"",0,TOKEN.z,TOKEN.n,
                   "\"", 1, 0);
................................................................................
// The next command format is dropping tables.
//
cmd ::= DROP TABLE id(X).          {sqliteDropTable(pParse,&X);}

// The select statement
//
cmd ::= select.
select ::= SELECT selcollist(W) from(X) where_opt(Y) orderby_opt(Z).
     {sqliteSelect(pParse, W, X, Y, Z);}
select ::= SELECT STAR from(X) where_opt(Y) orderby_opt(Z).
     {sqliteSelect(pParse, 0, X, Y, Z);}






%type selcollist {ExprList*}
%destructor selcollist {sqliteExprListDelete($$);}
%type sclp {ExprList*}
%destructor sclp {sqliteExprListDelete($$);}

sclp(A) ::= selcollist(X) COMMA.             {A = X;}







|







 







|
|
|
|
>
>
>
>
>







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.6 2000/05/31 20:00:52 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
  sqliteSetNString(&pParse->zErrMsg,"syntax error near \"",0,TOKEN.z,TOKEN.n,
                   "\"", 1, 0);
................................................................................
// The next command format is dropping tables.
//
cmd ::= DROP TABLE id(X).          {sqliteDropTable(pParse,&X);}

// The select statement
//
cmd ::= select.
select ::= SELECT distinct(D) selcollist(W) from(X) where_opt(Y) orderby_opt(Z).
     {sqliteSelect(pParse, W, X, Y, Z, D);}
select ::= SELECT distinct(D) STAR from(X) where_opt(Y) orderby_opt(Z).
     {sqliteSelect(pParse, 0, X, Y, Z, D);}

%type distinct {int}

distinct(A) ::= DISTINCT.   {A = 1;}
distinct(A) ::= .           {A = 0;}

%type selcollist {ExprList*}
%destructor selcollist {sqliteExprListDelete($$);}
%type sclp {ExprList*}
%destructor sclp {sqliteExprListDelete($$);}

sclp(A) ::= selcollist(X) COMMA.             {A = X;}

Changes to src/select.c.

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
...
116
117
118
119
120
121
122






123
124
125
126
127
128
129
...
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
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements.
**
** $Id: select.c,v 1.2 2000/05/31 18:20:14 drh Exp $
*/
#include "sqliteInt.h"


/*
** Process a SELECT statement.
*/
void sqliteSelect(
  Parse *pParse,         /* The parser context */
  ExprList *pEList,      /* List of fields to extract.  NULL means "*" */
  IdList *pTabList,      /* List of tables to select from */
  Expr *pWhere,          /* The WHERE clause.  May be NULL */
  ExprList *pOrderBy     /* The ORDER BY clause.  May be NULL */

){
  int i, j;
  WhereInfo *pWInfo;
  Vdbe *v;
  int isAgg = 0;         /* True for select lists like "count(*)" */

  if( pParse->nErr>0 ) goto select_cleanup;
................................................................................
  /* ORDER BY is ignored if this is an aggregate query like count(*)
  ** since only one row will be returned.
  */
  if( isAgg && pOrderBy ){
    sqliteExprListDelete(pOrderBy);
    pOrderBy = 0;
  }







  /* Begin generating code.
  */
  v = pParse->pVdbe;
  if( v==0 ){
    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
  }
................................................................................
          break;
        }
      }
    }
  }

  /* Begin the database scan
  */  




  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
  if( pWInfo==0 ) goto select_cleanup;

  /* Pull the requested fields.
  */
  if( !isAgg ){
    for(i=0; i<pEList->nExpr; i++){
      sqliteExprCode(pParse, pEList->a[i].pExpr);
    }
  }













  
  /* If there is no ORDER BY clause, then we can invoke the callback
  ** right away.  If there is an ORDER BY, then we need to put the
  ** data into an appropriate sorter record.
  */
  if( pOrderBy ){
    char *zSortOrder;







|












|
>







 







>
>
>
>
>
>







 







|
>
>
>
>










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







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
...
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
...
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
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** This file contains C code routines that are called by the parser
** to handle SELECT statements.
**
** $Id: select.c,v 1.3 2000/05/31 20:00:52 drh Exp $
*/
#include "sqliteInt.h"


/*
** Process a SELECT statement.
*/
void sqliteSelect(
  Parse *pParse,         /* The parser context */
  ExprList *pEList,      /* List of fields to extract.  NULL means "*" */
  IdList *pTabList,      /* List of tables to select from */
  Expr *pWhere,          /* The WHERE clause.  May be NULL */
  ExprList *pOrderBy,    /* The ORDER BY clause.  May be NULL */
  int distinct           /* If true, only output distinct results */
){
  int i, j;
  WhereInfo *pWInfo;
  Vdbe *v;
  int isAgg = 0;         /* True for select lists like "count(*)" */

  if( pParse->nErr>0 ) goto select_cleanup;
................................................................................
  /* ORDER BY is ignored if this is an aggregate query like count(*)
  ** since only one row will be returned.
  */
  if( isAgg && pOrderBy ){
    sqliteExprListDelete(pOrderBy);
    pOrderBy = 0;
  }

  /* Turn off distinct if this is an aggregate
  */
  if( isAgg ){
    distinct = 0;
  }

  /* Begin generating code.
  */
  v = pParse->pVdbe;
  if( v==0 ){
    v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
  }
................................................................................
          break;
        }
      }
    }
  }

  /* Begin the database scan
  */
  if( distinct ){
    distinct = pTabList->nId*2+1;
    sqliteVdbeAddOp(v, OP_Open, distinct, 0, 0, 0);
  }
  pWInfo = sqliteWhereBegin(pParse, pTabList, pWhere, 0);
  if( pWInfo==0 ) goto select_cleanup;

  /* Pull the requested fields.
  */
  if( !isAgg ){
    for(i=0; i<pEList->nExpr; i++){
      sqliteExprCode(pParse, pEList->a[i].pExpr);
    }
  }

  /* If the current result is not distinct, script the remainder
  ** of this processing.
  */
  if( distinct ){
    int isDistinct = sqliteVdbeMakeLabel(v);
    sqliteVdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1, 0, 0);
    sqliteVdbeAddOp(v, OP_Distinct, distinct, isDistinct, 0, 0);
    sqliteVdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0, 0, 0);
    sqliteVdbeAddOp(v, OP_Goto, 0, pWInfo->iContinue, 0, 0);
    sqliteVdbeAddOp(v, OP_String, 0, 0, "", isDistinct);
    sqliteVdbeAddOp(v, OP_Put, distinct, 0, 0, 0);
  }
  
  /* If there is no ORDER BY clause, then we can invoke the callback
  ** right away.  If there is an ORDER BY, then we need to put the
  ** data into an appropriate sorter record.
  */
  if( pOrderBy ){
    char *zSortOrder;

Changes to src/sqliteInt.h.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.5 2000/05/31 15:34:53 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>
................................................................................
void sqliteDeleteTable(sqlite*, Table*);
void sqliteInsert(Parse*, Token*, ExprList*, IdList*);
IdList *sqliteIdListAppend(IdList*, Token*);
void sqliteIdListAddAlias(IdList*, Token*);
void sqliteIdListDelete(IdList*);
void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, Token*, Token*);
void sqliteDropIndex(Parse*, Token*);
void sqliteSelect(Parse*, ExprList*, IdList*, Expr*, ExprList*);
void sqliteDeleteFrom(Parse*, Token*, Expr*);
void sqliteUpdate(Parse*, Token*, ExprList*, Expr*);
WhereInfo *sqliteWhereBegin(Parse*, IdList*, Expr*, int);
void sqliteWhereEnd(WhereInfo*);
void sqliteExprCode(Parse*, Expr*);
void sqliteExprIfTrue(Parse*, Expr*, int);
void sqliteExprIfFalse(Parse*, Expr*, int);







|







 







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
...
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.6 2000/05/31 20:00:52 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>
................................................................................
void sqliteDeleteTable(sqlite*, Table*);
void sqliteInsert(Parse*, Token*, ExprList*, IdList*);
IdList *sqliteIdListAppend(IdList*, Token*);
void sqliteIdListAddAlias(IdList*, Token*);
void sqliteIdListDelete(IdList*);
void sqliteCreateIndex(Parse*, Token*, Token*, IdList*, Token*, Token*);
void sqliteDropIndex(Parse*, Token*);
void sqliteSelect(Parse*, ExprList*, IdList*, Expr*, ExprList*, int);
void sqliteDeleteFrom(Parse*, Token*, Expr*);
void sqliteUpdate(Parse*, Token*, ExprList*, Expr*);
WhereInfo *sqliteWhereBegin(Parse*, IdList*, Expr*, int);
void sqliteWhereEnd(WhereInfo*);
void sqliteExprCode(Parse*, Expr*);
void sqliteExprIfTrue(Parse*, Expr*, int);
void sqliteExprIfFalse(Parse*, Expr*, int);

Changes to src/tokenize.c.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
57
58
59
60
61
62
63

64
65
66
67
68
69
70
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.4 2000/05/31 02:27:49 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include <stdlib.h>

/*
** All the keywords of the SQL language are stored as in a hash
................................................................................
  { "CONSTRAINT",        0, TK_CONSTRAINT,       0 },
  { "COPY",              0, TK_COPY,             0 },
  { "CREATE",            0, TK_CREATE,           0 },
  { "DEFAULT",           0, TK_DEFAULT,          0 },
  { "DELETE",            0, TK_DELETE,           0 },
  { "DELIMITERS",        0, TK_DELIMITERS,       0 },
  { "DESC",              0, TK_DESC,             0 },

  { "DROP",              0, TK_DROP,             0 },
  { "EXPLAIN",           0, TK_EXPLAIN,          0 },
  { "FROM",              0, TK_FROM,             0 },
  { "GLOB",              0, TK_GLOB,             0 },
  { "INDEX",             0, TK_INDEX,            0 },
  { "INSERT",            0, TK_INSERT,           0 },
  { "INTO",              0, TK_INTO,             0 },







|







 







>







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
*************************************************************************
** An tokenizer for SQL
**
** This file contains C code that splits an SQL input string up into
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
** $Id: tokenize.c,v 1.5 2000/05/31 20:00:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
#include <stdlib.h>

/*
** All the keywords of the SQL language are stored as in a hash
................................................................................
  { "CONSTRAINT",        0, TK_CONSTRAINT,       0 },
  { "COPY",              0, TK_COPY,             0 },
  { "CREATE",            0, TK_CREATE,           0 },
  { "DEFAULT",           0, TK_DEFAULT,          0 },
  { "DELETE",            0, TK_DELETE,           0 },
  { "DELIMITERS",        0, TK_DELIMITERS,       0 },
  { "DESC",              0, TK_DESC,             0 },
  { "DISTINCT",          0, TK_DISTINCT,         0 },
  { "DROP",              0, TK_DROP,             0 },
  { "EXPLAIN",           0, TK_EXPLAIN,          0 },
  { "FROM",              0, TK_FROM,             0 },
  { "GLOB",              0, TK_GLOB,             0 },
  { "INDEX",             0, TK_INDEX,            0 },
  { "INSERT",            0, TK_INSERT,           0 },
  { "INTO",              0, TK_INTO,             0 },

Changes to src/vdbe.c.

37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
...
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
....
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257





1258
1259
1260
1261
1262
1263
1264
....
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
....
1348
1349
1350
1351
1352
1353
1354
































1355
1356
1357
1358
1359
1360
1361
** 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.4 2000/05/31 15:34:53 drh Exp $
*/
#include "sqliteInt.h"

/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine.  Each instruction is an instance
** of the following structure.
................................................................................
** If any of the numeric OP_ values for opcodes defined in sqliteVdbe.h
** change, be sure to change this array to match.  You can use the
** "opNames.awk" awk script which is part of the source tree to regenerate
** this array, then copy and paste it into this file, if you want.
*/
static char *zOpName[] = { 0,
  "Open",           "Close",          "Fetch",          "New",
  "Put",            "Delete",         "Field",          "Key",
  "Rewind",         "Next",           "Destroy",        "Reorganize",
  "ResetIdx",       "NextIdx",        "PutIdx",         "DeleteIdx",
  "ListOpen",       "ListWrite",      "ListRewind",     "ListRead",
  "ListClose",      "SortOpen",       "SortPut",        "SortMakeRec",
  "SortMakeKey",    "Sort",           "SortNext",       "SortKey",
  "SortCallback",   "SortClose",      "FileOpen",       "FileRead",
  "FileField",      "FileClose",      "MakeRecord",     "MakeKey",
  "Goto",           "If",             "Halt",           "ColumnCount",
  "ColumnName",     "Callback",       "Integer",        "String",
  "Pop",            "Dup",            "Pull",           "Add",
  "AddImm",         "Subtract",       "Multiply",       "Divide",
  "Min",            "Max",            "Like",           "Glob",
  "Eq",             "Ne",             "Lt",             "Le",
  "Gt",             "Ge",             "IsNull",         "NotNull",
  "Negative",       "And",            "Or",             "Not",
  "Concat",         "Noop",         
};

/*
** Given the name of an opcode, return its number.  Return 0 if
** there is no match.
**
** This routine is used for testing and debugging.
................................................................................
        NeedStack(p, p->tos+1);
        p->tos++;
        p->iStack[p->tos] = nByte;
        p->zStack[p->tos] = zNewRecord;
        break;
      }

      /* Opcode: MakeKey P1 * *
      **
      ** Convert the top P1 entries of the stack into a single entry suitable
      ** for use as the key in an index or a sort.  The top P1 records are
      ** concatenated with a tab character (ASCII 0x09) used as a record
      ** separator.  The entire concatenation is null-terminated.  The
      ** lowest entry in the stack is the first field and the top of the
      ** stack becomes the last.





      **
      ** See also the SortMakeKey opcode.
      */
      case OP_MakeKey: {
        char *zNewKey;
        int nByte;
        int nField;
................................................................................
        j = 0;
        for(i=p->tos-nField+1; i<=p->tos; i++){
          memcpy(&zNewKey[j], p->zStack[i], p->iStack[i]-1);
          j += p->iStack[i]-1;
          if( i<p->tos ) zNewKey[j++] = '\t';
        }
        zNewKey[j] = 0;
        PopStack(p, nField);
        NeedStack(p, p->tos+1);
        p->tos++;
        p->iStack[p->tos] = nByte;
        p->zStack[p->tos] = zNewKey;
        break;
      }

................................................................................
          }else{
            sqliteDbbeFetch(p->aTab[i].pTable, p->iStack[tos], p->zStack[tos]);
          }
        }
        PopStack(p, 1);
        break;
      }

































      /* Opcode: New P1 * *
      **
      ** Get a new integer key not previous used by table P1 and
      ** push it onto the stack.
      */
      case OP_New: {







|







 







|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|







 







|







>
>
>
>
>







 







|







 







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







37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
...
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
....
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
....
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
....
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
** 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.5 2000/05/31 20:00:53 drh Exp $
*/
#include "sqliteInt.h"

/*
** SQL is translated into a sequence of instructions to be
** executed by a virtual machine.  Each instruction is an instance
** of the following structure.
................................................................................
** If any of the numeric OP_ values for opcodes defined in sqliteVdbe.h
** change, be sure to change this array to match.  You can use the
** "opNames.awk" awk script which is part of the source tree to regenerate
** this array, then copy and paste it into this file, if you want.
*/
static char *zOpName[] = { 0,
  "Open",           "Close",          "Fetch",          "New",
  "Put",            "Distinct",       "Delete",         "Field",
  "Key",            "Rewind",         "Next",           "Destroy",
  "Reorganize",     "ResetIdx",       "NextIdx",        "PutIdx",
  "DeleteIdx",      "ListOpen",       "ListWrite",      "ListRewind",
  "ListRead",       "ListClose",      "SortOpen",       "SortPut",
  "SortMakeRec",    "SortMakeKey",    "Sort",           "SortNext",
  "SortKey",        "SortCallback",   "SortClose",      "FileOpen",
  "FileRead",       "FileField",      "FileClose",      "MakeRecord",
  "MakeKey",        "Goto",           "If",             "Halt",
  "ColumnCount",    "ColumnName",     "Callback",       "Integer",
  "String",         "Pop",            "Dup",            "Pull",
  "Add",            "AddImm",         "Subtract",       "Multiply",
  "Divide",         "Min",            "Max",            "Like",
  "Glob",           "Eq",             "Ne",             "Lt",
  "Le",             "Gt",             "Ge",             "IsNull",
  "NotNull",        "Negative",       "And",            "Or",
  "Not",            "Concat",         "Noop",         
};

/*
** Given the name of an opcode, return its number.  Return 0 if
** there is no match.
**
** This routine is used for testing and debugging.
................................................................................
        NeedStack(p, p->tos+1);
        p->tos++;
        p->iStack[p->tos] = nByte;
        p->zStack[p->tos] = zNewRecord;
        break;
      }

      /* Opcode: MakeKey P1 P2 *
      **
      ** Convert the top P1 entries of the stack into a single entry suitable
      ** for use as the key in an index or a sort.  The top P1 records are
      ** concatenated with a tab character (ASCII 0x09) used as a record
      ** separator.  The entire concatenation is null-terminated.  The
      ** lowest entry in the stack is the first field and the top of the
      ** stack becomes the last.
      **
      ** If P2 is not zero, then the original entries remain on the stack
      ** and the new key is pushed on top.  If P2 is zero, the original
      ** data is popped off the stack first then the new key is pushed
      ** back in its place.
      **
      ** See also the SortMakeKey opcode.
      */
      case OP_MakeKey: {
        char *zNewKey;
        int nByte;
        int nField;
................................................................................
        j = 0;
        for(i=p->tos-nField+1; i<=p->tos; i++){
          memcpy(&zNewKey[j], p->zStack[i], p->iStack[i]-1);
          j += p->iStack[i]-1;
          if( i<p->tos ) zNewKey[j++] = '\t';
        }
        zNewKey[j] = 0;
        if( pOp->p2==0 ) PopStack(p, nField);
        NeedStack(p, p->tos+1);
        p->tos++;
        p->iStack[p->tos] = nByte;
        p->zStack[p->tos] = zNewKey;
        break;
      }

................................................................................
          }else{
            sqliteDbbeFetch(p->aTab[i].pTable, p->iStack[tos], p->zStack[tos]);
          }
        }
        PopStack(p, 1);
        break;
      }

      /* Opcode: Distinct P1 P2 *
      **
      ** Use the top of the stack as a key.  If a record with that key
      ** does not exist in table P1, then jump to P2.  If the record
      ** does already exist, then fall thru.  The record is not retrieved.
      ** The key is not popped from the stack.
      */
      case OP_Distinct: {
        int i = pOp->p1;
        int tos = p->tos;
        int alreadyExists = 0;
        if( tos<0 ) goto not_enough_stack;
        if( i>=0 && i<p->nTable && p->aTab[i].pTable ){
          if( p->zStack[tos]==0 ){
            alreadyExists = sqliteDbbeTest(p->aTab[i].pTable, sizeof(int), 
                                          (char*)&p->iStack[tos]);
          }else{
            alreadyExists = sqliteDbbeTest(p->aTab[i].pTable, p->iStack[tos], 
                                           p->zStack[tos]);
          }
        }
        if( !alreadyExists ){
          pc = pOp->p2;
          if( pc<0 || pc>p->nOp ){
            sqliteSetString(pzErrMsg, "jump destination out of range", 0);
            rc = 1;
          }
          pc--;
        }
        break;
      }

      /* Opcode: New P1 * *
      **
      ** Get a new integer key not previous used by table P1 and
      ** push it onto the stack.
      */
      case OP_New: {

Changes to src/vdbe.h.

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
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
152
153
154
155
156
157
158
159
160
161
162
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.3 2000/05/31 02:27:50 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
** can be used to renumber these opcodes when new opcodes are inserted.
*/
#define OP_Open                1
#define OP_Close               2
#define OP_Fetch               3
#define OP_New                 4
#define OP_Put                 5

#define OP_Delete              6
#define OP_Field               7
#define OP_Key                 8
#define OP_Rewind              9
#define OP_Next               10

#define OP_Destroy            11
#define OP_Reorganize         12

#define OP_ResetIdx           13
#define OP_NextIdx            14
#define OP_PutIdx             15
#define OP_DeleteIdx          16

#define OP_ListOpen           17
#define OP_ListWrite          18
#define OP_ListRewind         19
#define OP_ListRead           20
#define OP_ListClose          21

#define OP_SortOpen           22
#define OP_SortPut            23
#define OP_SortMakeRec        24
#define OP_SortMakeKey        25
#define OP_Sort               26
#define OP_SortNext           27
#define OP_SortKey            28
#define OP_SortCallback       29
#define OP_SortClose          30

#define OP_FileOpen           31
#define OP_FileRead           32
#define OP_FileField          33
#define OP_FileClose          34

#define OP_MakeRecord         35
#define OP_MakeKey            36

#define OP_Goto               37
#define OP_If                 38
#define OP_Halt               39

#define OP_ColumnCount        40
#define OP_ColumnName         41
#define OP_Callback           42

#define OP_Integer            43
#define OP_String             44
#define OP_Pop                45
#define OP_Dup                46
#define OP_Pull               47

#define OP_Add                48
#define OP_AddImm             49
#define OP_Subtract           50
#define OP_Multiply           51
#define OP_Divide             52
#define OP_Min                53
#define OP_Max                54
#define OP_Like               55
#define OP_Glob               56
#define OP_Eq                 57
#define OP_Ne                 58
#define OP_Lt                 59
#define OP_Le                 60
#define OP_Gt                 61
#define OP_Ge                 62
#define OP_IsNull             63
#define OP_NotNull            64
#define OP_Negative           65
#define OP_And                66
#define OP_Or                 67
#define OP_Not                68
#define OP_Concat             69
#define OP_Noop               70

#define OP_MAX                70

/*
** Prototypes for the VDBE interface.  See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqliteVdbeCreate(Dbbe*);
int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);







|







 







>
|
|
|
|
|

|
|

|
|
|
|

|
|
|
|
|

|
|
|
|
|
|
|
|
|

|
|
|
|

|
|

|
|
|

|
|
|

|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
..
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
152
153
154
155
156
157
158
159
160
161
162
163
*************************************************************************
** Header file for the Virtual DataBase Engine (VDBE)
**
** This header defines the interface to the virtual database engine
** or VDBE.  The VDBE implements an abstract machine that runs a
** simple program to access and modify the underlying database.
**
** $Id: vdbe.h,v 1.4 2000/05/31 20:00:53 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
#include <stdio.h>

/*
** A single VDBE is an opaque structure named "Vdbe".  Only routines
................................................................................
** can be used to renumber these opcodes when new opcodes are inserted.
*/
#define OP_Open                1
#define OP_Close               2
#define OP_Fetch               3
#define OP_New                 4
#define OP_Put                 5
#define OP_Distinct            6
#define OP_Delete              7
#define OP_Field               8
#define OP_Key                 9
#define OP_Rewind             10
#define OP_Next               11

#define OP_Destroy            12
#define OP_Reorganize         13

#define OP_ResetIdx           14
#define OP_NextIdx            15
#define OP_PutIdx             16
#define OP_DeleteIdx          17

#define OP_ListOpen           18
#define OP_ListWrite          19
#define OP_ListRewind         20
#define OP_ListRead           21
#define OP_ListClose          22

#define OP_SortOpen           23
#define OP_SortPut            24
#define OP_SortMakeRec        25
#define OP_SortMakeKey        26
#define OP_Sort               27
#define OP_SortNext           28
#define OP_SortKey            29
#define OP_SortCallback       30
#define OP_SortClose          31

#define OP_FileOpen           32
#define OP_FileRead           33
#define OP_FileField          34
#define OP_FileClose          35

#define OP_MakeRecord         36
#define OP_MakeKey            37

#define OP_Goto               38
#define OP_If                 39
#define OP_Halt               40

#define OP_ColumnCount        41
#define OP_ColumnName         42
#define OP_Callback           43

#define OP_Integer            44
#define OP_String             45
#define OP_Pop                46
#define OP_Dup                47
#define OP_Pull               48

#define OP_Add                49
#define OP_AddImm             50
#define OP_Subtract           51
#define OP_Multiply           52
#define OP_Divide             53
#define OP_Min                54
#define OP_Max                55
#define OP_Like               56
#define OP_Glob               57
#define OP_Eq                 58
#define OP_Ne                 59
#define OP_Lt                 60
#define OP_Le                 61
#define OP_Gt                 62
#define OP_Ge                 63
#define OP_IsNull             64
#define OP_NotNull            65
#define OP_Negative           66
#define OP_And                67
#define OP_Or                 68
#define OP_Not                69
#define OP_Concat             70
#define OP_Noop               71

#define OP_MAX                71

/*
** Prototypes for the VDBE interface.  See comments on the implementation
** for a description of what each of these routines does.
*/
Vdbe *sqliteVdbeCreate(Dbbe*);
int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);

Changes to www/index.tcl.

1
2
3
4
5
6
7
8
9
10
11
...
115
116
117
118
119
120
121



122
123
124
125
126
127
128
129
130
131
#
# Run this TCL script to generate HTML for the index.html file.
#
set rcsid {$Id: index.tcl,v 1.6 2000/05/31 15:34:54 drh Exp $}

puts {<html>
<head><title>SQLite: An SQL Frontend For GDBM</title></head>
<body bgcolor=white>
<h1 align=center>SQLite: An SQL Frontend For GDBM</h1>
<p align=center>}
puts "Last modified [lrange $rcsid 3 4] GMT"
................................................................................
       http://www.gnu.org/software/gdbm/gdbm.html</a></p></li>

<li><p>Someday, we would like to port SQLite to work with
       the Berkeley DB library in addition to GDBM.  For information
       about the Berkeley DB library, see
       <a href="http://www.sleepcat.com/">http://www.sleepycat.com</a>
       </p></li>



</ul>}

puts {
<p><hr /></p>
<p>
<a href="../index.html"><img src="/goback.jpg" border=0 />
More Open Source Software</a> from Hwaci.
</p>

</body></html>}



|







 







>
>
>










1
2
3
4
5
6
7
8
9
10
11
...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#
# Run this TCL script to generate HTML for the index.html file.
#
set rcsid {$Id: index.tcl,v 1.7 2000/05/31 20:00:53 drh Exp $}

puts {<html>
<head><title>SQLite: An SQL Frontend For GDBM</title></head>
<body bgcolor=white>
<h1 align=center>SQLite: An SQL Frontend For GDBM</h1>
<p align=center>}
puts "Last modified [lrange $rcsid 3 4] GMT"
................................................................................
       http://www.gnu.org/software/gdbm/gdbm.html</a></p></li>

<li><p>Someday, we would like to port SQLite to work with
       the Berkeley DB library in addition to GDBM.  For information
       about the Berkeley DB library, see
       <a href="http://www.sleepcat.com/">http://www.sleepycat.com</a>
       </p></li>

<li><p>Here is a <a href="http://w3.one.net/~jhoffman/sqltut.htm">
       tutorial on SQL</a>.</p></li>
</ul>}

puts {
<p><hr /></p>
<p>
<a href="../index.html"><img src="/goback.jpg" border=0 />
More Open Source Software</a> from Hwaci.
</p>

</body></html>}