]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Change the way the fuzzer (test_fuzzer.c) works so that it loads its configuration...
authordan <dan@noemail.net>
Mon, 20 Feb 2012 20:03:48 +0000 (20:03 +0000)
committerdan <dan@noemail.net>
Mon, 20 Feb 2012 20:03:48 +0000 (20:03 +0000)
FossilOrigin-Name: 90b7b957f8933047fd2878048dfa3ec4891988b8

manifest
manifest.uuid
src/test_fuzzer.c
test/fuzzer1.test

index a05f010578dbf90d9a88dac320934237a21dc139..b0a676f806d69576b878d99c27e6f09c7ed1aeee 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\scase\sin\stest_fuzzer.c\scausing\stransformations\sfrom\sthe\swrong\sruleset\sto\sbe\sapplied\sin\ssome\scases.
-D 2012-02-20T19:36:09.428
+C Change\sthe\sway\sthe\sfuzzer\s(test_fuzzer.c)\sworks\sso\sthat\sit\sloads\sits\sconfiguration\sfrom\sa\sdatabase\stable.
+D 2012-02-20T20:03:48.835
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 3f79a373e57c3b92dabf76f40b065e719d31ac34
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -206,7 +206,7 @@ F src/test_config.c a036a69b550ebc477ab9ca2b37269201f888436e
 F src/test_demovfs.c 20a4975127993f4959890016ae9ce5535a880094
 F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
 F src/test_func.c 6232d722a4ddb193035aa13a03796bf57d6c12fd
-F src/test_fuzzer.c 5c34fdb55c4fa3090d076886139b1f633327a2c5
+F src/test_fuzzer.c 010ee3d4122fd955d6f0db598f68d62f95d15fa9
 F src/test_hexio.c c4773049603151704a6ab25ac5e936b5109caf5a
 F src/test_init.c 3cbad7ce525aec925f8fda2192d576d47f0d478a
 F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
@@ -504,7 +504,7 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
 F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
 F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
 F test/fuzz_malloc.test 328f70aaca63adf29b4c6f06505ed0cf57ca7c26
-F test/fuzzer1.test d5638894ffd89cb01e1276e2a52707b0b1261fe2
+F test/fuzzer1.test 50a480932b91df9d61dd089f338e448991ab771e
 F test/hook.test 5f3749de6462a6b87b4209b74adf7df5ac2df639
 F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
 F test/in.test a7b8a0f43da81cd08645b7a710099ffe9ad1126b
@@ -989,7 +989,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
 F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
-P 760e009adc6d0fffb8e6f64c7ec283938a417a77
-R 2f925ccdeb58b2c1514de71ba4c4df79
+P cb5f5ebc563b8d3e47bc30b6dbb374bb91efd3ef
+R 15ed6cfb8d0ad7f6ea31fbc888768f7f
 U dan
-Z 2c1d8a850f278c0cc6fb31de180d043b
+Z d7a1a4dc789683dc31afc336a51e56bf
index df025c264140928ed9e2b18a25cb9d4aaa6a624f..8798c458c025712df8e7db92c709c5bc03fc3b9a 100644 (file)
@@ -1 +1 @@
-cb5f5ebc563b8d3e47bc30b6dbb374bb91efd3ef
\ No newline at end of file
+90b7b957f8933047fd2878048dfa3ec4891988b8
\ No newline at end of file
index 4402a245efe77621f63c8e8d2d64e0e55b007ebd..6953965243cd5b68bcfbd533435fd9d87af4ade0 100644 (file)
 **
 *************************************************************************
 **
-** Code for demonstartion virtual table that generates variations
+** Code for a demonstration virtual table that generates variations
 ** on an input word at increasing edit distances from the original.
 **
 ** A fuzzer virtual table is created like this:
 **
-**     CREATE VIRTUAL TABLE temp.f USING fuzzer;
+**     CREATE VIRTUAL TABLE f USING fuzzer(<fuzzer-data-table>);
 **
-** The name of the new virtual table in the example above is "f".
-** Note that all fuzzer virtual tables must be TEMP tables.  The
-** "temp." prefix in front of the table name is required when the
-** table is being created.  The "temp." prefix can be omitted when
-** using the table as long as the name is unambiguous.
+** When it is created, the new fuzzer table must be supplied with the
+** name of a "fuzzer data table", which must reside in the same database
+** file as the new fuzzer table. The fuzzer data table contains the various
+** transformations and their costs that the fuzzer logic uses to generate
+** variations.
 **
-** Before being used, the fuzzer needs to be programmed by giving it
-** character transformations and a cost associated with each transformation.
-** Examples:
+** The fuzzer data table must contain exactly four columns (more precisely,
+** the statement "SELECT * FROM <fuzzer_data_table>" must return records
+** that consist of four columns). It does not matter what the columns are
+** named. 
 **
-**    INSERT INTO f(cFrom,cTo,Cost) VALUES('','a',100);
+** Each row in the fuzzer table represents a single character transformation. 
+** The left most column of the row (column 0) contains an integer value -
+** the identifier of the ruleset to which the transformation rule belongs
+** (see "MULTIPLE RULE SETS" below). The second column of the row (column 0)
+** contains the input character or characters. The third column contains the
+** output character or characters. And the fourth column contains the integer 
+** cost of making the transformation. For example:
 **
-** The above statement says that the cost of inserting a letter 'a' is
-** 100.  (All costs are integers.  We recommend that costs be scaled so
-** that the average cost is around 100.)
+**    CREATE TABLE f_data(ruleset, cFrom, cTo, Cost);
+**    INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, '', 'a', 100);
+**    INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, 'b', '', 87);
+**    INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, 'o', 'oe', 38);
+**    INSERT INTO f_data(ruleset, cFrom, cTo, Cost) VALUES(0, 'oe', 'o', 40);
 **
-**    INSERT INTO f(cFrom,cTo,Cost) VALUES('b','',87);
-**
-** The above statement says that the cost of deleting a single letter
-** 'b' is 87.
-**
-**    INSERT INTO f(cFrom,cTo,Cost) VALUES('o','oe',38);
-**    INSERT INTO f(cFrom,cTo,Cost) VALUES('oe','o',40);
-**
-** This third example says that the cost of transforming the single
-** letter "o" into the two-letter sequence "oe" is 38 and that the
+** The first row inserted into the fuzzer data table by the SQL script
+** above indicates that the cost of inserting a letter 'a' is 100.  (All 
+** costs are integers.  We recommend that costs be scaled so that the 
+** average cost is around 100.) The second INSERT statement creates a rule
+** that the cost of that the cost of deleting a single letter 'b' is 87.
+** The third and fourth INSERT statements mean that the cost of transforming 
+** a single letter "o" into the two-letter sequence "oe" is 38 and that the
 ** cost of transforming "oe" back into "o" is 40.
 **
-** After all the transformation costs have been set, the fuzzer table
-** can be queried as follows:
+** The contents of the fuzzer data table are loaded into main memory when
+** a fuzzer table is first created, and may be internally reloaded by the
+** system at any subsequent time. Therefore, the fuzzer data table should be 
+** populated before the fuzzer table is created and not modified thereafter.
+** If you do need to modify the contents of the fuzzer data table, it is
+** recommended that the associated fuzzer table be dropped, the fuzzer data
+** table edited, and the fuzzer table recreated within a single transaction.
+**
+** Once it has been created, the fuzzer table can be queried as follows:
 **
 **    SELECT word, distance FROM f
 **     WHERE word MATCH 'abcdefg'
 **
 ** MULTIPLE RULE SETS
 **
-** An enhancement as of 2012-02-14 allows multiple rule sets to coexist in
-** the same fuzzer.  This allows, for example, the fuzzer to operate in
+** Normally, the "ruleset" value associated with all character transformations
+** in the fuzzer data table is zero. However, if required, the fuzzer table
+** allows multiple rulesets to be defined. Each query uses only a single
+** ruleset. This allows, for example, a single fuzzer table to support 
 ** multiple languages.
 **
-** A new column "ruleset" is added to the table.  This column must have a
-** value between 0 and 49.  The default value for the ruleset is 0.  But
-** alternative values can be specified.  For example:
-**
-**    INSERT INTO f(ruleset,cFrom,cTo,Cost) VALUES(1,'qu','k',100);
-**
-** Only one ruleset will be used at a time.  When running a MATCH query,
-** specify the desired ruleset using a "ruleset=N" term in the WHERE clause.
-** For example:
+** By default, only the rules from ruleset 0 are used. To specify an 
+** alternative ruleset, a "ruleset = ?" expression must be added to the
+** WHERE clause of a SELECT, where ? is the identifier of the desired 
+** ruleset. For example:
 **
 **   SELECT vocabulary.w FROM f, vocabulary
 **    WHERE f.word MATCH $word
 **      AND f.ruleset=1  -- Specify the ruleset to use here
 **    LIMIT 20
 **
-** If no ruleset is specified in the WHERE clause, ruleset 0 is used.
+** If no "ruleset = ?" constraint is specified in the WHERE clause, ruleset 
+** 0 is used.
 */
 #include "sqlite3.h"
 #include <stdlib.h>
@@ -199,7 +210,6 @@ 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 */
 };
 
@@ -224,51 +234,6 @@ struct fuzzer_cursor {
   fuzzer_stem *apHash[FUZZER_HASH]; /* Hash 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;
-  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);
-  sqlite3_declare_vtab(db,
-     "CREATE TABLE x(word,distance,ruleset,cFrom,cTo,cost)");
-  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
@@ -298,25 +263,129 @@ static fuzzer_rule *fuzzerMergeRules(fuzzer_rule *pA, fuzzer_rule *pB){
   return head.pNext;
 }
 
+/*
+** Statement pStmt currently points to a row in the fuzzer data table. This
+** function allocates and populates a fuzzer_rule structure according to
+** the content of the row.
+**
+** If successful, *ppRule is set to point to the new object and SQLITE_OK
+** is returned. Otherwise, *ppRule is zeroed, *pzErr may be set to point
+** to an error message and an SQLite error code returned.
+*/
+static int fuzzerLoadOneRule(
+  fuzzer_vtab *p,                 /* Fuzzer virtual table handle */
+  sqlite3_stmt *pStmt,            /* Base rule on statements current row */
+  fuzzer_rule **ppRule,           /* OUT: New rule object */
+  char **pzErr                    /* OUT: Error message */
+){
+  int iRuleset = sqlite3_column_int(pStmt, 0);
+  const char *zFrom = (const char *)sqlite3_column_text(pStmt, 1);
+  const char *zTo = (const char *)sqlite3_column_text(pStmt, 2);
+  int nCost = sqlite3_column_int(pStmt, 3);
+
+  int rc = SQLITE_OK;             /* Return code */
+  int nFrom;                      /* Size of string zFrom, in bytes */
+  int nTo;                        /* Size of string zTo, in bytes */
+  fuzzer_rule *pRule = 0;         /* New rule object to return */
+
+  if( zFrom==0 ) zFrom = "";
+  if( zTo==0 ) zTo = "";
+  nFrom = strlen(zFrom);
+  nTo = strlen(zTo);
+
+  /* Silently ignore null transformations */
+  if( strcmp(zFrom, zTo)==0 ){
+    *ppRule = 0;
+    return SQLITE_OK;
+  }
+
+  if( nCost<=0 || nCost>FUZZER_MX_COST ){
+    *pzErr = sqlite3_mprintf("cost must be between 1 and %d", FUZZER_MX_COST);
+    rc = SQLITE_ERROR;
+  }else
+  if( nFrom>FUZZER_MX_LENGTH || nTo>FUZZER_MX_LENGTH ){
+    *pzErr = sqlite3_mprintf("maximum string length is %d", FUZZER_MX_LENGTH);
+    rc = SQLITE_ERROR;    
+  }else
+  if( iRuleset<0 || iRuleset>FUZZER_MX_RULEID ){
+    *pzErr = sqlite3_mprintf(
+        "ruleset must be between 0 and %d", FUZZER_MX_RULEID);
+    rc = SQLITE_ERROR;    
+  }else{
+
+    pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo );
+    if( pRule==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      memset(pRule, 0, sizeof(*pRule));
+      pRule->zFrom = &pRule->zTo[nTo+1];
+      pRule->nFrom = nFrom;
+      memcpy(pRule->zFrom, zFrom, nFrom+1);
+      memcpy(pRule->zTo, zTo, nTo+1);
+      pRule->nTo = nTo;
+      pRule->rCost = nCost;
+      pRule->iRuleset = iRuleset;
+    }
+  }
+
+  *ppRule = pRule;
+  return rc;
+}
 
 /*
-** Open a new fuzzer cursor.
+** Load the content of the fuzzer data table into memory.
 */
-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));
-  pCur->pVtab = p;
-  *ppCursor = &pCur->base;
-  if( p->nCursor==0 && p->pNewRule ){
+static int fuzzerLoadRules(
+  sqlite3 *db,                    /* Database handle */
+  fuzzer_vtab *p,                 /* Virtual fuzzer table to configure */
+  const char *zDb,                /* Database containing rules data */
+  const char *zData,              /* Table containing rules data */
+  char **pzErr                    /* OUT: Error message */
+){
+  int rc = SQLITE_OK;             /* Return code */
+  char *zSql;                     /* SELECT used to read from rules table */
+  fuzzer_rule *pHead = 0;
+
+  zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zData);
+  if( zSql==0 ){
+    rc = SQLITE_NOMEM;
+  }else{
+    int rc2;                      /* finalize() return code */
+    sqlite3_stmt *pStmt = 0;
+    rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
+    if( rc!=SQLITE_OK ){
+      *pzErr = sqlite3_mprintf("%s: %s", p->zClassName, sqlite3_errmsg(db));
+    }else if( sqlite3_column_count(pStmt)!=4 ){
+      *pzErr = sqlite3_mprintf("%s: %s has %d columns, expected 4",
+          p->zClassName, zData, sqlite3_column_count(pStmt)
+      );
+      rc = SQLITE_ERROR;
+    }else{
+      while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
+        fuzzer_rule *pRule = 0;
+        rc = fuzzerLoadOneRule(p, pStmt, &pRule, pzErr);
+        if( pRule ){
+          pRule->pNext = pHead;
+          pHead = pRule;
+        }
+      }
+    }
+    rc2 = sqlite3_finalize(pStmt);
+    if( rc==SQLITE_OK ) rc = rc2;
+  }
+  sqlite3_free(zSql);
+
+  /* All rules are now in a singly linked list starting at pHead. This
+  ** block sorts them by cost and then sets fuzzer_vtab.pRule to point to 
+  ** point to the head of the sorted list.
+  */
+  if( rc==SQLITE_OK ){
     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;
+    while( (pX = pHead)!=0 ){
+      pHead = pX->pNext;
       pX->pNext = 0;
       for(i=0; a[i] && i<sizeof(a)/sizeof(a[0])-1; i++){
         pX = fuzzerMergeRules(a[i], pX);
@@ -328,7 +397,96 @@ static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
       pX = fuzzerMergeRules(a[i], pX);
     }
     p->pRule = fuzzerMergeRules(p->pRule, pX);
+  }else{
+    /* An error has occurred. Setting p->pRule to point to the head of the
+    ** allocated list ensures that the list will be cleaned up in this case.
+    */
+    assert( p->pRule==0 );
+    p->pRule = pHead;
   }
+
+  return rc;
+}
+
+
+/*
+** xConnect/xCreate method for the fuzzer module. Arguments are:
+**
+**   argv[0]   -> module name  ("fuzzer")
+**   argv[1]   -> database name
+**   argv[2]   -> table name
+**   argv[3]   -> fuzzer rule table name
+*/
+static int fuzzerConnect(
+  sqlite3 *db,
+  void *pAux,
+  int argc, const char *const*argv,
+  sqlite3_vtab **ppVtab,
+  char **pzErr
+){
+  int rc = SQLITE_OK;             /* Return code */
+  fuzzer_vtab *pNew = 0;          /* New virtual table */
+  const char *zModule = argv[0];
+  const char *zDb = argv[1];
+
+  if( argc!=4 ){
+    *pzErr = sqlite3_mprintf(
+        "%s: wrong number of CREATE VIRTUAL TABLE arguments", zModule
+    );
+    rc = SQLITE_ERROR;
+  }else{
+    int nModule;                  /* Length of zModule, in bytes */
+
+    nModule = strlen(zModule);
+    pNew = sqlite3_malloc( sizeof(*pNew) + nModule + 1);
+    if( pNew==0 ){
+      rc = SQLITE_NOMEM;
+    }else{
+      memset(pNew, 0, sizeof(*pNew));
+      pNew->zClassName = (char*)&pNew[1];
+      memcpy(pNew->zClassName, zModule, nModule+1);
+
+      rc = fuzzerLoadRules(db, pNew, zDb, argv[3], pzErr);
+      if( rc==SQLITE_OK ){
+        sqlite3_declare_vtab(db, "CREATE TABLE x(word, distance,ruleset)");
+      }else{
+        sqlite3_free(pNew);
+        pNew = 0;
+      }
+    }
+  }
+
+  *ppVtab = (sqlite3_vtab *)pNew;
+  return rc;
+}
+/* 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 );
+  while( p->pRule ){
+    fuzzer_rule *pRule = p->pRule;
+    p->pRule = pRule->pNext;
+    sqlite3_free(pRule);
+  }
+  sqlite3_free(p);
+  return SQLITE_OK;
+}
+/* The xDisconnect and xDestroy methods are also the same */
+
+
+/*
+** 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));
+  pCur->pVtab = p;
+  *ppCursor = &pCur->base;
   p->nCursor++;
   return SQLITE_OK;
 }
@@ -479,6 +637,7 @@ static int fuzzerSeen(fuzzer_cursor *pCur, fuzzer_stem *pStem){
 */
 static int fuzzerAdvance(fuzzer_cursor *pCur, fuzzer_stem *pStem){
   const fuzzer_rule *pRule;
+  const int iSet = pCur->iRuleset;
   while( (pRule = pStem->pRule)!=0 ){
     assert( pRule==&pCur->nullRule || pRule->iRuleset==pCur->iRuleset );
     while( pStem->n < pStem->nBasis - pRule->nFrom ){
@@ -498,7 +657,7 @@ static int fuzzerAdvance(fuzzer_cursor *pCur, fuzzer_stem *pStem){
     pStem->n = -1;
     do{
       pRule = pRule->pNext;
-    }while( pRule && pRule->iRuleset!=pCur->iRuleset );
+    }while( pRule && pRule->iRuleset!=iSet );
     pStem->pRule = pRule;
     if( pRule && fuzzerCost(pStem)>pCur->rLimit ) pStem->pRule = 0;
   }
@@ -864,86 +1023,6 @@ 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;
-  fuzzer_cost rCost;
-  int rulesetId;
-  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[5]);
-  if( zFrom==0 ) zFrom = "";
-  zTo = (char*)sqlite3_value_text(argv[6]);
-  if( zTo==0 ) zTo = "";
-  if( strcmp(zFrom,zTo)==0 ){
-    /* Silently ignore null transformations */
-    return SQLITE_OK;
-  }
-  rCost = sqlite3_value_int(argv[7]);
-  if( rCost<=0 || rCost>FUZZER_MX_COST ){
-    sqlite3_free(pVTab->zErrMsg);
-    pVTab->zErrMsg = sqlite3_mprintf("cost must be between 1 and %d",
-                                     FUZZER_MX_COST);
-    return SQLITE_CONSTRAINT;    
-  }
-  nFrom = strlen(zFrom);
-  nTo = strlen(zTo);
-  if( nFrom>FUZZER_MX_LENGTH || nTo>FUZZER_MX_LENGTH ){
-    sqlite3_free(pVTab->zErrMsg);
-    pVTab->zErrMsg = sqlite3_mprintf("maximum string length is %d",
-                                     FUZZER_MX_LENGTH);
-    return SQLITE_CONSTRAINT;    
-  }
-  rulesetId = sqlite3_value_int(argv[4]);
-  if( rulesetId<0 || rulesetId>FUZZER_MX_RULEID ){
-    sqlite3_free(pVTab->zErrMsg);
-    pVTab->zErrMsg = sqlite3_mprintf("rulesetid must be between 0 and %d",
-                                     FUZZER_MX_RULEID);
-    return SQLITE_CONSTRAINT;    
-  }
-  pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo );
-  if( pRule==0 ){
-    return SQLITE_NOMEM;
-  }
-  pRule->zFrom = &pRule->zTo[nTo+1];
-  pRule->nFrom = nFrom;
-  memcpy(pRule->zFrom, zFrom, nFrom+1);
-  memcpy(pRule->zTo, zTo, nTo+1);
-  pRule->nTo = nTo;
-  pRule->rCost = rCost;
-  pRule->pNext = p->pNewRule;
-  pRule->iRuleset = rulesetId;
-  p->pNewRule = pRule;
-  return SQLITE_OK;
-}
-
 /*
 ** A virtual table module that provides read-only access to a
 ** Tcl global variable namespace.
@@ -962,7 +1041,7 @@ static sqlite3_module fuzzerModule = {
   fuzzerEof,                   /* xEof - check for end of scan */
   fuzzerColumn,                /* xColumn - read data */
   fuzzerRowid,                 /* xRowid - read data */
-  fuzzerUpdate,                /* xUpdate - INSERT */
+  0,                           /* xUpdate */
   0,                           /* xBegin */
   0,                           /* xSync */
   0,                           /* xCommit */
index 05c00bc025b8c42597a0f6eecfdd03a205e7a2f2..cfa6b756d53afcc357f0f57885ac5450bfaf54bf 100644 (file)
@@ -23,48 +23,96 @@ ifcapable !vtab {
 }
 
 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',1);
-    INSERT INTO f1(cfrom, cto, cost) VALUES('a','e',10);
-    INSERT INTO f1(cfrom, cto, cost) VALUES('e','o',100);
-  }
+
+
+
+# Check configuration errors.
+#
+do_catchsql_test fuzzer1-1.1 {
+  CREATE VIRTUAL TABLE f USING fuzzer;
+} {1 {fuzzer: wrong number of CREATE VIRTUAL TABLE arguments}}
+
+do_catchsql_test fuzzer1-1.2 {
+  CREATE VIRTUAL TABLE f USING fuzzer(one, two);
+} {1 {fuzzer: wrong number of CREATE VIRTUAL TABLE arguments}}
+
+do_catchsql_test fuzzer1-1.3 {
+  CREATE VIRTUAL TABLE f USING fuzzer(nosuchtable);
+} {1 {fuzzer: no such table: main.nosuchtable}}
+
+do_catchsql_test fuzzer1-1.4 {
+  CREATE TEMP TABLE nosuchtable(a, b, c, d);
+  CREATE VIRTUAL TABLE f USING fuzzer(nosuchtable);
+} {1 {fuzzer: no such table: main.nosuchtable}}
+
+do_catchsql_test fuzzer1-1.5 {
+  DROP TABLE temp.nosuchtable;
+  CREATE TABLE nosuchtable(a, b, c, d);
+  CREATE VIRTUAL TABLE temp.f USING fuzzer(nosuchtable);
+} {1 {fuzzer: no such table: temp.nosuchtable}}
+
+do_catchsql_test fuzzer1-1.6 {
+  DROP TABLE IF EXISTS f_rules;
+  CREATE TABLE f_rules(a, b, c);
+  CREATE VIRTUAL TABLE f USING fuzzer(f_rules);
+} {1 {fuzzer: f_rules has 3 columns, expected 4}}
+
+do_catchsql_test fuzzer1-1.7 {
+  DROP TABLE IF EXISTS f_rules;
+  CREATE TABLE f_rules(a, b, c, d, e);
+  CREATE VIRTUAL TABLE f USING fuzzer(f_rules);
+} {1 {fuzzer: f_rules has 5 columns, expected 4}}
+
+
+do_execsql_test fuzzer1-2.1 {
+  CREATE TABLE f1_rules(ruleset DEFAULT 0, cfrom, cto, cost);
+  INSERT INTO f1_rules(cfrom, cto, cost) VALUES('e','a',1);
+  INSERT INTO f1_rules(cfrom, cto, cost) VALUES('a','e',10);
+  INSERT INTO f1_rules(cfrom, cto, cost) VALUES('e','o',100);
+
+  CREATE VIRTUAL TABLE f1 USING fuzzer(f1_rules);
 } {}
 
-do_test fuzzer1-1.3 {
-  db eval {
+do_execsql_test fuzzer1-2.1 {
     SELECT word, distance FROM f1 WHERE word MATCH 'abcde'
-  }
-} {abcde 0 abcda 1 ebcde 10 ebcda 11 abcdo 100 ebcdo 110 obcde 110 obcda 111 obcdo 210}
+} {
+  abcde 0   abcda 1   ebcde 10 
+  ebcda 11  abcdo 100 ebcdo 110 
+  obcde 110 obcda 111 obcdo 210
+}
 
-do_test fuzzer1-1.4 {
-  db eval {
-    INSERT INTO f1(ruleset, cfrom, cto, cost) VALUES(1,'b','x',1);
-    INSERT INTO f1(ruleset, cfrom, cto, cost) VALUES(1,'d','y',10);
-    INSERT INTO f1(ruleset, cfrom, cto, cost) VALUES(1,'y','z',100);
-  }
+do_execsql_test fuzzer1-2.4 {
+  INSERT INTO f1_rules(ruleset, cfrom, cto, cost) VALUES(1,'b','x',1);
+  INSERT INTO f1_rules(ruleset, cfrom, cto, cost) VALUES(1,'d','y',10);
+  INSERT INTO f1_rules(ruleset, cfrom, cto, cost) VALUES(1,'y','z',100);
+
+  DROP TABLE f1;
+  CREATE VIRTUAL TABLE f1 USING fuzzer(f1_rules);
 } {}
-do_test fuzzer1-1.5 {
-  db eval {
-    SELECT word, distance FROM f1 WHERE word MATCH 'abcde'
-  }
-} {abcde 0 abcda 1 ebcde 10 ebcda 11 abcdo 100 ebcdo 110 obcde 110 obcda 111 obcdo 210}
-do_test fuzzer1-1.6 {
-  db eval {
-    SELECT word, distance FROM f1 WHERE word MATCH 'abcde' AND ruleset=0
-  }
-} {abcde 0 abcda 1 ebcde 10 ebcda 11 abcdo 100 ebcdo 110 obcde 110 obcda 111 obcdo 210}
-do_test fuzzer1-1.7 {
-  db eval {
-    SELECT word, distance FROM f1 WHERE word MATCH 'abcde' AND ruleset=1
-  }
-} {abcde 0 axcde 1 abcye 10 axcye 11 abcze 110 axcze 111}
+
+do_execsql_test fuzzer1-2.5 {
+  SELECT word, distance FROM f1 WHERE word MATCH 'abcde'
+} {
+  abcde 0   abcda 1   ebcde 10 
+  ebcda 11  abcdo 100 ebcdo 110 
+  obcde 110 obcda 111 obcdo 210
+}
+
+do_execsql_test fuzzer1-2.6 {
+  SELECT word, distance FROM f1 WHERE word MATCH 'abcde' AND ruleset=0
+} {
+  abcde 0   abcda 1   ebcde 10 
+  ebcda 11  abcdo 100 ebcdo 110 
+  obcde 110 obcda 111 obcdo 210
+}
+
+do_execsql_test fuzzer1-2.7 {
+  SELECT word, distance FROM f1 WHERE word MATCH 'abcde' AND ruleset=1
+} {
+  abcde 0 axcde 1 abcye 10 
+  axcye 11 abcze 110 axcze 111
+}
+
 do_test fuzzer1-1.8 {
   db eval {
     SELECT word, distance FROM f1 WHERE word MATCH 'abcde' AND distance<100
@@ -102,77 +150,78 @@ do_test fuzzer1-1.13 {
 
 do_test fuzzer1-2.0 {
   execsql {
-    CREATE VIRTUAL TABLE temp.f2 USING fuzzer;
     -- costs based on English letter frequencies
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('a','e',24);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('a','o',47);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('a','u',50);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('e','a',23);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('e','i',33);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('e','o',37);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('i','e',33);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('i','y',33);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('o','a',41);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('o','e',46);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('o','u',57);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('u','o',58);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('y','i',33);
-
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('t','th',70);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('th','t',66);
+    CREATE TEMP TABLE f2_rules(ruleset, cFrom, cTo, cost);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('a','e',24);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('a','o',47);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('a','u',50);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('e','a',23);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('e','i',33);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('e','o',37);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('i','e',33);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('i','y',33);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('o','a',41);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('o','e',46);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('o','u',57);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('u','o',58);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('y','i',33);
 
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('t','th',70);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('th','t',66);
  
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('a','',84);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','b',106);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('b','',106);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','c',94);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('c','',94);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','d',89);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('d','',89);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','e',83);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('e','',83);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','f',97);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('f','',97);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','g',99);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('g','',99);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','h',86);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('h','',86);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','i',85);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('i','',85);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','j',120);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('j','',120);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','k',120);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('k','',120);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','l',89);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('l','',89);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','m',96);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('m','',96);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','n',85);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('n','',85);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','o',85);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('o','',85);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','p',100);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('p','',100);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','q',120);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('q','',120);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','r',86);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('r','',86);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','s',86);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('s','',86);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','t',84);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('t','',84);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','u',94);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('u','',94);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','v',120);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('v','',120);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','w',96);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('w','',96);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','x',120);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('x','',120);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','y',100);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('y','',100);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('','z',120);
-    INSERT INTO f2(cFrom,cTo,cost) VALUES('z','',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('a','',84);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','b',106);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('b','',106);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','c',94);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('c','',94);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','d',89);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('d','',89);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','e',83);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('e','',83);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','f',97);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('f','',97);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','g',99);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('g','',99);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','h',86);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('h','',86);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','i',85);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('i','',85);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','j',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('j','',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','k',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('k','',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','l',89);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('l','',89);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','m',96);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('m','',96);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','n',85);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('n','',85);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','o',85);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('o','',85);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','p',100);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('p','',100);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','q',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('q','',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','r',86);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('r','',86);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','s',86);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('s','',86);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','t',84);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('t','',84);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','u',94);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('u','',94);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','v',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('v','',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','w',96);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('w','',96);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','x',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('x','',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','y',100);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('y','',100);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('','z',120);
+    INSERT INTO f2_rules(cFrom,cTo,cost) VALUES('z','',120);
+
+    CREATE VIRTUAL TABLE temp.f2 USING fuzzer(f2_rules);
 
     -- Street names for the 28269 ZIPCODE.
     --
@@ -1435,12 +1484,13 @@ do_test fuzzer1-2.3 {
   }
 } {{tyler finley} trailer taymouth steelewood tallia tallu talwyn thelema}
 
-
-do_execsql_test fuzzer1-3.1 {
-  CREATE VIRTUAL TABLE temp.f3 USING fuzzer;
-  CREATE TABLE f3(ruleset, cfrom, cto, cost);
-  INSERT INTO f3(ruleset, cfrom, cto, cost) VALUES(0, 'x','y', 10);
-  INSERT INTO f3(ruleset, cfrom, cto, cost) VALUES(1, 'a','b', 10);
+forcedelete test.db2
+do_execsql_test fuzzer1-4.1 {
+  ATTACH 'test.db2' AS aux;
+  CREATE TABLE aux.f3_rules(ruleset, cfrom, cto, cost);
+  INSERT INTO f3_rules(ruleset, cfrom, cto, cost) VALUES(0, 'x','y', 10);
+  INSERT INTO f3_rules(ruleset, cfrom, cto, cost) VALUES(1, 'a','b', 10);
+  CREATE VIRTUAL TABLE aux.f3 USING fuzzer(f3_rules);
   SELECT word FROM f3 WHERE word MATCH 'ax'
 } {ax ay}