]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Skeleton code for the word-fuzzer virtual table.
authordrh <drh@noemail.net>
Sat, 26 Mar 2011 15:05:27 +0000 (15:05 +0000)
committerdrh <drh@noemail.net>
Sat, 26 Mar 2011 15:05:27 +0000 (15:05 +0000)
FossilOrigin-Name: ea3a4ee136ff6699c3099178f0efaa8bb517715f

Makefile.in
main.mk
manifest
manifest.uuid
src/tclsqlite.c
src/test_fuzzer.c [new file with mode: 0644]
test/fuzzer1.test [new file with mode: 0644]

index 2c5490265d92e7c3e1cda521ae9e6b1a8908a550..2ee36dec43f0a2b3fa739b7c0acbdd4e00e614b1 100644 (file)
@@ -356,6 +356,7 @@ TESTSRC = \
   $(TOP)/src/test_demovfs.c \
   $(TOP)/src/test_devsym.c \
   $(TOP)/src/test_func.c \
+  $(TOP)/src/test_fuzzer.c \
   $(TOP)/src/test_hexio.c \
   $(TOP)/src/test_init.c \
   $(TOP)/src/test_intarray.c \
diff --git a/main.mk b/main.mk
index 29374c546fb2e155f49aed3c87c8d024a4aaff9b..cfea9b590f26cf8e213fe26e26e8765668b7a4f2 100644 (file)
--- a/main.mk
+++ b/main.mk
@@ -237,6 +237,7 @@ TESTSRC = \
   $(TOP)/src/test_demovfs.c \
   $(TOP)/src/test_devsym.c \
   $(TOP)/src/test_func.c \
+  $(TOP)/src/test_fuzzer.c \
   $(TOP)/src/test_hexio.c \
   $(TOP)/src/test_init.c \
   $(TOP)/src/test_intarray.c \
index d485703eda0838611bc770b8ce111448953dec40..44205160e6811c4afacf8121b0ea08f3567cf700 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,7 +1,10 @@
-C Minor\schange\sto\ssqlite3Utf8Read()\sto\smake\sconsistent\swith\sREAD_UTF8()\susage\sand\savoid\simplementation\sdefined\susages\sof\s<<.\s\s\nAdded\ssome\sadditional\sUTF-8\stest\scases.
-D 2011-03-24T17:43:18.990
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+C Skeleton\scode\sfor\sthe\sword-fuzzer\svirtual\stable.
+D 2011-03-26T15:05:27.457
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
-F Makefile.in 27701a1653595a1f2187dc61c8117e00a6c1d50f
+F Makefile.in 6c96e694f446500449f683070b906de9fce17b88
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
 F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151
 F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
@@ -101,7 +104,7 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
 F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895
 F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
-F main.mk 54190fab7cdba523e311c274c95ea480f32abfb5
+F main.mk a767e12162f02719fa94697a6ff0c8b51bcd62a6
 F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
 F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
 F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
@@ -184,7 +187,7 @@ F src/sqliteInt.h f8f1d00a22c98fd3f2fbc94da74eeb880879f89f
 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
 F src/status.c 4997380fbb915426fef9e500b4872e79c99267fc
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
-F src/tclsqlite.c 879bf8a23d99fc0e99d9177fe1b48896bc796d65
+F src/tclsqlite.c 44979405594d33c55ec5ef8e82533d3b4133e455
 F src/test1.c 9020310c7617234b33fd1c3064f89524db25f290
 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
 F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc
@@ -202,6 +205,7 @@ F src/test_config.c 62f0f8f934b1d5c7e4cd4f506ae453a1117b47d7
 F src/test_demovfs.c 0aed671636735116fc872c5b03706fd5612488b5
 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
 F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5
+F src/test_fuzzer.c b09d2f47bc3ae1485100b323479c5d785d4f6e4b
 F src/test_hexio.c 1237f000ec7a491009b1233f5c626ea71bce1ea2
 F src/test_init.c 5d624ffd0409d424cf9adbfe1f056b200270077c
 F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
@@ -475,6 +479,7 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
 F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
 F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
 F test/fuzz_malloc.test dd7001ac86d09c154a7dff064f4739c60e2b312c
+F test/fuzzer1.test 29120e10821e2d04887b39c6c1ae4ddcbd2bb7f6
 F test/hook.test f04c3412463f8ec117c1c704c74ca0f627ce733a
 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
 F test/in.test 19b642bb134308980a92249750ea4ce3f6c75c2d
@@ -916,7 +921,18 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 69fe0c873d702ef1d781453ee6ac2b1fb77fce48
-R 3655844fccb71eb3fdafa07a1f475145
-U shaneh
-Z 4c379d73c236b4115e9dab5017415240
+P 7173b3929fae4e678223b0e978a2da7fa50a9005
+R 88772465d0029c6e2564e31a16d9e60f
+T *bgcolor * #b0b28e
+T *branch * word-fuzzer
+T *sym-word-fuzzer *
+T -sym-trunk *
+U drh
+Z 56aa191286824371992372fc6a5d252f
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.6 (GNU/Linux)
+
+iD8DBQFNjgC7oxKgR168RlERAutAAJ0V6j75yMfG5zTEYnDlvPG7yBJM5ACfSqKu
+yFIOeN9GMM2kCskHQ5jGilY=
+=IVMz
+-----END PGP SIGNATURE-----
index 44925bdb50559344411275ec29f2403bfaf61514..a0f61071e08b1b5e561ea428a7659716fb7e41d4 100644 (file)
@@ -1 +1 @@
-7173b3929fae4e678223b0e978a2da7fa50a9005
\ No newline at end of file
+ea3a4ee136ff6699c3099178f0efaa8bb517715f
\ No newline at end of file
index 57f38d78d165b1966fad76a5d993607b7416f3e1..e77a1ee919c20c20ddc120a474accd1cda07329d 100644 (file)
@@ -3581,6 +3581,7 @@ static void init_all(Tcl_Interp *interp){
     extern int Sqlitequota_Init(Tcl_Interp*);
     extern int Sqlitemultiplex_Init(Tcl_Interp*);
     extern int SqliteSuperlock_Init(Tcl_Interp*);
+    extern int Sqlitetestfuzzer_Init(Tcl_Interp*);
 
 #ifdef SQLITE_ENABLE_ZIPVFS
     extern int Zipvfs_Init(Tcl_Interp*);
@@ -3618,6 +3619,7 @@ static void init_all(Tcl_Interp *interp){
     Sqlitequota_Init(interp);
     Sqlitemultiplex_Init(interp);
     SqliteSuperlock_Init(interp);
+    Sqlitetestfuzzer_Init(interp);
 
     Tcl_CreateObjCommand(interp,"load_testfixture_extensions",init_all_cmd,0,0);
 
diff --git a/src/test_fuzzer.c b/src/test_fuzzer.c
new file mode 100644 (file)
index 0000000..406c1a2
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+** 2011 March 24
+**
+** The author disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+**
+*************************************************************************
+**
+** Code for demonstartion virtual table that generates variations
+** on an input word at increasing edit distances from the original.
+*/
+#include "sqlite3.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+
+/*
+** Forward declaration of objects used by this implementation
+*/
+typedef struct fuzzer_vtab fuzzer_vtab;
+typedef struct fuzzer_cursor fuzzer_cursor;
+typedef struct fuzzer_rule fuzzer_rule;
+typedef struct fuzzer_seen fuzzer_seen;
+typedef struct fuzzer_stem fuzzer_stem;
+
+
+/*
+** Each transformation rule is stored as an instance of this object.
+** All rules are kept on a linked list sorted by rCost.
+*/
+struct fuzzer_rule {
+  fuzzer_rule *pNext;   /* Next rule in order of increasing rCost */
+  float rCost;          /* Cost of this transformation */
+  char *zFrom;          /* Transform from */
+  char zTo[4];          /* Transform to (extra space appended) */
+};
+
+/*
+** When generating fuzzed words, we have to remember all previously
+** generated terms in order to suppress duplicates.  Each previously
+** generated term is an instance of the following structure.
+*/
+struct fuzzer_seen {
+  fuzzer_seen *pNext;    /* Next with the same hash */
+  char zWord[4];         /* The generated term. */
+};
+
+/*
+** A stem object is used to generate variants.  
+*/
+struct fuzzer_stem {
+  char *zBasis;           /* Word being fuzzed */
+  fuzzer_rule *pRule;     /* Next rule to apply */
+  int n;                  /* Apply rule at this character offset */
+  float rBaseCost;        /* Base cost of getting to zBasis */
+  float rCost;            /* rBaseCost + cost of applying pRule at n */
+  fuzzer_stem *pNext;     /* Next stem in rCost order */
+};
+
+/* 
+** A fuzzer virtual-table object 
+*/
+struct fuzzer_vtab {
+  sqlite3_vtab base;         /* Base class - must be first */
+  char *zClassName;          /* Name of this class.  Default: "fuzzer" */
+  fuzzer_rule *pRule;        /* All active rules in this fuzzer */
+  fuzzer_rule *pNewRule;     /* New rules to add when last cursor expires */
+  int nCursor;               /* Number of active cursors */
+};
+
+/* A fuzzer cursor object */
+struct fuzzer_cursor {
+  sqlite3_vtab_cursor base;  /* Base class - must be first */
+  float rMax;                /* Maximum cost of any term */
+  fuzzer_stem *pStem;        /* Sorted list of stems for generating new terms */
+  int nSeen;                 /* Number of terms already generated */
+  int nHash;                 /* Number of slots in apHash */
+  fuzzer_seen **apHash;      /* Hash table of previously generated terms */
+};
+
+/* Methods for the fuzzer module */
+static int fuzzerConnect(
+  sqlite3 *db,
+  void *pAux,
+  int argc, const char *const*argv,
+  sqlite3_vtab **ppVtab,
+  char **pzErr
+){
+  fuzzer_vtab *pNew;
+  char *zSql;
+  int n;
+  if( strcmp(argv[1],"temp")!=0 ){
+    *pzErr = sqlite3_mprintf("%s virtual tables must be TEMP", argv[0]);
+    return SQLITE_ERROR;
+  }
+  n = strlen(argv[0]) + 1;
+  pNew = sqlite3_malloc( sizeof(*pNew) + n );
+  if( pNew==0 ) return SQLITE_NOMEM;
+  pNew->zClassName = (char*)&pNew[1];
+  memcpy(pNew->zClassName, argv[0], n);
+  zSql = sqlite3_mprintf(
+     "CREATE TABLE x(word, distance, cFrom, cTo, cost, \"%w\" HIDDEN)",
+     argv[2]
+  );
+  sqlite3_declare_vtab(db, zSql);
+  sqlite3_free(zSql);
+  memset(pNew, 0, sizeof(*pNew));
+  *ppVtab = &pNew->base;
+  return SQLITE_OK;
+}
+/* Note that for this virtual table, the xCreate and xConnect
+** methods are identical. */
+
+static int fuzzerDisconnect(sqlite3_vtab *pVtab){
+  fuzzer_vtab *p = (fuzzer_vtab*)pVtab;
+  assert( p->nCursor==0 );
+  do{
+    while( p->pRule ){
+      fuzzer_rule *pRule = p->pRule;
+      p->pRule = pRule->pNext;
+      sqlite3_free(pRule);
+    }
+    p->pRule = p->pNewRule;
+    p->pNewRule = 0;
+  }while( p->pRule );
+  sqlite3_free(p);
+  return SQLITE_OK;
+}
+/* The xDisconnect and xDestroy methods are also the same */
+
+/*
+** The two input rule lists are both sorted in order of increasing
+** cost.  Merge them together into a single list, sorted by cost, and
+** return a pointer to the head of that list.
+*/
+static fuzzer_rule *fuzzerMergeRules(fuzzer_rule *pA, fuzzer_rule *pB){
+  fuzzer_rule head;
+  fuzzer_rule *pTail;
+
+  pTail =  &head;
+  while( pA && pB ){
+    if( pA->rCost<=pB->rCost ){
+      pTail->pNext = pA;
+      pTail = pA;
+      pA = pA->pNext;
+    }else{
+      pTail->pNext = pB;
+      pTail = pB;
+      pB = pB->pNext;
+    }
+  }
+  if( pA==0 ){
+    pTail->pNext = pB;
+  }else{
+    pTail->pNext = pA;
+  }
+  return head.pNext;
+}
+
+
+/*
+** Open a new fuzzer cursor.
+*/
+static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
+  fuzzer_vtab *p = (fuzzer_vtab*)pVTab;
+  fuzzer_cursor *pCur;
+  pCur = sqlite3_malloc( sizeof(*pCur) );
+  if( pCur==0 ) return SQLITE_NOMEM;
+  memset(pCur, 0, sizeof(*pCur));
+  *ppCursor = &pCur->base;
+  if( p->nCursor==0 && p->pNewRule ){
+    unsigned int i;
+    fuzzer_rule *pX;
+    fuzzer_rule *a[15];
+    for(i=0; i<sizeof(a)/sizeof(a[0]); i++) a[i] = 0;
+    while( (pX = p->pNewRule)!=0 ){
+      p->pNewRule = pX->pNext;
+      pX->pNext = 0;
+      for(i=0; a[i] && i<sizeof(a)/sizeof(a[0])-1; i++){
+        pX = fuzzerMergeRules(a[i], pX);
+        a[i] = 0;
+      }
+      a[i] = fuzzerMergeRules(a[i], pX);
+    }
+    for(pX=a[0], i=1; i<sizeof(a)/sizeof(a[0]); i++){
+      pX = fuzzerMergeRules(a[i], pX);
+    }
+    p->pRule = fuzzerMergeRules(p->pRule, pX);
+  }
+   
+  return SQLITE_OK;
+}
+
+/*
+** Close a fuzzer cursor.
+*/
+static int fuzzerClose(sqlite3_vtab_cursor *cur){
+  fuzzer_cursor *pCur = (fuzzer_cursor *)cur;
+  int i;
+  for(i=0; i<pCur->nHash; i++){
+    fuzzer_seen *pSeen = pCur->apHash[i];
+    while( pSeen ){
+      fuzzer_seen *pNext = pSeen->pNext;
+      sqlite3_free(pSeen);
+      pSeen = pNext;
+    }
+  }
+  sqlite3_free(pCur->apHash);
+  while( pCur->pStem ){
+    fuzzer_stem *pStem = pCur->pStem;
+    pCur->pStem = pStem->pNext;
+    sqlite3_free(pStem);
+  }
+  sqlite3_free(pCur);
+  return SQLITE_OK;
+}
+
+static int fuzzerNext(sqlite3_vtab_cursor *cur){
+  return 0;
+}
+
+static int fuzzerFilter(
+  sqlite3_vtab_cursor *pVtabCursor, 
+  int idxNum, const char *idxStr,
+  int argc, sqlite3_value **argv
+){
+  fuzzer_cursor *pCur = (fuzzer_cursor *)pVtabCursor;
+  return fuzzerNext(pVtabCursor);
+}
+
+static int fuzzerColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
+  fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
+  return SQLITE_OK;
+}
+
+static int fuzzerRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
+  *pRowid = 0;
+  return SQLITE_OK;
+}
+
+static int fuzzerEof(sqlite3_vtab_cursor *cur){
+  fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
+  return 1;
+}
+
+static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
+
+  return SQLITE_OK;
+}
+
+/*
+** Disallow all attempts to DELETE or UPDATE.  Only INSERTs are allowed.
+**
+** On an insert, the cFrom, cTo, and cost columns are used to construct
+** a new rule.   All other columns are ignored.  The rule is ignored
+** if cFrom and cTo are identical.  A NULL value for cFrom or cTo is
+** interpreted as an empty string.  The cost must be positive.
+*/
+static int fuzzerUpdate(
+  sqlite3_vtab *pVTab,
+  int argc,
+  sqlite3_value **argv,
+  sqlite_int64 *pRowid
+){
+  fuzzer_vtab *p = (fuzzer_vtab*)pVTab;
+  fuzzer_rule *pRule;
+  const char *zFrom;
+  int nFrom;
+  const char *zTo;
+  int nTo;
+  float rCost;
+  if( argc!=8 ){
+    sqlite3_free(pVTab->zErrMsg);
+    pVTab->zErrMsg = sqlite3_mprintf("cannot delete from a %s virtual table",
+                                     p->zClassName);
+    return SQLITE_CONSTRAINT;
+  }
+  if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){
+    sqlite3_free(pVTab->zErrMsg);
+    pVTab->zErrMsg = sqlite3_mprintf("cannot update a %s virtual table",
+                                     p->zClassName);
+    return SQLITE_CONSTRAINT;
+  }
+  zFrom = (char*)sqlite3_value_text(argv[4]);
+  if( zFrom==0 ) zFrom = "";
+  zTo = (char*)sqlite3_value_text(argv[5]);
+  if( zTo==0 ) zTo = "";
+  if( strcmp(zFrom,zTo)==0 ){
+    /* Silently ignore null transformations */
+    return SQLITE_OK;
+  }
+  rCost = (float)sqlite3_value_double(argv[6]);
+  if( rCost<=0 ){
+    sqlite3_free(pVTab->zErrMsg);
+    pVTab->zErrMsg = sqlite3_mprintf("cost must be positive");
+    return SQLITE_CONSTRAINT;    
+  }
+  nFrom = strlen(zFrom)+1;
+  nTo = strlen(zTo)+1;
+  if( nTo<4 ) nTo = 4;
+  pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo - 4 );
+  if( pRule==0 ){
+    return SQLITE_NOMEM;
+  }
+  pRule->zFrom = &pRule->zTo[nTo];
+  memcpy(pRule->zFrom, zFrom, nFrom);
+  memcpy(pRule->zTo, zTo, nTo);
+  pRule->rCost = rCost;
+  pRule->pNext = p->pNewRule;
+  p->pNewRule = pRule;
+  return SQLITE_OK;
+}
+
+/*
+** A virtual table module that provides read-only access to a
+** Tcl global variable namespace.
+*/
+static sqlite3_module fuzzerModule = {
+  0,                           /* iVersion */
+  fuzzerConnect,
+  fuzzerConnect,
+  fuzzerBestIndex,
+  fuzzerDisconnect, 
+  fuzzerDisconnect,
+  fuzzerOpen,                  /* xOpen - open a cursor */
+  fuzzerClose,                 /* xClose - close a cursor */
+  fuzzerFilter,                /* xFilter - configure scan constraints */
+  fuzzerNext,                  /* xNext - advance a cursor */
+  fuzzerEof,                   /* xEof - check for end of scan */
+  fuzzerColumn,                /* xColumn - read data */
+  fuzzerRowid,                 /* xRowid - read data */
+  fuzzerUpdate,                /* xUpdate - INSERT */
+  0,                           /* xBegin */
+  0,                           /* xSync */
+  0,                           /* xCommit */
+  0,                           /* xRollback */
+  0,                           /* xFindMethod */
+  0,                           /* xRename */
+};
+
+#endif /* SQLITE_OMIT_VIRTUALTABLE */
+
+
+/*
+** Register the fuzzer virtual table
+*/
+int fuzzer_register(sqlite3 *db){
+  int rc = SQLITE_OK;
+#ifndef SQLITE_OMIT_VIRTUALTABLE
+  rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0);
+#endif
+  return rc;
+}
+
+#ifdef SQLITE_TEST
+#include <tcl.h>
+/*
+** Decode a pointer to an sqlite3 object.
+*/
+extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
+
+/*
+** Register the echo virtual table module.
+*/
+static int register_fuzzer_module(
+  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
+  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
+  int objc,              /* Number of arguments */
+  Tcl_Obj *CONST objv[]  /* Command arguments */
+){
+  sqlite3 *db;
+  if( objc!=2 ){
+    Tcl_WrongNumArgs(interp, 1, objv, "DB");
+    return TCL_ERROR;
+  }
+  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
+  fuzzer_register(db);
+  return TCL_OK;
+}
+
+
+/*
+** Register commands with the TCL interpreter.
+*/
+int Sqlitetestfuzzer_Init(Tcl_Interp *interp){
+  static struct {
+     char *zName;
+     Tcl_ObjCmdProc *xProc;
+     void *clientData;
+  } aObjCmd[] = {
+     { "register_fuzzer_module",   register_fuzzer_module, 0 },
+  };
+  int i;
+  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
+    Tcl_CreateObjCommand(interp, aObjCmd[i].zName, 
+        aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
+  }
+  return TCL_OK;
+}
+
+#endif /* SQLITE_TEST */
diff --git a/test/fuzzer1.test b/test/fuzzer1.test
new file mode 100644 (file)
index 0000000..418bba5
--- /dev/null
@@ -0,0 +1,41 @@
+# 2011 March 25
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for TCL interface to the
+# SQLite library. 
+#
+# The focus of the tests is the word-fuzzer virtual table.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+ifcapable !vtab {
+  finish_test
+  return
+}
+
+register_fuzzer_module db
+do_test fuzzer1-1.0 {
+  catchsql {CREATE VIRTUAL TABLE fault1 USING fuzzer;}
+} {1 {fuzzer virtual tables must be TEMP}}
+do_test fuzzer1-1.1 {
+  db eval {CREATE VIRTUAL TABLE temp.f1 USING fuzzer;}
+} {}
+do_test fuzzer1-1.2 {
+  db eval {
+    INSERT INTO f1(cfrom, cto, cost) VALUES('e','a',0.1);
+    INSERT INTO f1(cfrom, cto, cost) VALUES('a','e',0.1);
+    INSERT INTO f1(cfrom, cto, cost) VALUES('e','o',0.1);
+  }
+} {}
+
+
+finish_test