15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 2011 March 24
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The author disclaims copyright to this source code.  In place of
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a legal notice, here is a blessing:
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you do good and not evil.
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you find forgiveness for yourself and forgive others.
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    May you share freely, never taking more than you give.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*************************************************************************
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Code for demonstartion virtual table that generates variations
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** on an input word at increasing edit distances from the original.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A fuzzer virtual table is created like this:
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     CREATE VIRTUAL TABLE temp.f USING fuzzer;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The name of the new virtual table in the example above is "f".
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Note that all fuzzer virtual tables must be TEMP tables.  The
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** "temp." prefix in front of the table name is required when the
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** table is being created.  The "temp." prefix can be omitted when
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** using the table as long as the name is unambiguous.
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Before being used, the fuzzer needs to be programmed by giving it
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** character transformations and a cost associated with each transformation.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Examples:
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    INSERT INTO f(cFrom,cTo,Cost) VALUES('','a',100);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The above statement says that the cost of inserting a letter 'a' is
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 100.  (All costs are integers.  We recommend that costs be scaled so
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** that the average cost is around 100.)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    INSERT INTO f(cFrom,cTo,Cost) VALUES('b','',87);
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The above statement says that the cost of deleting a single letter
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** 'b' is 87.
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    INSERT INTO f(cFrom,cTo,Cost) VALUES('o','oe',38);
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    INSERT INTO f(cFrom,cTo,Cost) VALUES('oe','o',40);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This third example says that the cost of transforming the single
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** letter "o" into the two-letter sequence "oe" is 38 and that the
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** cost of transforming "oe" back into "o" is 40.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** After all the transformation costs have been set, the fuzzer table
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** can be queried as follows:
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    SELECT word, distance FROM f
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**     WHERE word MATCH 'abcdefg'
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**       AND distance<200;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This first query outputs the string "abcdefg" and all strings that
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** can be derived from that string by appling the specified transformations.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The strings are output together with their total transformation cost
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** (called "distance") and appear in order of increasing cost.  No string
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is output more than once.  If there are multiple ways to transform the
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** target string into the output string then the lowest cost transform is
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** the one that is returned.  In the example, the search is limited to
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** strings with a total distance of less than 200.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** It is important to put some kind of a limit on the fuzzer output.  This
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** can be either in the form of a LIMIT clause at the end of the query,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** or better, a "distance<NNN" constraint where NNN is some number.  The
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** running time and memory requirement is exponential in the value of NNN
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** so you want to make sure that NNN is not too big.  A value of NNN that
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** is about twice the average transformation cost seems to give good results.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The fuzzer table can be useful for tasks such as spelling correction.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Suppose there is a second table vocabulary(w) where the w column contains
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** all correctly spelled words.   Let $word be a word you want to look up.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   SELECT vocabulary.w FROM f, vocabulary
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    WHERE f.word MATCH $word
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      AND f.distance<=200
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      AND f.word=vocabulary.w
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    LIMIT 20
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The query above gives the 20 closest words to the $word being tested.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** (Note that for good performance, the vocubulary.w column should be
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** indexed.)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A similar query can be used to find all words in the dictionary that
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** begin with some prefix $prefix:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   SELECT vocabulary.w FROM f, vocabulary
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    WHERE f.word MATCH $prefix
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      AND f.distance<=200
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**      AND vocabulary.w BETWEEN f.word AND (f.word || x'F7BFBFBF')
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**    LIMIT 50
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** This last query will show up to 50 words out of the vocabulary that
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** match or nearly match the $prefix.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "sqlite3.h"
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h>
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SQLITE_OMIT_VIRTUALTABLE
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Forward declaration of objects used by this implementation
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct fuzzer_vtab fuzzer_vtab;
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct fuzzer_cursor fuzzer_cursor;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct fuzzer_rule fuzzer_rule;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct fuzzer_seen fuzzer_seen;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct fuzzer_stem fuzzer_stem;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Type of the "cost" of an edit operation.  Might be changed to
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** "float" or "double" or "sqlite3_int64" in the future.
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef int fuzzer_cost;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Each transformation rule is stored as an instance of this object.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** All rules are kept on a linked list sorted by rCost.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct fuzzer_rule {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_rule *pNext;        /* Next rule in order of increasing rCost */
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cost rCost;         /* Cost of this transformation */
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nFrom, nTo;            /* Length of the zFrom and zTo strings */
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zFrom;               /* Transform from */
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char zTo[4];               /* Transform to (extra space appended) */
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A stem object is used to generate variants.  It is also used to record
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** previously generated outputs.
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Every stem is added to a hash table as it is output.  Generation of
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** duplicate stems is suppressed.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Active stems (those that might generate new outputs) are kepts on a linked
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** list sorted by increasing cost.  The cost is the sum of rBaseCost and
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** pRule->rCost.
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct fuzzer_stem {
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zBasis;              /* Word being fuzzed */
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nBasis;                /* Length of the zBasis string */
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const fuzzer_rule *pRule;  /* Current rule to apply */
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int n;                     /* Apply pRule at this character offset */
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cost rBaseCost;     /* Base cost of getting to zBasis */
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cost rCostX;        /* Precomputed rBaseCost + pRule->rCost */
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pNext;        /* Next stem in rCost order */
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pHash;        /* Next stem with same hash on zBasis */
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A fuzzer virtual-table object
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct fuzzer_vtab {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab base;         /* Base class - must be first */
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zClassName;          /* Name of this class.  Default: "fuzzer" */
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_rule *pRule;        /* All active rules in this fuzzer */
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_rule *pNewRule;     /* New rules to add when last cursor expires */
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nCursor;               /* Number of active cursors */
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define FUZZER_HASH  4001    /* Hash table size */
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define FUZZER_NQUEUE  20    /* Number of slots on the stem queue */
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* A fuzzer cursor object */
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct fuzzer_cursor {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab_cursor base;  /* Base class - must be first */
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_int64 iRowid;      /* The rowid of the current word */
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_vtab *pVtab;        /* The virtual table this cursor belongs to */
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cost rLimit;        /* Maximum cost of any term */
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pStem;        /* Stem with smallest rCostX */
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pDone;        /* Stems already processed to completion */
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *aQueue[FUZZER_NQUEUE];  /* Queue of stems with higher rCostX */
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int mxQueue;               /* Largest used index in aQueue[] */
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *zBuf;                /* Temporary use buffer */
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nBuf;                  /* Bytes allocated for zBuf */
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nStem;                 /* Number of stems allocated */
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_rule nullRule;      /* Null rule used first */
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *apHash[FUZZER_HASH]; /* Hash of previously generated terms */
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Methods for the fuzzer module */
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerConnect(
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db,
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pAux,
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int argc, const char *const*argv,
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab **ppVtab,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char **pzErr
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_vtab *pNew;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int n;
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( strcmp(argv[1],"temp")!=0 ){
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *pzErr = sqlite3_mprintf("%s virtual tables must be TEMP", argv[0]);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_ERROR;
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  n = strlen(argv[0]) + 1;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew = sqlite3_malloc( sizeof(*pNew) + n );
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pNew==0 ) return SQLITE_NOMEM;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->zClassName = (char*)&pNew[1];
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(pNew->zClassName, argv[0], n);
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_declare_vtab(db, "CREATE TABLE x(word,distance,cFrom,cTo,cost)");
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(pNew, 0, sizeof(*pNew));
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ppVtab = &pNew->base;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* Note that for this virtual table, the xCreate and xConnect
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** methods are identical. */
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerDisconnect(sqlite3_vtab *pVtab){
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_vtab *p = (fuzzer_vtab*)pVtab;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  assert( p->nCursor==0 );
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  do{
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while( p->pRule ){
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      fuzzer_rule *pRule = p->pRule;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->pRule = pRule->pNext;
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sqlite3_free(pRule);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->pRule = p->pNewRule;
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->pNewRule = 0;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }while( p->pRule );
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(p);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* The xDisconnect and xDestroy methods are also the same */
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The two input rule lists are both sorted in order of increasing
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** cost.  Merge them together into a single list, sorted by cost, and
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** return a pointer to the head of that list.
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static fuzzer_rule *fuzzerMergeRules(fuzzer_rule *pA, fuzzer_rule *pB){
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_rule head;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_rule *pTail;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pTail =  &head;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( pA && pB ){
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pA->rCost<=pB->rCost ){
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail->pNext = pA;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail = pA;
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pA = pA->pNext;
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail->pNext = pB;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail = pB;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pB = pB->pNext;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pA==0 ){
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pTail->pNext = pB;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pTail->pNext = pA;
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return head.pNext;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Open a new fuzzer cursor.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_vtab *p = (fuzzer_vtab*)pVTab;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cursor *pCur;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur = sqlite3_malloc( sizeof(*pCur) );
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCur==0 ) return SQLITE_NOMEM;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(pCur, 0, sizeof(*pCur));
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->pVtab = p;
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ppCursor = &pCur->base;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( p->nCursor==0 && p->pNewRule ){
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    unsigned int i;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fuzzer_rule *pX;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fuzzer_rule *a[15];
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(i=0; i<sizeof(a)/sizeof(a[0]); i++) a[i] = 0;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while( (pX = p->pNewRule)!=0 ){
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      p->pNewRule = pX->pNext;
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pX->pNext = 0;
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      for(i=0; a[i] && i<sizeof(a)/sizeof(a[0])-1; i++){
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pX = fuzzerMergeRules(a[i], pX);
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        a[i] = 0;
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      a[i] = fuzzerMergeRules(a[i], pX);
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(pX=a[0], i=1; i<sizeof(a)/sizeof(a[0]); i++){
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pX = fuzzerMergeRules(a[i], pX);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    p->pRule = fuzzerMergeRules(p->pRule, pX);
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->nCursor++;
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Free all stems in a list.
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void fuzzerClearStemList(fuzzer_stem *pStem){
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( pStem ){
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fuzzer_stem *pNext = pStem->pNext;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(pStem);
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pStem = pNext;
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Free up all the memory allocated by a cursor.  Set it rLimit to 0
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to indicate that it is at EOF.
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void fuzzerClearCursor(fuzzer_cursor *pCur, int clearHash){
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerClearStemList(pCur->pStem);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerClearStemList(pCur->pDone);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<FUZZER_NQUEUE; i++) fuzzerClearStemList(pCur->aQueue[i]);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->rLimit = (fuzzer_cost)0;
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( clearHash && pCur->nStem ){
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCur->mxQueue = 0;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCur->pStem = 0;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCur->pDone = 0;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(pCur->aQueue, 0, sizeof(pCur->aQueue));
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memset(pCur->apHash, 0, sizeof(pCur->apHash));
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->nStem = 0;
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Close a fuzzer cursor.
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerClose(sqlite3_vtab_cursor *cur){
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cursor *pCur = (fuzzer_cursor *)cur;
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerClearCursor(pCur, 0);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(pCur->zBuf);
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->pVtab->nCursor--;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_free(pCur);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Compute the current output term for a fuzzer_stem.
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerRender(
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pStem,   /* The stem to be rendered */
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char **pzBuf,         /* Write results into this buffer.  realloc if needed */
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int *pnBuf            /* Size of the buffer */
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const fuzzer_rule *pRule = pStem->pRule;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int n;
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  char *z;
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  n = pStem->nBasis + pRule->nTo - pRule->nFrom;
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( (*pnBuf)<n+1 ){
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*pzBuf) = sqlite3_realloc((*pzBuf), n+100);
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( (*pzBuf)==0 ) return SQLITE_NOMEM;
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    (*pnBuf) = n+100;
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  n = pStem->n;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  z = *pzBuf;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( n<0 ){
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(z, pStem->zBasis, pStem->nBasis+1);
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(z, pStem->zBasis, n);
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(&z[n], pRule->zTo, pRule->nTo);
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    memcpy(&z[n+pRule->nTo], &pStem->zBasis[n+pRule->nFrom],
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           pStem->nBasis-n-pRule->nFrom+1);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Compute a hash on zBasis.
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static unsigned int fuzzerHash(const char *z){
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int h = 0;
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( *z ){ h = (h<<3) ^ (h>>29) ^ *(z++); }
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return h % FUZZER_HASH;
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Current cost of a stem
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static fuzzer_cost fuzzerCost(fuzzer_stem *pStem){
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pStem->rCostX = pStem->rBaseCost + pStem->pRule->rCost;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if 0
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Print a description of a fuzzer_stem on stderr.
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void fuzzerStemPrint(
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zPrefix,
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pStem,
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zSuffix
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pStem->n<0 ){
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr, "%s[%s](%d)-->self%s",
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       zPrefix,
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       pStem->zBasis, pStem->rBaseCost,
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       zSuffix
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    );
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *zBuf = 0;
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int nBuf = 0;
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( fuzzerRender(pStem, &zBuf, &nBuf)!=SQLITE_OK ) return;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    fprintf(stderr, "%s[%s](%d)-->{%s}(%d)%s",
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zPrefix,
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pStem->zBasis, pStem->rBaseCost, zBuf, pStem->,
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      zSuffix
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    );
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(zBuf);
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Return 1 if the string to which the cursor is point has already
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** been emitted.  Return 0 if not.  Return -1 on a memory allocation
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** failures.
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerSeen(fuzzer_cursor *pCur, fuzzer_stem *pStem){
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int h;
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pLookup;
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( fuzzerRender(pStem, &pCur->zBuf, &pCur->nBuf)==SQLITE_NOMEM ){
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  h = fuzzerHash(pCur->zBuf);
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pLookup = pCur->apHash[h];
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while( pLookup && strcmp(pLookup->zBasis, pCur->zBuf)!=0 ){
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pLookup = pLookup->pHash;
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pLookup!=0;
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Advance a fuzzer_stem to its next value.   Return 0 if there are
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** no more values that can be generated by this fuzzer_stem.  Return
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** -1 on a memory allocation failure.
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerAdvance(fuzzer_cursor *pCur, fuzzer_stem *pStem){
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const fuzzer_rule *pRule;
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( (pRule = pStem->pRule)!=0 ){
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while( pStem->n < pStem->nBasis - pRule->nFrom ){
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pStem->n++;
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( pRule->nFrom==0
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       || memcmp(&pStem->zBasis[pStem->n], pRule->zFrom, pRule->nFrom)==0
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ){
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /* Found a rewrite case.  Make sure it is not a duplicate */
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int rc = fuzzerSeen(pCur, pStem);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if( rc<0 ) return -1;
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if( rc==0 ){
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          fuzzerCost(pStem);
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return 1;
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pStem->n = -1;
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pStem->pRule = pRule->pNext;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pStem->pRule && fuzzerCost(pStem)>pCur->rLimit ) pStem->pRule = 0;
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The two input stem lists are both sorted in order of increasing
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** rCostX.  Merge them together into a single list, sorted by rCostX, and
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** return a pointer to the head of that new list.
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static fuzzer_stem *fuzzerMergeStems(fuzzer_stem *pA, fuzzer_stem *pB){
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem head;
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pTail;
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pTail =  &head;
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( pA && pB ){
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pA->rCostX<=pB->rCostX ){
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail->pNext = pA;
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail = pA;
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pA = pA->pNext;
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail->pNext = pB;
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pTail = pB;
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pB = pB->pNext;
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pA==0 ){
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pTail->pNext = pB;
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pTail->pNext = pA;
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return head.pNext;
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Load pCur->pStem with the lowest-cost stem.  Return a pointer
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** to the lowest-cost stem.
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static fuzzer_stem *fuzzerLowestCostStem(fuzzer_cursor *pCur){
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pBest, *pX;
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int iBest;
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pCur->pStem==0 ){
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    iBest = -1;
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pBest = 0;
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for(i=0; i<=pCur->mxQueue; i++){
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pX = pCur->aQueue[i];
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( pX==0 ) continue;
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( pBest==0 || pBest->rCostX>pX->rCostX ){
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pBest = pX;
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        iBest = i;
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pBest ){
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCur->aQueue[iBest] = pBest->pNext;
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pBest->pNext = 0;
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCur->pStem = pBest;
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pCur->pStem;
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Insert pNew into queue of pending stems.  Then find the stem
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** with the lowest rCostX and move it into pCur->pStem.
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** list.  The insert is done such the pNew is in the correct order
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** according to fuzzer_stem.zBaseCost+fuzzer_stem.pRule->rCost.
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static fuzzer_stem *fuzzerInsert(fuzzer_cursor *pCur, fuzzer_stem *pNew){
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pX;
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* If pCur->pStem exists and is greater than pNew, then make pNew
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** the new pCur->pStem and insert the old pCur->pStem instead.
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( (pX = pCur->pStem)!=0 && pX->rCostX>pNew->rCostX ){
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pNew->pNext = 0;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCur->pStem = pNew;
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pNew = pX;
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Insert the new value */
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->pNext = 0;
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pX = pNew;
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<=pCur->mxQueue; i++){
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pCur->aQueue[i] ){
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pX = fuzzerMergeStems(pX, pCur->aQueue[i]);
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCur->aQueue[i] = 0;
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCur->aQueue[i] = pX;
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( i>pCur->mxQueue ){
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( i<FUZZER_NQUEUE ){
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCur->mxQueue = i;
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCur->aQueue[i] = pX;
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      assert( pCur->mxQueue==FUZZER_NQUEUE-1 );
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pX = fuzzerMergeStems(pX, pCur->aQueue[FUZZER_NQUEUE-1]);
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCur->aQueue[FUZZER_NQUEUE-1] = pX;
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return fuzzerLowestCostStem(pCur);
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Allocate a new fuzzer_stem.  Add it to the hash table but do not
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** link it into either the pCur->pStem or pCur->pDone lists.
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static fuzzer_stem *fuzzerNewStem(
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cursor *pCur,
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zWord,
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cost rBaseCost
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pNew;
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned int h;
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew = sqlite3_malloc( sizeof(*pNew) + strlen(zWord) + 1 );
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pNew==0 ) return 0;
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(pNew, 0, sizeof(*pNew));
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->zBasis = (char*)&pNew[1];
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->nBasis = strlen(zWord);
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(pNew->zBasis, zWord, pNew->nBasis+1);
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->pRule = pCur->pVtab->pRule;
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->n = -1;
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->rBaseCost = pNew->rCostX = rBaseCost;
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  h = fuzzerHash(pNew->zBasis);
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pNew->pHash = pCur->apHash[h];
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->apHash[h] = pNew;
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->nStem++;
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pNew;
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Advance a cursor to its next row of output
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerNext(sqlite3_vtab_cursor *cur){
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc;
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pStem, *pNew;
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->iRowid++;
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Use the element the cursor is currently point to to create
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** a new stem and insert the new stem into the priority queue.
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pStem = pCur->pStem;
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pStem->rCostX>0 ){
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    rc = fuzzerRender(pStem, &pCur->zBuf, &pCur->nBuf);
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM;
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pNew = fuzzerNewStem(pCur, pCur->zBuf, pStem->rCostX);
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pNew ){
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( fuzzerAdvance(pCur, pNew)==0 ){
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pNew->pNext = pCur->pDone;
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        pCur->pDone = pNew;
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }else{
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if( fuzzerInsert(pCur, pNew)==pNew ){
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return SQLITE_OK;
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }else{
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SQLITE_NOMEM;
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Adjust the priority queue so that the first element of the
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** stem list is the next lowest cost word.
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  */
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while( (pStem = pCur->pStem)!=0 ){
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( fuzzerAdvance(pCur, pStem) ){
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pCur->pStem = 0;
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pStem = fuzzerInsert(pCur, pStem);
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( (rc = fuzzerSeen(pCur, pStem))!=0 ){
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if( rc<0 ) return SQLITE_NOMEM;
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SQLITE_OK;  /* New word found */
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCur->pStem = 0;
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pStem->pNext = pCur->pDone;
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCur->pDone = pStem;
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( fuzzerLowestCostStem(pCur) ){
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      rc = fuzzerSeen(pCur, pCur->pStem);
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( rc<0 ) return SQLITE_NOMEM;
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if( rc==0 ){
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return SQLITE_OK;
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  /* Reach this point only if queue has been exhausted and there is
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ** nothing left to be output. */
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->rLimit = (fuzzer_cost)0;
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Called to "rewind" a cursor back to the beginning so that
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** it starts its output over again.  Always called at least once
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** prior to any fuzzerColumn, fuzzerRowid, or fuzzerEof call.
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerFilter(
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab_cursor *pVtabCursor,
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int idxNum, const char *idxStr,
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int argc, sqlite3_value **argv
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cursor *pCur = (fuzzer_cursor *)pVtabCursor;
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zWord = 0;
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_stem *pStem;
6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerClearCursor(pCur, 1);
6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->rLimit = 2147483647;
6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( idxNum==1 ){
6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zWord = (const char*)sqlite3_value_text(argv[0]);
6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else if( idxNum==2 ){
6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCur->rLimit = (fuzzer_cost)sqlite3_value_int(argv[0]);
6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else if( idxNum==3 ){
6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    zWord = (const char*)sqlite3_value_text(argv[0]);
6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pCur->rLimit = (fuzzer_cost)sqlite3_value_int(argv[1]);
6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( zWord==0 ) zWord = "";
6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->pStem = pStem = fuzzerNewStem(pCur, zWord, (fuzzer_cost)0);
6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pStem==0 ) return SQLITE_NOMEM;
6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->nullRule.pNext = pCur->pVtab->pRule;
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->nullRule.rCost = 0;
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->nullRule.nFrom = 0;
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->nullRule.nTo = 0;
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->nullRule.zFrom = "";
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pStem->pRule = &pCur->nullRule;
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pStem->n = pStem->nBasis;
6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pCur->iRowid = 1;
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Only the word and distance columns have values.  All other columns
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** return NULL
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( i==0 ){
7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* the "word" column */
7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( fuzzerRender(pCur->pStem, &pCur->zBuf, &pCur->nBuf)==SQLITE_NOMEM ){
7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return SQLITE_NOMEM;
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_result_text(ctx, pCur->zBuf, -1, SQLITE_TRANSIENT);
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else if( i==1 ){
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* the "distance" column */
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_result_int(ctx, pCur->pStem->rCostX);
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else{
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* All other columns are NULL */
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_result_null(ctx);
7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The rowid.
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *pRowid = pCur->iRowid;
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** When the fuzzer_cursor.rLimit value is 0 or less, that is a signal
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** that the cursor has nothing more to output.
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerEof(sqlite3_vtab_cursor *cur){
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pCur->rLimit<=(fuzzer_cost)0;
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Search for terms of these forms:
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**       word MATCH $str
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**       distance < $value
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**       distance <= $value
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The distance< and distance<= are both treated as distance<=.
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** The query plan number is as follows:
7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   0:    None of the terms above are found
7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   1:    There is a "word MATCH" term with $str in filter.argv[0].
7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   2:    There is a "distance<" term with $value in filter.argv[0].
7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**   3:    Both "word MATCH" and "distance<" with $str in argv[0] and
7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**         $value in argv[1].
7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int iPlan = 0;
7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int iDistTerm = -1;
7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const struct sqlite3_index_constraint *pConstraint;
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pConstraint = pIdxInfo->aConstraint;
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( pConstraint->usable==0 ) continue;
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( (iPlan & 1)==0
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     && pConstraint->iColumn==0
7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     && pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH
7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ){
7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iPlan |= 1;
7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pIdxInfo->aConstraintUsage[i].argvIndex = 1;
7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pIdxInfo->aConstraintUsage[i].omit = 1;
7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if( (iPlan & 2)==0
7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     && pConstraint->iColumn==1
7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     && (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           || pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE)
7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ){
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iPlan |= 2;
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iDistTerm = i;
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( iPlan==2 ){
7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = 1;
7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }else if( iPlan==3 ){
7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = 2;
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pIdxInfo->idxNum = iPlan;
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pIdxInfo->nOrderBy==1
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   && pIdxInfo->aOrderBy[0].iColumn==1
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   && pIdxInfo->aOrderBy[0].desc==0
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ){
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pIdxInfo->orderByConsumed = 1;
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pIdxInfo->estimatedCost = (double)10000;
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Disallow all attempts to DELETE or UPDATE.  Only INSERTs are allowed.
7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)**
7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** On an insert, the cFrom, cTo, and cost columns are used to construct
7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** a new rule.   All other columns are ignored.  The rule is ignored
7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** if cFrom and cTo are identical.  A NULL value for cFrom or cTo is
7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** interpreted as an empty string.  The cost must be positive.
8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int fuzzerUpdate(
8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_vtab *pVTab,
8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int argc,
8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3_value **argv,
8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite_int64 *pRowid
8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_vtab *p = (fuzzer_vtab*)pVTab;
8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_rule *pRule;
8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zFrom;
8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nFrom;
8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char *zTo;
8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int nTo;
8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_cost rCost;
8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( argc!=7 ){
8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(pVTab->zErrMsg);
8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pVTab->zErrMsg = sqlite3_mprintf("cannot delete from a %s virtual table",
8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     p->zClassName);
8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_CONSTRAINT;
8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( sqlite3_value_type(argv[0])!=SQLITE_NULL ){
8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(pVTab->zErrMsg);
8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pVTab->zErrMsg = sqlite3_mprintf("cannot update a %s virtual table",
8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     p->zClassName);
8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_CONSTRAINT;
8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zFrom = (char*)sqlite3_value_text(argv[4]);
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( zFrom==0 ) zFrom = "";
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zTo = (char*)sqlite3_value_text(argv[5]);
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( zTo==0 ) zTo = "";
8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( strcmp(zFrom,zTo)==0 ){
8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* Silently ignore null transformations */
8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_OK;
8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rCost = sqlite3_value_int(argv[6]);
8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( rCost<=0 ){
8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sqlite3_free(pVTab->zErrMsg);
8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pVTab->zErrMsg = sqlite3_mprintf("cost must be positive");
8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_CONSTRAINT;
8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nFrom = strlen(zFrom);
8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  nTo = strlen(zTo);
8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pRule = sqlite3_malloc( sizeof(*pRule) + nFrom + nTo );
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( pRule==0 ){
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return SQLITE_NOMEM;
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pRule->zFrom = &pRule->zTo[nTo+1];
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pRule->nFrom = nFrom;
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(pRule->zFrom, zFrom, nFrom+1);
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(pRule->zTo, zTo, nTo+1);
8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pRule->nTo = nTo;
8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pRule->rCost = rCost;
8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pRule->pNext = p->pNewRule;
8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  p->pNewRule = pRule;
8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return SQLITE_OK;
8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** A virtual table module that provides read-only access to a
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Tcl global variable namespace.
8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static sqlite3_module fuzzerModule = {
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0,                           /* iVersion */
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerConnect,
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerConnect,
8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerBestIndex,
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerDisconnect,
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerDisconnect,
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerOpen,                  /* xOpen - open a cursor */
8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerClose,                 /* xClose - close a cursor */
8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerFilter,                /* xFilter - configure scan constraints */
8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerNext,                  /* xNext - advance a cursor */
8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerEof,                   /* xEof - check for end of scan */
8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerColumn,                /* xColumn - read data */
8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerRowid,                 /* xRowid - read data */
8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzerUpdate,                /* xUpdate - INSERT */
8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0,                           /* xBegin */
8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0,                           /* xSync */
8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0,                           /* xCommit */
8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0,                           /* xRollback */
8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0,                           /* xFindMethod */
8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  0,                           /* xRename */
8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* SQLITE_OMIT_VIRTUALTABLE */
8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Register the fuzzer virtual table
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int fuzzer_register(sqlite3 *db){
8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int rc = SQLITE_OK;
8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef SQLITE_OMIT_VIRTUALTABLE
8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0);
8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rc;
8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef SQLITE_TEST
8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <tcl.h>
9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Decode a pointer to an sqlite3 object.
9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb);
9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Register the echo virtual table module.
9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int register_fuzzer_module(
9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Interp *interp,    /* The TCL interpreter that invoked this command */
9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int objc,              /* Number of arguments */
9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Tcl_Obj *CONST objv[]  /* Command arguments */
9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)){
9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sqlite3 *db;
9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( objc!=2 ){
9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Tcl_WrongNumArgs(interp, 1, objv, "DB");
9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TCL_ERROR;
9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR;
9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fuzzer_register(db);
9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TCL_OK;
9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)** Register commands with the TCL interpreter.
9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int Sqlitetestfuzzer_Init(Tcl_Interp *interp){
9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static struct {
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     char *zName;
9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     Tcl_ObjCmdProc *xProc;
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     void *clientData;
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } aObjCmd[] = {
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     { "register_fuzzer_module",   register_fuzzer_module, 0 },
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int i;
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Tcl_CreateObjCommand(interp, aObjCmd[i].zName,
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        aObjCmd[i].xProc, aObjCmd[i].clientData, 0);
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return TCL_OK;
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif /* SQLITE_TEST */
945