Added most of the logic. Simple test runs without segfaulting but does not
give the correct answer. FossilOrigin-Name: fb4c31eac8a7290f61c50a3552245660e1271871
This commit is contained in:
parent
326a67d0e8
commit
94169564fa
24
manifest
24
manifest
@ -1,8 +1,8 @@
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
C Skeleton\scode\sfor\sthe\sword-fuzzer\svirtual\stable.
|
||||
D 2011-03-26T15:05:27.457
|
||||
C Added\smost\sof\sthe\slogic.\s\sSimple\stest\sruns\swithout\ssegfaulting\sbut\sdoes\snot\ngive\sthe\scorrect\sanswer.
|
||||
D 2011-03-26T19:04:47.346
|
||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||
F Makefile.in 6c96e694f446500449f683070b906de9fce17b88
|
||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||
@ -205,7 +205,7 @@ F src/test_config.c 62f0f8f934b1d5c7e4cd4f506ae453a1117b47d7
|
||||
F src/test_demovfs.c 0aed671636735116fc872c5b03706fd5612488b5
|
||||
F src/test_devsym.c e7498904e72ba7491d142d5c83b476c4e76993bc
|
||||
F src/test_func.c cbdec5cededa0761daedde5baf06004a9bf416b5
|
||||
F src/test_fuzzer.c b09d2f47bc3ae1485100b323479c5d785d4f6e4b
|
||||
F src/test_fuzzer.c 133c830fdd4342b687910a04cf8e617e0f5f0e5f
|
||||
F src/test_hexio.c 1237f000ec7a491009b1233f5c626ea71bce1ea2
|
||||
F src/test_init.c 5d624ffd0409d424cf9adbfe1f056b200270077c
|
||||
F src/test_intarray.c d879bbf8e4ce085ab966d1f3c896a7c8b4f5fc99
|
||||
@ -479,7 +479,7 @@ F test/fuzz2.test 207d0f9d06db3eaf47a6b7bfc835b8e2fc397167
|
||||
F test/fuzz3.test aec64345184d1662bd30e6a17851ff659d596dc5
|
||||
F test/fuzz_common.tcl a87dfbb88c2a6b08a38e9a070dabd129e617b45b
|
||||
F test/fuzz_malloc.test dd7001ac86d09c154a7dff064f4739c60e2b312c
|
||||
F test/fuzzer1.test 29120e10821e2d04887b39c6c1ae4ddcbd2bb7f6
|
||||
F test/fuzzer1.test e0fe96bb8d318250b35407954c7059eea8ea77b2
|
||||
F test/hook.test f04c3412463f8ec117c1c704c74ca0f627ce733a
|
||||
F test/icu.test 70df4faca133254c042d02ae342c0a141f2663f4
|
||||
F test/in.test 19b642bb134308980a92249750ea4ce3f6c75c2d
|
||||
@ -921,18 +921,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 7173b3929fae4e678223b0e978a2da7fa50a9005
|
||||
R 88772465d0029c6e2564e31a16d9e60f
|
||||
T *bgcolor * #b0b28e
|
||||
T *branch * word-fuzzer
|
||||
T *sym-word-fuzzer *
|
||||
T -sym-trunk *
|
||||
P ea3a4ee136ff6699c3099178f0efaa8bb517715f
|
||||
R 6a09f2dbc53bf6a269c56104914ae3e5
|
||||
U drh
|
||||
Z 56aa191286824371992372fc6a5d252f
|
||||
Z c40c33ca74d9ed106c795140b6ad71ee
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.4.6 (GNU/Linux)
|
||||
|
||||
iD8DBQFNjgC7oxKgR168RlERAutAAJ0V6j75yMfG5zTEYnDlvPG7yBJM5ACfSqKu
|
||||
yFIOeN9GMM2kCskHQ5jGilY=
|
||||
=IVMz
|
||||
iD8DBQFNjjjSoxKgR168RlERAjfMAKCJigUMIbnNV83nhVCWCpDK5WxPFQCeLIbS
|
||||
+J80DLXre8S3k4SR8glB8Jc=
|
||||
=nBDg
|
||||
-----END PGP SIGNATURE-----
|
||||
|
@ -1 +1 @@
|
||||
ea3a4ee136ff6699c3099178f0efaa8bb517715f
|
||||
fb4c31eac8a7290f61c50a3552245660e1271871
|
@ -29,38 +29,36 @@ typedef struct fuzzer_rule fuzzer_rule;
|
||||
typedef struct fuzzer_seen fuzzer_seen;
|
||||
typedef struct fuzzer_stem fuzzer_stem;
|
||||
|
||||
/*
|
||||
** Type of the "cost" of an edit operation. Might be changed to
|
||||
** "float" or "double" or "sqlite3_int64" in the future.
|
||||
*/
|
||||
typedef int fuzzer_cost;
|
||||
|
||||
|
||||
/*
|
||||
** Each transformation rule is stored as an instance of this object.
|
||||
** All rules are kept on a linked list sorted by rCost.
|
||||
*/
|
||||
struct fuzzer_rule {
|
||||
fuzzer_rule *pNext; /* Next rule in order of increasing rCost */
|
||||
float rCost; /* Cost of this transformation */
|
||||
char *zFrom; /* Transform from */
|
||||
char zTo[4]; /* Transform to (extra space appended) */
|
||||
};
|
||||
|
||||
/*
|
||||
** When generating fuzzed words, we have to remember all previously
|
||||
** generated terms in order to suppress duplicates. Each previously
|
||||
** generated term is an instance of the following structure.
|
||||
*/
|
||||
struct fuzzer_seen {
|
||||
fuzzer_seen *pNext; /* Next with the same hash */
|
||||
char zWord[4]; /* The generated term. */
|
||||
fuzzer_rule *pNext; /* Next rule in order of increasing rCost */
|
||||
fuzzer_cost rCost; /* Cost of this transformation */
|
||||
int nFrom, nTo; /* Length of the zFrom and zTo strings */
|
||||
char *zFrom; /* Transform from */
|
||||
char zTo[4]; /* Transform to (extra space appended) */
|
||||
};
|
||||
|
||||
/*
|
||||
** A stem object is used to generate variants.
|
||||
*/
|
||||
struct fuzzer_stem {
|
||||
char *zBasis; /* Word being fuzzed */
|
||||
fuzzer_rule *pRule; /* Next rule to apply */
|
||||
int n; /* Apply rule at this character offset */
|
||||
float rBaseCost; /* Base cost of getting to zBasis */
|
||||
float rCost; /* rBaseCost + cost of applying pRule at n */
|
||||
fuzzer_stem *pNext; /* Next stem in rCost order */
|
||||
char *zBasis; /* Word being fuzzed */
|
||||
int nBasis; /* Length of the zBasis string */
|
||||
const fuzzer_rule *pRule; /* Current rule to apply */
|
||||
int n; /* Apply pRule at this character offset */
|
||||
fuzzer_cost rBaseCost; /* Base cost of getting to zBasis */
|
||||
fuzzer_stem *pNext; /* Next stem in rCost order */
|
||||
fuzzer_stem *pHash; /* Next stem with same hash on zBasis */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -74,14 +72,18 @@ struct fuzzer_vtab {
|
||||
int nCursor; /* Number of active cursors */
|
||||
};
|
||||
|
||||
#define FUZZER_HASH 4001 /* Hash table size */
|
||||
|
||||
/* A fuzzer cursor object */
|
||||
struct fuzzer_cursor {
|
||||
sqlite3_vtab_cursor base; /* Base class - must be first */
|
||||
float rMax; /* Maximum cost of any term */
|
||||
fuzzer_vtab *pVtab; /* The virtual table this cursor belongs to */
|
||||
fuzzer_cost rLimit; /* Maximum cost of any term */
|
||||
fuzzer_stem *pStem; /* Sorted list of stems for generating new terms */
|
||||
int nSeen; /* Number of terms already generated */
|
||||
int nHash; /* Number of slots in apHash */
|
||||
fuzzer_seen **apHash; /* Hash table of previously generated terms */
|
||||
fuzzer_stem *pDone; /* Stems already processed to completion */
|
||||
char *zBuf; /* Temporary use buffer */
|
||||
int nBuf; /* Bytes allocated for zBuf */
|
||||
fuzzer_stem *apHash[FUZZER_HASH]; /* Hash of previously generated terms */
|
||||
};
|
||||
|
||||
/* Methods for the fuzzer module */
|
||||
@ -93,7 +95,6 @@ static int fuzzerConnect(
|
||||
char **pzErr
|
||||
){
|
||||
fuzzer_vtab *pNew;
|
||||
char *zSql;
|
||||
int n;
|
||||
if( strcmp(argv[1],"temp")!=0 ){
|
||||
*pzErr = sqlite3_mprintf("%s virtual tables must be TEMP", argv[0]);
|
||||
@ -104,12 +105,7 @@ static int fuzzerConnect(
|
||||
if( pNew==0 ) return SQLITE_NOMEM;
|
||||
pNew->zClassName = (char*)&pNew[1];
|
||||
memcpy(pNew->zClassName, argv[0], n);
|
||||
zSql = sqlite3_mprintf(
|
||||
"CREATE TABLE x(word, distance, cFrom, cTo, cost, \"%w\" HIDDEN)",
|
||||
argv[2]
|
||||
);
|
||||
sqlite3_declare_vtab(db, zSql);
|
||||
sqlite3_free(zSql);
|
||||
sqlite3_declare_vtab(db, "CREATE TABLE x(word,distance,cFrom,cTo,cost)");
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
*ppVtab = &pNew->base;
|
||||
return SQLITE_OK;
|
||||
@ -173,7 +169,9 @@ static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
pCur = sqlite3_malloc( sizeof(*pCur) );
|
||||
if( pCur==0 ) return SQLITE_NOMEM;
|
||||
memset(pCur, 0, sizeof(*pCur));
|
||||
pCur->pVtab = p;
|
||||
*ppCursor = &pCur->base;
|
||||
p->nCursor++;
|
||||
if( p->nCursor==0 && p->pNewRule ){
|
||||
unsigned int i;
|
||||
fuzzer_rule *pX;
|
||||
@ -193,63 +191,331 @@ static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
|
||||
}
|
||||
p->pRule = fuzzerMergeRules(p->pRule, pX);
|
||||
}
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Free up all the memory allocated by a cursor. Set it rLimit to 0
|
||||
** to indicate that it is at EOF.
|
||||
*/
|
||||
static void fuzzerClearCursor(fuzzer_cursor *pCur, int clearHash){
|
||||
if( pCur->pStem==0 && pCur->pDone==0 ) clearHash = 0;
|
||||
do{
|
||||
while( pCur->pStem ){
|
||||
fuzzer_stem *pStem = pCur->pStem;
|
||||
pCur->pStem = pStem->pNext;
|
||||
sqlite3_free(pStem);
|
||||
}
|
||||
pCur->pStem = pCur->pDone;
|
||||
pCur->pDone = 0;
|
||||
}while( pCur->pStem );
|
||||
pCur->rLimit = (fuzzer_cost)0;
|
||||
if( clearHash ) memset(pCur->apHash, 0, sizeof(pCur->apHash));
|
||||
}
|
||||
|
||||
/*
|
||||
** Close a fuzzer cursor.
|
||||
*/
|
||||
static int fuzzerClose(sqlite3_vtab_cursor *cur){
|
||||
fuzzer_cursor *pCur = (fuzzer_cursor *)cur;
|
||||
int i;
|
||||
for(i=0; i<pCur->nHash; i++){
|
||||
fuzzer_seen *pSeen = pCur->apHash[i];
|
||||
while( pSeen ){
|
||||
fuzzer_seen *pNext = pSeen->pNext;
|
||||
sqlite3_free(pSeen);
|
||||
pSeen = pNext;
|
||||
}
|
||||
}
|
||||
sqlite3_free(pCur->apHash);
|
||||
while( pCur->pStem ){
|
||||
fuzzer_stem *pStem = pCur->pStem;
|
||||
pCur->pStem = pStem->pNext;
|
||||
sqlite3_free(pStem);
|
||||
}
|
||||
sqlite3_free(pCur);
|
||||
fuzzerClearCursor(pCur, 0);
|
||||
sqlite3_free(pCur->zBuf);
|
||||
pCur->pVtab->nCursor--;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
static int fuzzerNext(sqlite3_vtab_cursor *cur){
|
||||
/*
|
||||
** Compute the current output term for a fuzzer_stem.
|
||||
*/
|
||||
static int fuzzerComputeWord(
|
||||
fuzzer_cursor *pCur,
|
||||
fuzzer_stem *pStem
|
||||
){
|
||||
const fuzzer_rule *pRule = pStem->pRule;
|
||||
int n;
|
||||
|
||||
n = pStem->nBasis;
|
||||
if( pStem->n>=0 ) n += pRule->nTo - pRule->nFrom;
|
||||
if( pCur->nBuf<n+1 ){
|
||||
pCur->zBuf = sqlite3_realloc(pCur->zBuf, n+100);
|
||||
if( pCur->zBuf==0 ) return SQLITE_NOMEM;
|
||||
pCur->nBuf = n+100;
|
||||
}
|
||||
n = pStem->n;
|
||||
if( n<0 ){
|
||||
memcpy(pCur->zBuf, pStem->zBasis, pStem->nBasis+1);
|
||||
}else{
|
||||
memcpy(pCur->zBuf, pStem->zBasis, n);
|
||||
memcpy(&pCur->zBuf[n], pRule->zTo, pRule->nTo);
|
||||
memcpy(&pCur->zBuf[n+pRule->nTo], &pStem->zBasis[n+pRule->nFrom],
|
||||
pStem->nBasis-n-pRule->nFrom+1);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Compute a hash on zBasis.
|
||||
*/
|
||||
static unsigned int fuzzerHash(const char *z){
|
||||
unsigned int h = 0;
|
||||
while( *z ){ h = (h<<3) ^ (h>>29) ^ *(z++); }
|
||||
return h%10007;
|
||||
}
|
||||
|
||||
/*
|
||||
** Current cost of a stem
|
||||
*/
|
||||
static fuzzer_cost fuzzerCost(fuzzer_stem *pStem){
|
||||
return pStem->rBaseCost + pStem->pRule->rCost;
|
||||
}
|
||||
|
||||
/*
|
||||
** Advance a fuzzer_stem to its next value. Return 0 if there are
|
||||
** no more values that can be generated by this fuzzer_stem.
|
||||
*/
|
||||
static int fuzzerAdvance(fuzzer_cursor *pCur, fuzzer_stem *pStem){
|
||||
const fuzzer_rule *pRule;
|
||||
while( (pRule = pStem->pRule)!=0 ){
|
||||
while( pStem->n < pStem->nBasis - pRule->nFrom ){
|
||||
pStem->n++;
|
||||
if( pRule->nFrom==0
|
||||
|| memcmp(&pStem->zBasis[pStem->n], pRule->zFrom, pRule->nFrom)==0
|
||||
){
|
||||
/* Found a rewrite case. Make sure it is not a duplicate */
|
||||
unsigned int h;
|
||||
fuzzer_stem *pLookup;
|
||||
|
||||
fuzzerComputeWord(pCur, pStem);
|
||||
h = fuzzerHash(pCur->zBuf);
|
||||
pLookup = pCur->apHash[h];
|
||||
while( pLookup && strcmp(pLookup->zBasis, pCur->zBuf)!=0 ){
|
||||
pLookup = pLookup->pHash;
|
||||
}
|
||||
if( pLookup==0 ) return 1; /* A new output is found. */
|
||||
}
|
||||
}
|
||||
pStem->n = -1;
|
||||
pStem->pRule = pRule->pNext;
|
||||
if( fuzzerCost(pStem)>pCur->rLimit ) pStem->pRule = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Insert pNew into the list at pList. Return a pointer to the new
|
||||
** list. The insert is done such the pNew is in the correct order
|
||||
** according to fuzzer_stem.zBaseCost+fuzzer_stem.pRule->rCost.
|
||||
*/
|
||||
static fuzzer_stem *fuzzerInsert(fuzzer_stem *pList, fuzzer_stem *pNew){
|
||||
fuzzer_cost c1;
|
||||
|
||||
c1 = fuzzerCost(pNew);
|
||||
if( c1 <= fuzzerCost(pList) ){
|
||||
pNew->pNext = pList;
|
||||
return pNew;
|
||||
}else{
|
||||
fuzzer_stem *pPrev;
|
||||
pPrev = pList;
|
||||
while( pPrev->pNext && fuzzerCost(pPrev->pNext)<c1 ){
|
||||
pPrev = pPrev->pNext;
|
||||
}
|
||||
pNew->pNext = pPrev->pNext;
|
||||
pPrev->pNext = pNew;
|
||||
return pList;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Allocate a new fuzzer_stem. Add it to the hash table but do not
|
||||
** link it into either the pCur->pStem or pCur->pDone lists.
|
||||
*/
|
||||
static fuzzer_stem *fuzzerNewStem(
|
||||
fuzzer_cursor *pCur,
|
||||
const char *zWord,
|
||||
fuzzer_cost rBaseCost
|
||||
){
|
||||
fuzzer_stem *pNew;
|
||||
unsigned int h;
|
||||
|
||||
pNew = sqlite3_malloc( sizeof(*pNew) + strlen(zWord) + 1 );
|
||||
if( pNew==0 ) return 0;
|
||||
memset(pNew, 0, sizeof(*pNew));
|
||||
pNew->zBasis = (char*)&pNew[1];
|
||||
pNew->nBasis = strlen(zWord);
|
||||
memcpy(pNew->zBasis, zWord, pNew->nBasis+1);
|
||||
pNew->pRule = pCur->pVtab->pRule;
|
||||
pNew->n = -1;
|
||||
pNew->rBaseCost = rBaseCost;
|
||||
h = fuzzerHash(pNew->zBasis);
|
||||
pNew->pHash = pCur->apHash[h];
|
||||
pCur->apHash[h] = pNew;
|
||||
return pNew;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Advance a cursor to its next row of output
|
||||
*/
|
||||
static int fuzzerNext(sqlite3_vtab_cursor *cur){
|
||||
fuzzer_cursor *pCur = (fuzzer_cursor*)pCur;
|
||||
fuzzer_stem *pStem, *pNew;
|
||||
|
||||
/* Use the element the cursor is currently point to to create
|
||||
** a new stem and insert the new stem into the priority queue.
|
||||
*/
|
||||
fuzzerComputeWord(pCur, pCur->pStem);
|
||||
pNew = fuzzerNewStem(pCur, pCur->zBuf, fuzzerCost(pCur->pStem));
|
||||
if( pNew ){
|
||||
if( fuzzerAdvance(pCur, pNew)==0 ){
|
||||
pNew->pNext = pCur->pDone;
|
||||
pCur->pDone = pNew;
|
||||
}else{
|
||||
pCur->pStem = fuzzerInsert(pCur->pStem, pNew);
|
||||
}
|
||||
}
|
||||
|
||||
/* Adjust the priority queue so that the first element of the
|
||||
** stem list is the next lowest cost word.
|
||||
*/
|
||||
while( (pStem = pCur->pStem)!=0 ){
|
||||
if( fuzzerAdvance(pCur, pStem) ){
|
||||
pCur->pStem = fuzzerInsert(pStem->pNext, pStem);
|
||||
return SQLITE_OK; /* New word found */
|
||||
}
|
||||
pCur->pStem = pStem->pNext;
|
||||
pStem->pNext = pCur->pDone;
|
||||
pCur->pDone = pStem;
|
||||
}
|
||||
|
||||
/* Reach this point only if queue has been exhausted and there is
|
||||
** nothing left to be output. */
|
||||
pCur->rLimit = (fuzzer_cost)0;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Called to "rewind" a cursor back to the beginning so that
|
||||
** it starts its output over again. Always called at least once
|
||||
** prior to any fuzzerColumn, fuzzerRowid, or fuzzerEof call.
|
||||
*/
|
||||
static int fuzzerFilter(
|
||||
sqlite3_vtab_cursor *pVtabCursor,
|
||||
int idxNum, const char *idxStr,
|
||||
int argc, sqlite3_value **argv
|
||||
){
|
||||
fuzzer_cursor *pCur = (fuzzer_cursor *)pVtabCursor;
|
||||
return fuzzerNext(pVtabCursor);
|
||||
const char *zWord = 0;
|
||||
pCur->rLimit = 2147483647;
|
||||
|
||||
fuzzerClearCursor(pCur, 1);
|
||||
if( idxNum==1 ){
|
||||
zWord = (const char*)sqlite3_value_text(argv[0]);
|
||||
}else if( idxNum==2 ){
|
||||
pCur->rLimit = (fuzzer_cost)sqlite3_value_int(argv[0]);
|
||||
}else if( idxNum==3 ){
|
||||
zWord = (const char*)sqlite3_value_text(argv[0]);
|
||||
pCur->rLimit = (fuzzer_cost)sqlite3_value_int(argv[1]);
|
||||
}
|
||||
if( zWord==0 ) zWord = "";
|
||||
pCur->pStem = fuzzerNewStem(pCur, zWord, (fuzzer_cost)0);
|
||||
if( pCur->pStem==0 ) return SQLITE_NOMEM;
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Only the word and distance columns have values. All other columns
|
||||
** return NULL
|
||||
*/
|
||||
static int fuzzerColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
|
||||
fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
|
||||
if( i==0 ){
|
||||
/* the "word" column */
|
||||
if( fuzzerComputeWord(pCur, pCur->pStem)==SQLITE_NOMEM ){
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
sqlite3_result_text(ctx, pCur->zBuf, -1, SQLITE_TRANSIENT);
|
||||
}else if( i==1 ){
|
||||
/* the "distance" column */
|
||||
sqlite3_result_int(ctx, fuzzerCost(pCur->pStem));
|
||||
}else{
|
||||
/* All other columns are NULL */
|
||||
sqlite3_result_null(ctx);
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The rowid is always 0
|
||||
*/
|
||||
static int fuzzerRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
|
||||
*pRowid = 0;
|
||||
*pRowid = 0; /* The rowid is always 0 */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** When the fuzzer_cursor.rLimit value is 0 or less, that is a signal
|
||||
** that the cursor has nothing more to output.
|
||||
*/
|
||||
static int fuzzerEof(sqlite3_vtab_cursor *cur){
|
||||
fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
|
||||
return 1;
|
||||
return pCur->rLimit<=(fuzzer_cost)0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Search for terms of these forms:
|
||||
**
|
||||
** word MATCH $str
|
||||
** distance < $value
|
||||
** distance <= $value
|
||||
**
|
||||
** The distance< and distance<= are both treated as distance<=.
|
||||
** The query plan number is as follows:
|
||||
**
|
||||
** 0: None of the terms above are found
|
||||
** 1: There is a "word MATCH" term with $str in filter.argv[0].
|
||||
** 2: There is a "distance<" term with $value in filter.argv[0].
|
||||
** 3: Both "word MATCH" and "distance<" with $str in argv[0] and
|
||||
** $value in argv[1].
|
||||
*/
|
||||
static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
|
||||
int iPlan = 0;
|
||||
int iDistTerm = -1;
|
||||
int i;
|
||||
const struct sqlite3_index_constraint *pConstraint;
|
||||
pConstraint = pIdxInfo->aConstraint;
|
||||
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
|
||||
if( pConstraint->usable==0 ) continue;
|
||||
if( (iPlan & 1)==0
|
||||
&& pConstraint->iColumn==0
|
||||
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH
|
||||
){
|
||||
iPlan |= 1;
|
||||
pIdxInfo->aConstraintUsage[i].argvIndex = 1;
|
||||
pIdxInfo->aConstraintUsage[i].omit = 1;
|
||||
}
|
||||
if( (iPlan & 2)==0
|
||||
&& pConstraint->iColumn==1
|
||||
&& (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT
|
||||
|| pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE)
|
||||
){
|
||||
iPlan |= 2;
|
||||
iDistTerm = i;
|
||||
}
|
||||
}
|
||||
if( iPlan==2 ){
|
||||
pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = 1;
|
||||
}else if( iPlan==3 ){
|
||||
pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = 2;
|
||||
}
|
||||
pIdxInfo->idxNum = iPlan;
|
||||
if( pIdxInfo->nOrderBy==1
|
||||
&& pIdxInfo->aOrderBy[0].iColumn==1
|
||||
&& pIdxInfo->aOrderBy[0].desc==0
|
||||
){
|
||||
pIdxInfo->orderByConsumed = 1;
|
||||
}
|
||||
pIdxInfo->estimatedCost = (double)10000;
|
||||
|
||||
return SQLITE_OK;
|
||||
}
|
||||
@ -274,8 +540,8 @@ static int fuzzerUpdate(
|
||||
int nFrom;
|
||||
const char *zTo;
|
||||
int nTo;
|
||||
float rCost;
|
||||
if( argc!=8 ){
|
||||
fuzzer_cost rCost;
|
||||
if( argc!=7 ){
|
||||
sqlite3_free(pVTab->zErrMsg);
|
||||
pVTab->zErrMsg = sqlite3_mprintf("cannot delete from a %s virtual table",
|
||||
p->zClassName);
|
||||
@ -295,7 +561,7 @@ static int fuzzerUpdate(
|
||||
/* Silently ignore null transformations */
|
||||
return SQLITE_OK;
|
||||
}
|
||||
rCost = (float)sqlite3_value_double(argv[6]);
|
||||
rCost = sqlite3_value_int(argv[6]);
|
||||
if( rCost<=0 ){
|
||||
sqlite3_free(pVTab->zErrMsg);
|
||||
pVTab->zErrMsg = sqlite3_mprintf("cost must be positive");
|
||||
@ -309,8 +575,10 @@ static int fuzzerUpdate(
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
pRule->zFrom = &pRule->zTo[nTo];
|
||||
pRule->nFrom = nFrom;
|
||||
memcpy(pRule->zFrom, zFrom, nFrom);
|
||||
memcpy(pRule->zTo, zTo, nTo);
|
||||
pRule->nTo = nTo;
|
||||
pRule->rCost = rCost;
|
||||
pRule->pNext = p->pNewRule;
|
||||
p->pNewRule = pRule;
|
||||
|
@ -31,9 +31,15 @@ do_test fuzzer1-1.1 {
|
||||
} {}
|
||||
do_test fuzzer1-1.2 {
|
||||
db eval {
|
||||
INSERT INTO f1(cfrom, cto, cost) VALUES('e','a',0.1);
|
||||
INSERT INTO f1(cfrom, cto, cost) VALUES('a','e',0.1);
|
||||
INSERT INTO f1(cfrom, cto, cost) VALUES('e','o',0.1);
|
||||
INSERT INTO f1(cfrom, cto, cost) VALUES('e','a',1);
|
||||
INSERT INTO f1(cfrom, cto, cost) VALUES('a','e',1);
|
||||
INSERT INTO f1(cfrom, cto, cost) VALUES('e','o',2);
|
||||
}
|
||||
} {}
|
||||
|
||||
do_test fuzzer1-1.3 {
|
||||
db eval {
|
||||
SELECT word, distance FROM f1 WHERE word MATCH 'abcde'
|
||||
}
|
||||
} {}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user