]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
added DISTINCT on select (CVS 27)
authordrh <drh@noemail.net>
Wed, 31 May 2000 20:00:52 +0000 (20:00 +0000)
committerdrh <drh@noemail.net>
Wed, 31 May 2000 20:00:52 +0000 (20:00 +0000)
FossilOrigin-Name: 1f0c4ffd98591e506201b6b0e6e60b9216ceb596

manifest
manifest.uuid
src/dbbe.c
src/dbbe.h
src/parse.y
src/select.c
src/sqliteInt.h
src/tokenize.c
src/vdbe.c
src/vdbe.h
www/index.tcl

index 152225a4904594ac555490088b416851535f56fb..79a3d1eb2df9b0dee1db21b2e78b6f4595b1f496 100644 (file)
--- a/manifest
+++ b/manifest
@@ -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
index dcd9fbc3e83bff059b3f3a123e46c9e654bb024f..30c7fcabd8b699ad6613de34cd3a6c046793af77 100644 (file)
@@ -1 +1 @@
-0b7d9eb8ad771917c53587ea4d674f7e8d76121f
\ No newline at end of file
+1f0c4ffd98591e506201b6b0e6e60b9216ceb596
\ No newline at end of file
index 0e96bf85e67c7d877f068bda50beeae431d276b2..edbdccf2f2d52abb57caae55c3fb22b0906a3684 100644 (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,9 +223,14 @@ DbbeTable *sqliteDbbeOpenTable(
 
   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( 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) );
@@ -176,7 +246,24 @@ DbbeTable *sqliteDbbeOpenTable(
     }
     pFile->pNext = pBe->pOpen;
     pBe->pOpen = pFile;
-    pFile->dbf = gdbm_open(pFile->zName, 0, GDBM_WRCREAT|GDBM_FAST, 0640, 0);
+    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;
-  sqliteSetString(&zFile, pBe->zDir, zBuf, 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];
index c9f424d498acc582bcfc405a038e6764c8c9014d..b5e36011d6dd8c1fe7d49683350f79738e20d9aa 100644 (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.
index 556b92e05a06f03557750b6522128799314f9e19..7ae7dbf7d2f4cb0eb5f7cc27acf0cace3748f52a 100644 (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($$);}
index c0722f00e5262ef6ed2f3609e74de810643a127f..52e4d30d8da249f4c679d278554bdd94ef8d6ece 100644 (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;
@@ -188,7 +195,11 @@ 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;
 
@@ -199,6 +210,19 @@ void sqliteSelect(
       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
index 2c1491d8d39d4f5bf4149f9703ba3da915516485..0dd8ef82518a9cc0f1bf2df2d734de7010d1b399 100644 (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);
index d47476ff7b826b741598c7bece8eebbaf7f137a3..76e0b7a17a6883684e807d8513ee2ff55b5384bc 100644 (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 },
index 195210a30dbab9c7ec7aad64daaed128d7c52495..a4883a8cb7520b78adfde6a130ed7da8ac8e337c 100644 (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
index 3672cfee35fb99578780efd3d51059474c3211e0..9a01412a10454388b1fb070297363556c7e828ad 100644 (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_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
+#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
index 93bf168cf864a6f58c97aa2382f5c96dfa164b84..15f31b8f55e409e09227b5922c18369dab8a369f 100644 (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 {