1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

added DISTINCT on select (CVS 27)

FossilOrigin-Name: 1f0c4ffd98591e506201b6b0e6e60b9216ceb596
This commit is contained in:
drh
2000-05-31 20:00:52 +00:00
parent ec86adb88b
commit efb7251d6e
11 changed files with 316 additions and 178 deletions

View File

@@ -1,5 +1,5 @@
C :-)\s(CVS\s26)
D 2000-05-31T18:33:10
C added\sDISTINCT\son\sselect\s(CVS\s27)
D 2000-05-31T20:00:52
F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
F Makefile.in 7ac2fef265940d93a544cb454efa836451559a71
F README 6b5960603c7f8bf42fc022b4b6436f242f238dbb
@@ -7,23 +7,23 @@ F configure 00a5b5c82147a576fa6e82d7c1b0d55c321d6d2c x
F configure.in 6ccfd5fc80517f7cfe605a7fc7e0f62d962a233c
F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
F src/build.c 03f83e95d46e328a2ac08aace102b142ea38e6d7
F src/dbbe.c dc9439f839d13e633158808e352056b531f17e1b
F src/dbbe.h b678e31c32fa252e6fba830ad16ed8978d1521a9
F src/dbbe.c 80080f5ef2297e54797ee24f5951dab1c39af5d5
F src/dbbe.h 0147c9f8539d421d6c5558d3e854b78387372fae
F src/delete.c 16ef3418b19be9ab39db836c693970ca7bbff605
F src/expr.c 91970700e3e39b2b725b028c166f588a5bb0c038
F src/insert.c bd34716d0bba5561f6b55101adbf16fa75f872e8
F src/main.c 25cce7bce0eb3ba10bada7c05f4b38dc6dbbc86f
F src/parse.y 038e0f0fd243b89344c974c5d0552e85c4d27916
F src/select.c 719ca9605a351b2a3521a692ae8d2936d4832609
F src/parse.y 16322c46ec117082ef745715f7a4761f2491a0b2
F src/select.c 25cada7cb2b0b4973b3e17c81ba1b1c887829f71
F src/shell.c c5752d32cdeaa7d548d4f91177b697b023a00381
F src/sqlite.h 2397c17a8f4ca90c09acab0100dc7e2f8f441b69
F src/sqliteInt.h 81552acdedb0c3b256510a66c0f656d35d2ea2bd
F src/sqliteInt.h 04f38613a8ecedfdb15b21175acf0fe2ce55e299
F src/tclsqlite.c 9efd29f79ded6a900aa3d142169c8bfe03b7affd
F src/tokenize.c 5b066f314646d6c5396a253315e5e95d107e1800
F src/tokenize.c 15c229fee77325334c6814652e429b0930eba6c1
F src/update.c 9194f548dafc9884d79489874e22974ed67cd6a2
F src/util.c 6b4327d7fbf684f8635155d4acb847ae991b3ebc
F src/vdbe.c 11d8e4f6e25044ceace5e7a5c160b74b0537492c
F src/vdbe.h 02b470d344caed04451c896be7a775068dbdf076
F src/vdbe.c a60a9316f2ffbc020d5a9a73535b84e7f513e45d
F src/vdbe.h ab574c91c6328c5795f68b84074fbcf860eae70e
F src/where.c bed9a8360cbfbf712bdc397c8e22216a5e5f9800
F test/all.test 66a8a5b8291a472157944edcdce51a320ebd1f35
F test/copy.test 641bd3cfaab61c4ee32889587e21e4c70788a97a
@@ -43,9 +43,9 @@ F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
F www/c_interface.tcl f875864edf7974157d1c257ca08de854660882a5
F www/changes.tcl 995d64c96978a996f0e9e46f2ce896355a7c87a7
F www/index.tcl 600e85c207929bedb9c6fd221aa7875fd8f43edf
F www/index.tcl a94e31dc690f07b0dfdb82c5ab6315e4840a336d
F www/sqlite.tcl 7deb564df188ad4523adecfe2365de6d09f6dfd9
P 35a8f523e8389a1a6e41f6561500644b165d556e
R 7e04f378295246aef19c10676ba30bf8
P 0b7d9eb8ad771917c53587ea4d674f7e8d76121f
R 73a74ce4d5a10f11090cf328a18ab074
U drh
Z 23a52b4171f3850f1bc24517d67a8aa5
Z ef837be79fdfd30ace7832037467a189

View File

@@ -1 +1 @@
0b7d9eb8ad771917c53587ea4d674f7e8d76121f
1f0c4ffd98591e506201b6b0e6e60b9216ceb596

View File

@@ -30,7 +30,7 @@
** 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 $
** $Id: dbbe.c,v 1.4 2000/05/31 20:00:52 drh Exp $
*/
#include "sqliteInt.h"
#include <gdbm.h>
@@ -47,9 +47,20 @@ 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.
*/
@@ -59,6 +70,7 @@ struct Dbbe {
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 */
};
/*
@@ -74,6 +86,41 @@ struct DbbeTable {
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
@@ -105,6 +152,8 @@ Dbbe *sqliteDbbeOpen(
strcpy(pNew->zDir, zName);
pNew->write = write;
pNew->pOpen = 0;
time(&statbuf.st_ctime);
rc4init(&pNew->rc4, (char*)&statbuf, sizeof(statbuf));
return pNew;
}
@@ -144,6 +193,22 @@ static char *sqliteFileOfTable(Dbbe *pBe, const char *zTable){
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
*/
@@ -158,10 +223,15 @@ DbbeTable *sqliteDbbeOpenTable(
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 ){
@@ -176,7 +246,24 @@ DbbeTable *sqliteDbbeOpenTable(
}
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++;
@@ -240,6 +327,9 @@ void sqliteDbbeCloseTable(DbbeTable *pTable){
if( pFile->pNext ){
pFile->pNext->pPrev = pFile->pPrev;
}
if( pFile->delOnClose ){
unlink(pFile->zName);
}
sqliteFree(pFile->zName);
memset(pFile, 0, sizeof(*pFile));
sqliteFree(pFile);
@@ -275,6 +365,21 @@ int sqliteDbbeFetch(DbbeTable *pTable, int nKey, char *pKey){
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.
@@ -377,73 +482,22 @@ int sqliteDbbeNextKey(DbbeTable *pTable){
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;
struct rc4 *pRc4;
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;
pRc4 = &pTable->pBe->rc4;
while( go ){
iKey = 0;
for(i=0; i<4; i++){
iKey = (iKey<<8) + rc4byte();
iKey = (iKey<<8) + rc4byte(pRc4);
}
key.dptr = (char*)&iKey;
key.dsize = 4;
@@ -488,8 +542,9 @@ int sqliteDbbeDelete(DbbeTable *pTable, int nKey, char *pKey){
*/
FILE *sqliteDbbeOpenTempFile(Dbbe *pBe){
char *zFile;
char zBuf[30];
int i;
char zBuf[50];
int i, j;
int limit;
for(i=0; i<pBe->nTemp; i++){
if( pBe->apTemp[i]==0 ) break;
@@ -499,9 +554,13 @@ FILE *sqliteDbbeOpenTempFile(Dbbe *pBe){
pBe->apTemp = sqliteRealloc(pBe->apTemp, pBe->nTemp*sizeof(FILE*) );
}
if( pBe->apTemp==0 ) return 0;
sprintf(zBuf, "/_temp_%d~", i);
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];

View File

@@ -28,7 +28,7 @@
** 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 $
** $Id: dbbe.h,v 1.3 2000/05/31 20:00:52 drh Exp $
*/
#ifndef _SQLITE_DBBE_H_
#define _SQLITE_DBBE_H_
@@ -59,6 +59,9 @@ 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);
@@ -76,6 +79,11 @@ void sqliteDbbeCloseTable(DbbeTable*);
*/
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.

View File

@@ -26,7 +26,7 @@
** 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 $
** @(#) $Id: parse.y,v 1.6 2000/05/31 20:00:52 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -125,10 +125,15 @@ 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);}
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($$);}

View File

@@ -24,7 +24,7 @@
** 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 $
** $Id: select.c,v 1.3 2000/05/31 20:00:52 drh Exp $
*/
#include "sqliteInt.h"
@@ -37,7 +37,8 @@ void sqliteSelect(
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 */
ExprList *pOrderBy, /* The ORDER BY clause. May be NULL */
int distinct /* If true, only output distinct results */
){
int i, j;
WhereInfo *pWInfo;
@@ -121,6 +122,12 @@ void sqliteSelect(
pOrderBy = 0;
}
/* Turn off distinct if this is an aggregate
*/
if( isAgg ){
distinct = 0;
}
/* Begin generating code.
*/
v = pParse->pVdbe;
@@ -189,6 +196,10 @@ void sqliteSelect(
/* 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;
@@ -200,6 +211,19 @@ void sqliteSelect(
}
}
/* 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.

View File

@@ -23,7 +23,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.5 2000/05/31 15:34:53 drh Exp $
** @(#) $Id: sqliteInt.h,v 1.6 2000/05/31 20:00:52 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
@@ -249,7 +249,7 @@ 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 sqliteSelect(Parse*, ExprList*, IdList*, Expr*, ExprList*, int);
void sqliteDeleteFrom(Parse*, Token*, Expr*);
void sqliteUpdate(Parse*, Token*, ExprList*, Expr*);
WhereInfo *sqliteWhereBegin(Parse*, IdList*, Expr*, int);

View File

@@ -27,7 +27,7 @@
** 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 $
** $Id: tokenize.c,v 1.5 2000/05/31 20:00:53 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -61,6 +61,7 @@ static Keyword aKeywordTable[] = {
{ "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 },

View File

@@ -41,7 +41,7 @@
** 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 $
** $Id: vdbe.c,v 1.5 2000/05/31 20:00:53 drh Exp $
*/
#include "sqliteInt.h"
@@ -392,23 +392,23 @@ void sqliteVdbeDelete(Vdbe *p){
*/
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",
"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",
};
/*
@@ -1247,7 +1247,7 @@ int sqliteVdbeExec(
break;
}
/* Opcode: MakeKey P1 * *
/* 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
@@ -1256,6 +1256,11 @@ int sqliteVdbeExec(
** 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: {
@@ -1280,7 +1285,7 @@ int sqliteVdbeExec(
if( i<p->tos ) zNewKey[j++] = '\t';
}
zNewKey[j] = 0;
PopStack(p, nField);
if( pOp->p2==0 ) PopStack(p, nField);
NeedStack(p, p->tos+1);
p->tos++;
p->iStack[p->tos] = nByte;
@@ -1353,6 +1358,38 @@ int sqliteVdbeExec(
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

View File

@@ -27,7 +27,7 @@
** 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 $
** $Id: vdbe.h,v 1.4 2000/05/31 20:00:53 drh Exp $
*/
#ifndef _SQLITE_VDBE_H_
#define _SQLITE_VDBE_H_
@@ -76,83 +76,84 @@ typedef struct VdbeOp VdbeOp;
#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_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 11
#define OP_Reorganize 12
#define OP_Destroy 12
#define OP_Reorganize 13
#define OP_ResetIdx 13
#define OP_NextIdx 14
#define OP_PutIdx 15
#define OP_DeleteIdx 16
#define OP_ResetIdx 14
#define OP_NextIdx 15
#define OP_PutIdx 16
#define OP_DeleteIdx 17
#define OP_ListOpen 17
#define OP_ListWrite 18
#define OP_ListRewind 19
#define OP_ListRead 20
#define OP_ListClose 21
#define OP_ListOpen 18
#define OP_ListWrite 19
#define OP_ListRewind 20
#define OP_ListRead 21
#define OP_ListClose 22
#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_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 31
#define OP_FileRead 32
#define OP_FileField 33
#define OP_FileClose 34
#define OP_FileOpen 32
#define OP_FileRead 33
#define OP_FileField 34
#define OP_FileClose 35
#define OP_MakeRecord 35
#define OP_MakeKey 36
#define OP_MakeRecord 36
#define OP_MakeKey 37
#define OP_Goto 37
#define OP_If 38
#define OP_Halt 39
#define OP_Goto 38
#define OP_If 39
#define OP_Halt 40
#define OP_ColumnCount 40
#define OP_ColumnName 41
#define OP_Callback 42
#define OP_ColumnCount 41
#define OP_ColumnName 42
#define OP_Callback 43
#define OP_Integer 43
#define OP_String 44
#define OP_Pop 45
#define OP_Dup 46
#define OP_Pull 47
#define OP_Integer 44
#define OP_String 45
#define OP_Pop 46
#define OP_Dup 47
#define OP_Pull 48
#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_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 70
#define OP_MAX 71
/*
** Prototypes for the VDBE interface. See comments on the implementation

View File

@@ -1,7 +1,7 @@
#
# 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 $}
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>
@@ -119,6 +119,9 @@ puts {<h2>Related Sites</h2>
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 {