:-) (CVS 20)

FossilOrigin-Name: 01d85b35e9c4ca5619ad21a4232a8f8bf9ec3538
diff --git a/Makefile.in b/Makefile.in
index ab446b1..8c27799 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -145,6 +145,9 @@
 c_interface.html:	$(TOP)/www/c_interface.tcl
 	tclsh $(TOP)/www/c_interface.tcl >c_interface.html
 
+changes.html:	$(TOP)/www/changes.tcl
+	tclsh $(TOP)/www/changes.tcl >changes.html
+
 # Files to be published on the website.
 #
 PUBLISH = \
@@ -152,6 +155,7 @@
   all.tar.gz \
   index.html \
   sqlite.html \
+  changes.html \
   c_interface.html
 
 website:	$(PUBLISH)
diff --git a/manifest b/manifest
index f65555f..e1a4a8a 100644
--- a/manifest
+++ b/manifest
@@ -1,25 +1,25 @@
-C :-)\s(CVS\s19)
-D 2000-05-30T20:17:49
+C :-)\s(CVS\s20)
+D 2000-05-31T02:27:49
 F COPYRIGHT 74a8a6531a42e124df07ab5599aad63870fa0bd4
-F Makefile.in 89921c1ee4de75275bfadfbac198396da31704d1
+F Makefile.in dd79c78825935c5711ce45c372b0ac0f194b6d43
 F README 6b5960603c7f8bf42fc022b4b6436f242f238dbb
 F configure 00a5b5c82147a576fa6e82d7c1b0d55c321d6d2c x
 F configure.in 6ccfd5fc80517f7cfe605a7fc7e0f62d962a233c
 F doc/lemon.html e233a3e97a779c7a87e1bc4528c664a58e49dd47
-F src/build.c 335df4b65f49d335438d3a0cd7e48d19713a1917
-F src/dbbe.c 159c39f8bf5475c34904786fad4f3f0f579d9eb6
-F src/dbbe.h bedeb3a0985bb584458e7849fb59927e99e751e6
+F src/build.c c6b500077913cde55871d1f9c0d17d4ee4a86828
+F src/dbbe.c dc9439f839d13e633158808e352056b531f17e1b
+F src/dbbe.h b678e31c32fa252e6fba830ad16ed8978d1521a9
 F src/main.c 25cce7bce0eb3ba10bada7c05f4b38dc6dbbc86f
-F src/parse.y 50ca06d471132e16bb47c56f19553e4efd5b3d4a
-F src/shell.c 3ffa9059514cd4db3bd64e0797bf7ebbe1ea8ee3
+F src/parse.y 05de7dec046dd8bd11f8cc3513ff8b27624618c8
+F src/shell.c c5752d32cdeaa7d548d4f91177b697b023a00381
 F src/sqlite.h 2397c17a8f4ca90c09acab0100dc7e2f8f441b69
-F src/sqliteInt.h 749da8b3e4ce146fd172aeb59b6db04c57726d7a
+F src/sqliteInt.h 9ac3f9e05bbc5913531473c86d4742343ae670c5
 F src/tclsqlite.c 9efd29f79ded6a900aa3d142169c8bfe03b7affd
-F src/tokenize.c e176b2c1c38e11482ee3419d6b50b733860a1587
-F src/util.c 2a0314dcc9de230526380765339071a5b304d70d
-F src/vdbe.c 117ce5541143e3af9dccdc15c22c4920a7b9bdb4
-F src/vdbe.h 03de26632f2e608c2a44a40262fbba21a8bdfd81
-F src/where.c 2c8de69c4cf5a620ed380d3d6bb658bbbe8da5d5
+F src/tokenize.c 5b066f314646d6c5396a253315e5e95d107e1800
+F src/util.c 6b4327d7fbf684f8635155d4acb847ae991b3ebc
+F src/vdbe.c 74ff55bc2910e25bd811638233f6c02fb1a17fbc
+F src/vdbe.h 02b470d344caed04451c896be7a775068dbdf076
+F src/where.c fd9faea693083c1bde83f824b98f7eb81c4762cc
 F test/all.test 66a8a5b8291a472157944edcdce51a320ebd1f35
 F test/copy.test 641bd3cfaab61c4ee32889587e21e4c70788a97a
 F test/delete.test 814d53e3b0d2d7069fb17e005d4041454d6585d4
@@ -36,9 +36,10 @@
 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
 F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
 F www/c_interface.tcl f875864edf7974157d1c257ca08de854660882a5
-F www/index.tcl 2466d1b2e26c6f354b0acedee12025309a216799
-F www/sqlite.tcl 947e067bcc347dc767af4c1a6e5a8d47d8404aa3
-P 2d41caec807a6ab83b67e59c849ebbda004f2869
-R d274f71e9bf0807a8f2c186fb0e9f965
+F www/changes.tcl 38ff869ccbf99388d53abd08aeea4e24e2bb23b7
+F www/index.tcl 57a97afafe04ab53d1996ba3a61ac41fa8453f5a
+F www/sqlite.tcl 7deb564df188ad4523adecfe2365de6d09f6dfd9
+P 03725ce5ae871247789ece0f2c3426f74ba575e7
+R bab7f299b23f92a0096c17a89a463018
 U drh
-Z 1247bb7c9fa8cc79296726f95e563a76
+Z e30b944ebaee88defeb667112902d5c8
diff --git a/manifest.uuid b/manifest.uuid
index e900404..1b7f2df 100644
--- a/manifest.uuid
+++ b/manifest.uuid
@@ -1 +1 @@
-03725ce5ae871247789ece0f2c3426f74ba575e7
\ No newline at end of file
+01d85b35e9c4ca5619ad21a4232a8f8bf9ec3538
\ No newline at end of file
diff --git a/src/build.c b/src/build.c
index 4b29cc1..fd0aaee 100644
--- a/src/build.c
+++ b/src/build.c
@@ -24,7 +24,7 @@
 ** This file contains C code routines that are called by the parser
 ** when syntax rules are reduced.
 **
-** $Id: build.c,v 1.9 2000/05/30 19:22:26 drh Exp $
+** $Id: build.c,v 1.10 2000/05/31 02:27:49 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -1528,3 +1528,46 @@
 copy_cleanup:
   return;
 }
+
+/*
+** The non-standard VACUUM command is used to clean up the database,
+** collapse free space, etc.  It is modelled after the VACUUM command
+** in PostgreSQL.
+*/
+void sqliteVacuum(Parse *pParse, Token *pTableName){
+  char *zName;
+  Vdbe *v;
+
+  if( pTableName ){
+    zName = sqliteTableNameFromToken(pTableName);
+  }else{
+    zName = 0;
+  }
+  if( zName && sqliteFindIndex(pParse->db, zName)==0
+    && sqliteFindTable(pParse->db, zName)==0 ){
+    sqliteSetString(&pParse->zErrMsg, "no such table or index: ", zName, 0);
+    pParse->nErr++;
+    goto vacuum_cleanup;
+  }
+  v = pParse->pVdbe = sqliteVdbeCreate(pParse->db->pBe);
+  if( v==0 ) goto vacuum_cleanup;
+  if( zName ){
+    sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, zName, 0);
+  }else{
+    int h;
+    Table *pTab;
+    Index *pIdx;
+    for(h=0; h<N_HASH; h++){
+      for(pTab=pParse->db->apTblHash[h]; pTab; pTab=pTab->pHash){
+        sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, pTab->zName, 0);
+        for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+          sqliteVdbeAddOp(v, OP_Reorganize, 0, 0, pIdx->zName, 0);
+        }
+      }
+    }
+  }
+
+vacuum_cleanup:
+  sqliteFree(zName);
+  return;
+}
diff --git a/src/dbbe.c b/src/dbbe.c
index 51cf86b..0e96bf8 100644
--- a/src/dbbe.c
+++ b/src/dbbe.c
@@ -30,7 +30,7 @@
 ** relatively simple to convert to a different database such
 ** as NDBM, SDBM, or BerkeleyDB.
 **
-** $Id: dbbe.c,v 1.2 2000/05/30 18:45:24 drh Exp $
+** $Id: dbbe.c,v 1.3 2000/05/31 02:27:49 drh Exp $
 */
 #include "sqliteInt.h"
 #include <gdbm.h>
@@ -200,6 +200,22 @@
 }
 
 /*
+** Reorganize a table to reduce search times and disk usage.
+*/
+void sqliteDbbeReorganizeTable(Dbbe *pBe, const char *zTable){
+  char *zFile;            /* Name of the table file */
+  DbbeTable *pTab;
+
+  pTab = sqliteDbbeOpenTable(pBe, zTable, 1);
+  if( pTab && pTab->pFile && pTab->pFile->dbf ){
+    gdbm_reorganize(pTab->pFile->dbf);
+  }
+  if( pTab ){
+    sqliteDbbeCloseTable(pTab);
+  }
+}
+
+/*
 ** Close a table previously opened by sqliteDbbeOpenTable().
 */
 void sqliteDbbeCloseTable(DbbeTable *pTable){
diff --git a/src/dbbe.h b/src/dbbe.h
index 26e83a6..c9f424d 100644
--- a/src/dbbe.h
+++ b/src/dbbe.h
@@ -28,7 +28,7 @@
 ** This library was originally designed to support the following
 ** backends: GDBM, NDBM, SDBM, Berkeley DB.
 **
-** $Id: dbbe.h,v 1.1 2000/05/29 14:26:01 drh Exp $
+** $Id: dbbe.h,v 1.2 2000/05/31 02:27:49 drh Exp $
 */
 #ifndef _SQLITE_DBBE_H_
 #define _SQLITE_DBBE_H_
@@ -65,6 +65,9 @@
 /* Delete a table from the database */
 void sqliteDbbeDropTable(Dbbe*, const char *zTableName);
 
+/* Reorganize a table to speed access or reduce its disk usage */
+void sqliteDbbeReorganizeTable(Dbbe*, const char *zTableName);
+
 /* Close a table */
 void sqliteDbbeCloseTable(DbbeTable*);
 
diff --git a/src/parse.y b/src/parse.y
index 7b58846..89d0035 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -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.2 2000/05/30 16:27:04 drh Exp $
+** @(#) $Id: parse.y,v 1.3 2000/05/31 02:27:49 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -236,7 +236,7 @@
 
 %left OR.
 %left AND.
-%left EQ NE ISNULL NOTNULL IS.
+%left EQ NE ISNULL NOTNULL IS LIKE GLOB.
 %left GT GE LT LE.
 %left PLUS MINUS.
 %left STAR SLASH PERCENT.
@@ -264,7 +264,9 @@
 expr(A) ::= expr(X) GE expr(Y).    {A = sqliteExpr(TK_GE, X, Y, 0);}
 expr(A) ::= expr(X) NE expr(Y).    {A = sqliteExpr(TK_NE, X, Y, 0);}
 expr(A) ::= expr(X) EQ expr(Y).    {A = sqliteExpr(TK_EQ, X, Y, 0);}
-expr(A) ::= expr(X) IS expr(Y).    {A = sqliteExpr(TK_EQ, X, Y, 0);}
+expr(A) ::= expr(X) LIKE expr(Y).  {A = sqliteExpr(TK_LIKE, X, Y, 0);}
+expr(A) ::= expr(X) GLOB expr(Y).   {A = sqliteExpr(TK_GLOB,X,Y,0);}
+// expr(A) ::= expr(X) IS expr(Y).    {A = sqliteExpr(TK_EQ, X, Y, 0);}
 expr(A) ::= expr(X) PLUS expr(Y).  {A = sqliteExpr(TK_PLUS, X, Y, 0);}
 expr(A) ::= expr(X) MINUS expr(Y). {A = sqliteExpr(TK_MINUS, X, Y, 0);}
 expr(A) ::= expr(X) STAR expr(Y).  {A = sqliteExpr(TK_STAR, X, Y, 0);}
@@ -309,3 +311,6 @@
     {sqliteCopy(pParse,&X,&Y,&Z);}
 cmd ::= COPY id(X) FROM id(Y).
     {sqliteCopy(pParse,&X,&Y,0);}
+
+cmd ::= VACUUM.                {sqliteVacuum(pParse,0);}
+cmd ::= VACUUM id(X).          {sqliteVacuum(pParse,&X);}
diff --git a/src/shell.c b/src/shell.c
index b044ad4..4cc8a30 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -24,7 +24,7 @@
 ** This file contains code to implement the "sqlite" command line
 ** utility for accessing SQLite databases.
 **
-** $Id: shell.c,v 1.3 2000/05/30 18:45:24 drh Exp $
+** $Id: shell.c,v 1.4 2000/05/31 02:27:49 drh Exp $
 */
 #include <stdlib.h>
 #include <string.h>
@@ -300,7 +300,7 @@
     data.showHeader = 0;
     data.mode = MODE_List;
     sprintf(zSql, "SELECT name FROM sqlite_master "
-                  "WHERE type='index' AND tbl_name='%.00s' "
+                  "WHERE type='index' AND tbl_name LIKE '%.00s' "
                   "ORDER BY name", azArg[1]);
     sqlite_exec(db, zSql, callback, &data, &zErrMsg);
     if( zErrMsg ){
@@ -343,7 +343,7 @@
     data.showHeader = 0;
     data.mode = MODE_List;
     if( nArg>1 ){
-      sprintf(zSql, "SELECT sql FROM sqlite_master WHERE name='%.900s'",
+      sprintf(zSql, "SELECT sql FROM sqlite_master WHERE name LIKE '%.900s'",
          azArg[1]);
     }else{
       sprintf(zSql, "SELECT sql FROM sqlite_master "
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 7bbabff..c64a147 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -23,7 +23,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.3 2000/05/30 16:27:04 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.4 2000/05/31 02:27:49 drh Exp $
 */
 #include "sqlite.h"
 #include "dbbe.h"
@@ -248,3 +248,6 @@
 void sqliteExprIfFalse(Parse*, Expr*, int);
 Table *sqliteFindTable(sqlite*,char*);
 void sqliteCopy(Parse*, Token*, Token*, Token*);
+void sqliteVacuum(Parse*, Token*);
+int sqliteGlobCompare(const char*,const char*);
+int sqliteLikeCompare(const unsigned char*,const unsigned char*);
diff --git a/src/tokenize.c b/src/tokenize.c
index ac062d0..d47476f 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -27,7 +27,7 @@
 ** individual tokens and sends those tokens one-by-one over to the
 ** parser for analysis.
 **
-** $Id: tokenize.c,v 1.3 2000/05/30 16:27:04 drh Exp $
+** $Id: tokenize.c,v 1.4 2000/05/31 02:27:49 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -64,12 +64,14 @@
   { "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 },
   { "IS",                0, TK_IS,               0 },
   { "ISNULL",            0, TK_ISNULL,           0 },
   { "KEY",               0, TK_KEY,              0 },
+  { "LIKE",              0, TK_LIKE,             0 },
   { "NOT",               0, TK_NOT,              0 },
   { "NOTNULL",           0, TK_NOTNULL,          0 },
   { "NULL",              0, TK_NULL,             0 },
@@ -83,6 +85,7 @@
   { "UNIQUE",            0, TK_UNIQUE,           0 },
   { "UPDATE",            0, TK_UPDATE,           0 },
   { "USING",             0, TK_USING,            0 },
+  { "VACUUM",            0, TK_VACUUM,           0 },
   { "VALUES",            0, TK_VALUES,           0 },
   { "WHERE",             0, TK_WHERE,            0 },
 };
diff --git a/src/util.c b/src/util.c
index 1c59ad7..b5bf19c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -26,7 +26,7 @@
 ** This file contains functions for allocating memory, comparing
 ** strings, and stuff like that.
 **
-** $Id: util.c,v 1.6 2000/05/30 16:27:04 drh Exp $
+** $Id: util.c,v 1.7 2000/05/31 02:27:49 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -563,3 +563,138 @@
   if( *a=='-' ) res = -res;
   return res;
 }
+
+/*
+** Compare two strings for equality where the first string can
+** potentially be a "glob" expression.  Return true (1) if they
+** are the same and false (0) if they are different.
+**
+** Globbing rules:
+**
+**      '*'       Matches any sequence of zero or more characters.
+**
+**      '?'       Matches exactly one character.
+**
+**     [...]      Matches one character from the enclosed list of
+**                characters.
+**
+**     [^...]     Matches one character not in the enclosed list.
+**
+** With the [...] and [^...] matching, a ']' character can be included
+** in the list by making it the first character after '[' or '^'.  A
+** range of characters can be specified using '-'.  Example:
+** "[a-z]" matches any single lower-case letter.  To match a '-', make
+** it the last character in the list.
+**
+** This routine is usually quick, but can be N**2 in the worst case.
+**
+** Hints: to match '*' or '?', put them in "[]".  Like this:
+**
+**         abc[*]xyz        Matches "abc*xyz" only
+*/
+int sqliteGlobCompare(const char *zPattern, const char *zString){
+  register char c;
+  int invert;
+  int seen;
+  char c2;
+
+  while( (c = *zPattern)!=0 ){
+    switch( c ){
+      case '*':
+        while( zPattern[1]=='*' ) zPattern++;
+        if( zPattern[1]==0 ) return 1;
+        c = zPattern[1];
+        if( c=='[' || c=='?' ){
+          while( *zString && sqliteGlobCompare(&zPattern[1],zString)==0 ){
+            zString++;
+          }
+          return *zString!=0;
+        }else{
+          while( (c2 = *zString)!=0 ){
+            while( c2 != 0 && c2 != c ){ c2 = *++zString; }
+            if( sqliteGlobCompare(&zPattern[1],zString) ) return 1;
+            zString++;
+          }
+          return 0;
+        }
+      case '?':
+        if( *zString==0 ) return 0;
+        break;
+      case '[':
+        seen = 0;
+        invert = 0;
+        c = *zString;
+        if( c==0 ) return 0;
+        c2 = *++zPattern;
+        if( c2=='^' ){ invert = 1; c2 = *++zPattern; }
+        if( c2==']' ){
+          if( c==']' ) seen = 1;
+          c2 = *++zPattern;
+        }
+        while( (c2 = *zPattern)!=0 && c2!=']' ){
+          if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 ){
+            if( c>zPattern[-1] && c<zPattern[1] ) seen = 1;
+          }else if( c==c2 ){
+            seen = 1;
+          }
+          zPattern++;
+        }
+        if( c2==0 || (seen ^ invert)==0 ) return 0;
+        break;
+      default:
+        if( c != *zString ) return 0;
+        break;
+    }
+    zPattern++;
+    zString++;
+  }
+  return *zString==0;
+}
+
+/*
+** Compare two strings for equality using the "LIKE" operator of
+** SQL.  The '%' character matches any sequence of 0 or more
+** characters and '_' matches any single character.  Case is
+** not significant.
+**
+** This routine is just an adaptation of the sqliteGlobCompare()
+** routine above.
+*/
+int 
+sqliteLikeCompare(const unsigned char *zPattern, const unsigned char *zString){
+  register char c;
+  int invert;
+  int seen;
+  char c2;
+
+  while( (c = UpperToLower[*zPattern])!=0 ){
+    switch( c ){
+      case '%':
+        while( zPattern[1]=='%' ) zPattern++;
+        if( zPattern[1]==0 ) return 1;
+        c = UpperToLower[0xff & zPattern[1]];
+        if( c=='_' ){
+          while( *zString && sqliteLikeCompare(&zPattern[1],zString)==0 ){
+            zString++;
+          }
+          return *zString!=0;
+        }else{
+          while( (c2 = UpperToLower[*zString])!=0 ){
+            while( c2 != 0 && c2 != c ){ c2 = UpperToLower[*++zString]; }
+            if( sqliteLikeCompare(&zPattern[1],zString) ) return 1;
+            zString++;
+          }
+          return 0;
+        }
+      case '_':
+        if( *zString==0 ) return 0;
+        break;
+      default:
+        if( c != UpperToLower[*zString] ) return 0;
+        break;
+    }
+    zPattern++;
+    zString++;
+  }
+  return *zString==0;
+}
diff --git a/src/vdbe.c b/src/vdbe.c
index de87f96..62ed2e9 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -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.2 2000/05/30 16:27:04 drh Exp $
+** $Id: vdbe.c,v 1.3 2000/05/31 02:27:50 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -391,23 +391,24 @@
 ** this array, then copy and paste it into this file, if you want.
 */
 static char *zOpName[] = { 0,
-  "Open",           "Close",          "Destroy",        "Fetch",
-  "New",            "Put",            "Delete",         "Field",
-  "Key",            "Rewind",         "Next",           "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",            "Eq",             "Ne",             "Lt",
-  "Le",             "Gt",             "Ge",             "IsNull",
-  "NotNull",        "Negative",       "And",            "Or",
-  "Not",            "Concat",         "Noop",         
+  "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",         
 };
 
 /*
@@ -997,6 +998,67 @@
         break;
       }
 
+      /* Opcode: Like P1 P2 *
+      **
+      ** Pop the top two elements from the stack.  The top-most is a
+      ** "like" pattern -- the right operand of the SQL "LIKE" operator.
+      ** The lower element is the string to compare against the like
+      ** pattern.  Jump to P2 if the two compare, and fall through without
+      ** jumping if they do not.  The '%' in the top-most element matches
+      ** any sequence of zero or more characters in the lower element.  The
+      ** '_' character in the topmost matches any single character of the
+      ** lower element.  Case is ignored for this comparison.
+      **
+      ** If P1 is not zero, the sense of the test is inverted and we
+      ** have a "NOT LIKE" operator.  The jump is made if the two values
+      ** are different.
+      */
+      case OP_Like: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        int c;
+        if( nos<0 ) goto not_enough_stack;
+        Stringify(p, tos);
+        Stringify(p, nos);
+        c = sqliteLikeCompare(p->zStack[tos], p->zStack[nos]);
+        PopStack(p, 2);
+        if( pOp->p1 ) c = !c;
+        if( c ) pc = pOp->p2-1;
+        break;
+      }
+
+      /* Opcode: Glob P1 P2 *
+      **
+      ** Pop the top two elements from the stack.  The top-most is a
+      ** "glob" pattern.  The lower element is the string to compare 
+      ** against the glob pattern.
+      **
+      ** Jump to P2 if the two compare, and fall through without
+      ** jumping if they do not.  The '*' in the top-most element matches
+      ** any sequence of zero or more characters in the lower element.  The
+      ** '?' character in the topmost matches any single character of the
+      ** lower element.  [...] matches a range of characters.  [^...]
+      ** matches any character not in the range.  Case is significant
+      ** for globs.
+      **
+      ** If P1 is not zero, the sense of the test is inverted and we
+      ** have a "NOT GLOB" operator.  The jump is made if the two values
+      ** are different.
+      */
+      case OP_Glob: {
+        int tos = p->tos;
+        int nos = tos - 1;
+        int c;
+        if( nos<0 ) goto not_enough_stack;
+        Stringify(p, tos);
+        Stringify(p, nos);
+        c = sqliteGlobCompare(p->zStack[tos], p->zStack[nos]);
+        PopStack(p, 2);
+        if( pOp->p1 ) c = !c;
+        if( c ) pc = pOp->p2-1;
+        break;
+      }
+
       /* Opcode: And * * *
       **
       ** Pop two values off the stack.  Take the logical AND of the
@@ -1581,6 +1643,15 @@
         break;
       }
 
+      /* Opcode: Reorganize * * P3
+      **
+      ** Compress, optimize, and tidy up the GDBM file named by P3.
+      */
+      case OP_Reorganize: {
+        sqliteDbbeReorganizeTable(p->pBe, pOp->p3);
+        break;
+      }
+
       /* Opcode: ListOpen P1 * *
       **
       ** Open a file used for temporary storage of index numbers.  P1
diff --git a/src/vdbe.h b/src/vdbe.h
index d5dca04..3672cfe 100644
--- a/src/vdbe.h
+++ b/src/vdbe.h
@@ -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.2 2000/05/30 16:27:05 drh Exp $
+** $Id: vdbe.h,v 1.3 2000/05/31 02:27:50 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -73,81 +73,86 @@
 */
 #define OP_Open                1
 #define OP_Close               2
-#define OP_Destroy             3
-#define OP_Fetch               4
-#define OP_New                 5
-#define OP_Put                 6
-#define OP_Delete              7
-#define OP_Field               8
-#define OP_Key                 9
-#define OP_Rewind             10
-#define OP_Next               11
-#define OP_ResetIdx           12
-#define OP_NextIdx            13
-#define OP_PutIdx             14
-#define OP_DeleteIdx          15
+#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_ListOpen           16
-#define OP_ListWrite          17
-#define OP_ListRewind         18
-#define OP_ListRead           19
-#define OP_ListClose          20
+#define OP_Destroy            11
+#define OP_Reorganize         12
 
-#define OP_SortOpen           21
-#define OP_SortPut            22
-#define OP_SortMakeRec        23
-#define OP_SortMakeKey        24
-#define OP_Sort               25
-#define OP_SortNext           26
-#define OP_SortKey            27
-#define OP_SortCallback       28
-#define OP_SortClose          29
+#define OP_ResetIdx           13
+#define OP_NextIdx            14
+#define OP_PutIdx             15
+#define OP_DeleteIdx          16
 
-#define OP_FileOpen           30
-#define OP_FileRead           31
-#define OP_FileField          32
-#define OP_FileClose          33
+#define OP_ListOpen           17
+#define OP_ListWrite          18
+#define OP_ListRewind         19
+#define OP_ListRead           20
+#define OP_ListClose          21
 
-#define OP_MakeRecord         34
-#define OP_MakeKey            35
+#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_Goto               36
-#define OP_If                 37
-#define OP_Halt               38
+#define OP_FileOpen           31
+#define OP_FileRead           32
+#define OP_FileField          33
+#define OP_FileClose          34
 
-#define OP_ColumnCount        39
-#define OP_ColumnName         40
-#define OP_Callback           41
+#define OP_MakeRecord         35
+#define OP_MakeKey            36
 
-#define OP_Integer            42
-#define OP_String             43
-#define OP_Pop                44
-#define OP_Dup                45
-#define OP_Pull               46
+#define OP_Goto               37
+#define OP_If                 38
+#define OP_Halt               39
 
-#define OP_Add                47
-#define OP_AddImm             48
-#define OP_Subtract           49
-#define OP_Multiply           50
-#define OP_Divide             51
-#define OP_Min                52
-#define OP_Max                53
-#define OP_Eq                 54
-#define OP_Ne                 55
-#define OP_Lt                 56
-#define OP_Le                 57
-#define OP_Gt                 58
-#define OP_Ge                 59
-#define OP_IsNull             60
-#define OP_NotNull            61
-#define OP_Negative           62
-#define OP_And                63
-#define OP_Or                 64
-#define OP_Not                65
-#define OP_Concat             66
-#define OP_Noop               67
+#define OP_ColumnCount        40
+#define OP_ColumnName         41
+#define OP_Callback           42
 
-#define OP_MAX                67
+#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
diff --git a/src/where.c b/src/where.c
index 4efabff..217bfd3 100644
--- a/src/where.c
+++ b/src/where.c
@@ -25,7 +25,7 @@
 ** the WHERE clause of SQL statements.  Also found here are subroutines
 ** to generate VDBE code to evaluate expressions.
 **
-** $Id: where.c,v 1.3 2000/05/30 20:17:49 drh Exp $
+** $Id: where.c,v 1.4 2000/05/31 02:27:50 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -368,12 +368,14 @@
     case TK_SLASH:    op = OP_Divide;   break;
     case TK_AND:      op = OP_And;      break;
     case TK_OR:       op = OP_Or;       break;
-    case TK_LT:       op = OP_Ge;       break;
-    case TK_LE:       op = OP_Gt;       break;
-    case TK_GT:       op = OP_Le;       break;
-    case TK_GE:       op = OP_Lt;       break;
-    case TK_NE:       op = OP_Eq;       break;
-    case TK_EQ:       op = OP_Ne;       break;
+    case TK_LT:       op = OP_Lt;       break;
+    case TK_LE:       op = OP_Le;       break;
+    case TK_GT:       op = OP_Gt;       break;
+    case TK_GE:       op = OP_Ge;       break;
+    case TK_NE:       op = OP_Ne;       break;
+    case TK_EQ:       op = OP_Eq;       break;
+    case TK_LIKE:     op = OP_Like;     break;
+    case TK_GLOB:     op = OP_Glob;     break;
     case TK_ISNULL:   op = OP_IsNull;   break;
     case TK_NOTNULL:  op = OP_NotNull;  break;
     case TK_NOT:      op = OP_Not;      break;
@@ -421,14 +423,16 @@
     case TK_GT:
     case TK_GE:
     case TK_NE:
-    case TK_EQ: {
+    case TK_EQ: 
+    case TK_LIKE: 
+    case TK_GLOB: {
       int dest;
-      sqliteVdbeAddOp(v, OP_Integer, 0, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_Integer, 1, 0, 0, 0);
       sqliteExprCode(pParse, pExpr->pLeft);
       sqliteExprCode(pParse, pExpr->pRight);
       dest = sqliteVdbeCurrentAddr(v) + 2;
       sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
-      sqliteVdbeAddOp(v, OP_AddImm, 1, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_AddImm, -1, 0, 0, 0);
       break;
     }
     case TK_NOT:
@@ -466,6 +470,8 @@
     case TK_GE:       op = OP_Ge;       break;
     case TK_NE:       op = OP_Ne;       break;
     case TK_EQ:       op = OP_Eq;       break;
+    case TK_LIKE:     op = OP_Like;     break;
+    case TK_GLOB:     op = OP_Glob;     break;
     case TK_ISNULL:   op = OP_IsNull;   break;
     case TK_NOTNULL:  op = OP_NotNull;  break;
     default:  break;
@@ -483,12 +489,18 @@
       sqliteExprIfTrue(pParse, pExpr->pRight, dest);
       break;
     }
+    case TK_NOT: {
+      sqliteExprIfFalse(pParse, pExpr->pLeft, dest);
+      break;
+    }
     case TK_LT:
     case TK_LE:
     case TK_GT:
     case TK_GE:
     case TK_NE:
-    case TK_EQ: {
+    case TK_EQ:
+    case TK_LIKE:
+    case TK_GLOB: {
       sqliteExprCode(pParse, pExpr->pLeft);
       sqliteExprCode(pParse, pExpr->pRight);
       sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
@@ -523,6 +535,8 @@
     case TK_GE:       op = OP_Lt;       break;
     case TK_NE:       op = OP_Eq;       break;
     case TK_EQ:       op = OP_Ne;       break;
+    case TK_LIKE:     op = OP_Like;     break;
+    case TK_GLOB:     op = OP_Glob;     break;
     case TK_ISNULL:   op = OP_NotNull;  break;
     case TK_NOTNULL:  op = OP_IsNull;   break;
     default:  break;
@@ -540,6 +554,10 @@
       sqliteVdbeResolveLabel(v, d2);
       break;
     }
+    case TK_NOT: {
+      sqliteExprIfTrue(pParse, pExpr->pLeft, dest);
+      break;
+    }
     case TK_LT:
     case TK_LE:
     case TK_GT:
@@ -551,6 +569,13 @@
       sqliteVdbeAddOp(v, op, 0, dest, 0, 0);
       break;
     }
+    case TK_LIKE:
+    case TK_GLOB: {
+      sqliteExprCode(pParse, pExpr->pLeft);
+      sqliteExprCode(pParse, pExpr->pRight);
+      sqliteVdbeAddOp(v, op, 1, dest, 0, 0);
+      break;
+    }
     case TK_ISNULL:
     case TK_NOTNULL: {
       sqliteExprCode(pParse, pExpr->pLeft);
diff --git a/www/changes.tcl b/www/changes.tcl
new file mode 100644
index 0000000..fa52187
--- /dev/null
+++ b/www/changes.tcl
@@ -0,0 +1,46 @@
+#
+# Run this script to generated a changes.html output file
+#
+puts {<html>
+<head>
+  <title>SQLite Change Log</title>
+</head>
+<body bgcolor="white">
+<h1 align="center">Recent Changes To SQLite</h1>
+
+<DL>
+}
+
+
+proc chng {date desc} {
+  puts "<DT><B>$date</B></DT>"
+  puts "<DD><P><UL>$desc</UL></P></DD>"
+}
+
+chng {2000 May 30} {
+<li>Added the <b>LIKE</b> operator.</li>
+<li>Added a <b>GLOB</b> operator: similar to <B>LIKE</B> 
+but it uses Unix shell globbing wildcards instead of the '%' 
+and '_' wildcards of SQL.</li>
+<li>Added the <B>COPY</b> command patterned after 
+<a href="http://www.postgresql.org/">PostgreSQL</a> so that SQLite
+can now read the output of the <b>pg_dump</b> database dump utility
+of PostgreSQL.</li>
+<li>Added a <B>VACUUM</B> command that that calls the 
+<b>gdbm_reorganize()</b> function on the underlying database
+files.</li>
+<li>And many, many bug fixes...</li>
+}
+
+chng {2000 May 29} {
+<li>Initial Public Release of Alpha code</li>
+}
+
+puts {
+</DL>
+<p><hr /></p>
+<p><a href="index.html"><img src="/goback.jpg" border=0 />
+Back to the SQLite Home Page</a>
+</p>
+
+</body></html>}
diff --git a/www/index.tcl b/www/index.tcl
index badc1da..24a87a4 100644
--- a/www/index.tcl
+++ b/www/index.tcl
@@ -1,7 +1,7 @@
 #
 # Run this TCL script to generate HTML for the index.html file.
 #
-set rcsid {$Id: index.tcl,v 1.4 2000/05/30 00:05:13 drh Exp $}
+set rcsid {$Id: index.tcl,v 1.5 2000/05/31 02:27:50 drh Exp $}
 
 puts {<html>
 <head><title>SQLite: An SQL Frontend For GDBM</title></head>
@@ -47,6 +47,9 @@
 library.  For more information on the sqlite program,
 see <a href="sqlite.html">sqlite.html</a>.</p>
 
+<p>A history of changes to SQLite is found
+<a href="changes.html">here</a>.</p>
+
 <p>SQLite does not try to implement every feature of SQL.  But it
 does strive to implement to most commonly used features.  SQLite
 currently understands the following SQL commands:</p>
@@ -71,7 +74,6 @@
 <ul>
 <li>ALTER TABLE</li>
 <li>The GROUP BY or HAVING clauses of a SELECT</li>
-<li>The LIKE or IN operators</li>
 <li>The COUNT(), MAX(), MIN(), and AVG() functions</li>
 <li>Constraints</li>
 <li>Nested queries</li>
diff --git a/www/sqlite.tcl b/www/sqlite.tcl
index a69b376..873d3e2 100644
--- a/www/sqlite.tcl
+++ b/www/sqlite.tcl
@@ -1,7 +1,7 @@
 #
 # Run this Tcl script to generate the sqlite.html file.
 #
-set rcsid {$Id: sqlite.tcl,v 1.3 2000/05/29 18:50:16 drh Exp $}
+set rcsid {$Id: sqlite.tcl,v 1.4 2000/05/31 02:27:50 drh Exp $}
 
 puts {<html>
 <head>
@@ -354,6 +354,18 @@
 ORDER BY tbl_name, type DESC, name
 </pre></blockquote>
 
+<p>Of, if you give an argument to ".schema" because you only
+one the schema for a single table, the query looks like this:</p>
+
+<blockquote><pre>
+SELECT sql FROM sqlite_master
+WHERE tbl_name LIKE '%s'
+ORDER BY type DESC, name
+</pre></blockquote>
+
+<p>The <b>%s</b> in the query above is replaced by the argument
+to ".schema", of course.</p>
+
 <h2>Other Dot Commands</h2>
 
 <p>The ".explain" dot command can be used to set the output mode