#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#if !defined(NDEBUG) && !defined(SQLITE_DEBUG)
# define NDEBUG
#endif
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#ifndef SQLITE_OMIT_VIRTUALTABLE
typedef struct fuzzer_vtab fuzzer_vtab;
typedef struct fuzzer_cursor fuzzer_cursor;
typedef struct fuzzer_rule fuzzer_rule;
typedef struct fuzzer_seen fuzzer_seen;
typedef struct fuzzer_stem fuzzer_stem;
typedef int fuzzer_cost;
typedef signed char fuzzer_len;
typedef int fuzzer_ruleid;
#define FUZZER_MX_LENGTH 50
#define FUZZER_MX_RULEID 2147483647
#define FUZZER_MX_COST 1000
#define FUZZER_MX_OUTPUT_LENGTH 100
struct fuzzer_rule {
fuzzer_rule *pNext;
char *zFrom;
fuzzer_cost rCost;
fuzzer_len nFrom, nTo;
fuzzer_ruleid iRuleset;
char zTo[4];
};
struct fuzzer_stem {
char *zBasis;
const fuzzer_rule *pRule;
fuzzer_stem *pNext;
fuzzer_stem *pHash;
fuzzer_cost rBaseCost;
fuzzer_cost rCostX;
fuzzer_len nBasis;
fuzzer_len n;
};
struct fuzzer_vtab {
sqlite3_vtab base;
char *zClassName;
fuzzer_rule *pRule;
int nCursor;
};
#define FUZZER_HASH 4001
#define FUZZER_NQUEUE 20
struct fuzzer_cursor {
sqlite3_vtab_cursor base;
sqlite3_int64 iRowid;
fuzzer_vtab *pVtab;
fuzzer_cost rLimit;
fuzzer_stem *pStem;
fuzzer_stem *pDone;
fuzzer_stem *aQueue[FUZZER_NQUEUE];
int mxQueue;
char *zBuf;
int nBuf;
int nStem;
int iRuleset;
fuzzer_rule nullRule;
fuzzer_stem *apHash[FUZZER_HASH];
};
static fuzzer_rule *fuzzerMergeRules(fuzzer_rule *pA, fuzzer_rule *pB){
fuzzer_rule head;
fuzzer_rule *pTail;
pTail = &head;
while( pA && pB ){
if( pA->rCost<=pB->rCost ){
pTail->pNext = pA;
pTail = pA;
pA = pA->pNext;
}else{
pTail->pNext = pB;
pTail = pB;
pB = pB->pNext;
}
}
if( pA==0 ){
pTail->pNext = pB;
}else{
pTail->pNext = pA;
}
return head.pNext;
}
static int fuzzerLoadOneRule(
fuzzer_vtab *p,
sqlite3_stmt *pStmt,
fuzzer_rule **ppRule,
char **pzErr
){
sqlite3_int64 iRuleset = sqlite3_column_int64(pStmt, 0);
const char *zFrom = (const char *)sqlite3_column_text(pStmt, 1);
const char *zTo = (const char *)sqlite3_column_text(pStmt, 2);
int nCost = sqlite3_column_int(pStmt, 3);
int rc = SQLITE_OK;
int nFrom;
int nTo;
fuzzer_rule *pRule = 0;
if( zFrom==0 ) zFrom = "";
if( zTo==0 ) zTo = "";
nFrom = (int)strlen(zFrom);
nTo = (int)strlen(zTo);
if( strcmp(zFrom, zTo)==0 ){
*ppRule = 0;
return SQLITE_OK;
}
if( nCost<=0 || nCost>FUZZER_MX_COST ){
*pzErr = sqlite3_mprintf("%s: cost must be between 1 and %d",
p->zClassName, FUZZER_MX_COST
);
rc = SQLITE_ERROR;
}else
if( nFrom>FUZZER_MX_LENGTH || nTo>FUZZER_MX_LENGTH ){
*pzErr = sqlite3_mprintf("%s: maximum string length is %d",
p->zClassName, FUZZER_MX_LENGTH
);
rc = SQLITE_ERROR;
}else
if( iRuleset<0 || iRuleset>FUZZER_MX_RULEID ){
*pzErr = sqlite3_mprintf("%s: ruleset must be between 0 and %d",
p->zClassName, FUZZER_MX_RULEID
);
rc = SQLITE_ERROR;
}else{
pRule = sqlite3_malloc64( sizeof(*pRule) + nFrom + nTo );
if( pRule==0 ){
rc = SQLITE_NOMEM;
}else{
memset(pRule, 0, sizeof(*pRule));
pRule->zFrom = pRule->zTo;
pRule->zFrom += nTo + 1;
pRule->nFrom = (fuzzer_len)nFrom;
memcpy(pRule->zFrom, zFrom, nFrom+1);
memcpy(pRule->zTo, zTo, nTo+1);
pRule->nTo = (fuzzer_len)nTo;
pRule->rCost = nCost;
pRule->iRuleset = (int)iRuleset;
}
}
*ppRule = pRule;
return rc;
}
static int fuzzerLoadRules(
sqlite3 *db,
fuzzer_vtab *p,
const char *zDb,
const char *zData,
char **pzErr
){
int rc = SQLITE_OK;
char *zSql;
fuzzer_rule *pHead = 0;
zSql = sqlite3_mprintf("SELECT * FROM %Q.%Q", zDb, zData);
if( zSql==0 ){
rc = SQLITE_NOMEM;
}else{
int rc2;
sqlite3_stmt *pStmt = 0;
rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0);
if( rc!=SQLITE_OK ){
*pzErr = sqlite3_mprintf("%s: %s", p->zClassName, sqlite3_errmsg(db));
}else if( sqlite3_column_count(pStmt)!=4 ){
*pzErr = sqlite3_mprintf("%s: %s has %d columns, expected 4",
p->zClassName, zData, sqlite3_column_count(pStmt)
);
rc = SQLITE_ERROR;
}else{
while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){
fuzzer_rule *pRule = 0;
rc = fuzzerLoadOneRule(p, pStmt, &pRule, pzErr);
if( pRule ){
pRule->pNext = pHead;
pHead = pRule;
}
}
}
rc2 = sqlite3_finalize(pStmt);
if( rc==SQLITE_OK ) rc = rc2;
}
sqlite3_free(zSql);
if( rc==SQLITE_OK ){
unsigned int i;
fuzzer_rule *pX;
fuzzer_rule *a[15];
for(i=0; i<sizeof(a)/sizeof(a[0]); i++) a[i] = 0;
while( (pX = pHead)!=0 ){
pHead = pX->pNext;
pX->pNext = 0;
for(i=0; a[i] && i<sizeof(a)/sizeof(a[0])-1; i++){
pX = fuzzerMergeRules(a[i], pX);
a[i] = 0;
}
a[i] = fuzzerMergeRules(a[i], pX);
}
for(pX=a[0], i=1; i<sizeof(a)/sizeof(a[0]); i++){
pX = fuzzerMergeRules(a[i], pX);
}
p->pRule = fuzzerMergeRules(p->pRule, pX);
}else{
assert( p->pRule==0 );
p->pRule = pHead;
}
return rc;
}
static char *fuzzerDequote(const char *zIn){
sqlite3_int64 nIn;
char *zOut;
nIn = strlen(zIn);
zOut = sqlite3_malloc64(nIn+1);
if( zOut ){
char q = zIn[0];
if( q!='[' && q!= '\'' && q!='"' && q!='`' ){
memcpy(zOut, zIn, (size_t)(nIn+1));
}else{
int iOut = 0;
int iIn;
if( q=='[' ) q = ']';
for(iIn=1; iIn<nIn; iIn++){
if( zIn[iIn]==q ) iIn++;
zOut[iOut++] = zIn[iIn];
}
}
assert( (int)strlen(zOut)<=nIn );
}
return zOut;
}
static int fuzzerDisconnect(sqlite3_vtab *pVtab){
fuzzer_vtab *p = (fuzzer_vtab*)pVtab;
assert( p->nCursor==0 );
while( p->pRule ){
fuzzer_rule *pRule = p->pRule;
p->pRule = pRule->pNext;
sqlite3_free(pRule);
}
sqlite3_free(p);
return SQLITE_OK;
}
static int fuzzerConnect(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
int rc = SQLITE_OK;
fuzzer_vtab *pNew = 0;
const char *zModule = argv[0];
const char *zDb = argv[1];
if( argc!=4 ){
*pzErr = sqlite3_mprintf(
"%s: wrong number of CREATE VIRTUAL TABLE arguments", zModule
);
rc = SQLITE_ERROR;
}else{
sqlite3_int64 nModule;
nModule = strlen(zModule);
pNew = sqlite3_malloc64( sizeof(*pNew) + nModule + 1);
if( pNew==0 ){
rc = SQLITE_NOMEM;
}else{
char *zTab;
memset(pNew, 0, sizeof(*pNew));
pNew->zClassName = (char*)&pNew[1];
memcpy(pNew->zClassName, zModule, (size_t)(nModule+1));
zTab = fuzzerDequote(argv[3]);
if( zTab==0 ){
rc = SQLITE_NOMEM;
}else{
rc = fuzzerLoadRules(db, pNew, zDb, zTab, pzErr);
sqlite3_free(zTab);
}
if( rc==SQLITE_OK ){
rc = sqlite3_declare_vtab(db, "CREATE TABLE x(word,distance,ruleset)");
}
if( rc!=SQLITE_OK ){
fuzzerDisconnect((sqlite3_vtab *)pNew);
pNew = 0;
}else{
sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
}
}
}
*ppVtab = (sqlite3_vtab *)pNew;
return rc;
}
static int fuzzerOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){
fuzzer_vtab *p = (fuzzer_vtab*)pVTab;
fuzzer_cursor *pCur;
pCur = sqlite3_malloc( sizeof(*pCur) );
if( pCur==0 ) return SQLITE_NOMEM;
memset(pCur, 0, sizeof(*pCur));
pCur->pVtab = p;
*ppCursor = &pCur->base;
p->nCursor++;
return SQLITE_OK;
}
static void fuzzerClearStemList(fuzzer_stem *pStem){
while( pStem ){
fuzzer_stem *pNext = pStem->pNext;
sqlite3_free(pStem);
pStem = pNext;
}
}
static void fuzzerClearCursor(fuzzer_cursor *pCur, int clearHash){
int i;
fuzzerClearStemList(pCur->pStem);
fuzzerClearStemList(pCur->pDone);
for(i=0; i<FUZZER_NQUEUE; i++) fuzzerClearStemList(pCur->aQueue[i]);
pCur->rLimit = (fuzzer_cost)0;
if( clearHash && pCur->nStem ){
pCur->mxQueue = 0;
pCur->pStem = 0;
pCur->pDone = 0;
memset(pCur->aQueue, 0, sizeof(pCur->aQueue));
memset(pCur->apHash, 0, sizeof(pCur->apHash));
}
pCur->nStem = 0;
}
static int fuzzerClose(sqlite3_vtab_cursor *cur){
fuzzer_cursor *pCur = (fuzzer_cursor *)cur;
fuzzerClearCursor(pCur, 0);
sqlite3_free(pCur->zBuf);
pCur->pVtab->nCursor--;
sqlite3_free(pCur);
return SQLITE_OK;
}
static int fuzzerRender(
fuzzer_stem *pStem,
char **pzBuf,
int *pnBuf
){
const fuzzer_rule *pRule = pStem->pRule;
int n;
char *z;
n = pStem->nBasis + pRule->nTo - pRule->nFrom;
if( (*pnBuf)<n+1 ){
(*pzBuf) = sqlite3_realloc((*pzBuf), n+100);
if( (*pzBuf)==0 ) return SQLITE_NOMEM;
(*pnBuf) = n+100;
}
n = pStem->n;
z = *pzBuf;
if( n<0 ){
memcpy(z, pStem->zBasis, pStem->nBasis+1);
}else{
memcpy(z, pStem->zBasis, n);
memcpy(&z[n], pRule->zTo, pRule->nTo);
memcpy(&z[n+pRule->nTo], &pStem->zBasis[n+pRule->nFrom],
pStem->nBasis-n-pRule->nFrom+1);
}
assert( z[pStem->nBasis + pRule->nTo - pRule->nFrom]==0 );
return SQLITE_OK;
}
static unsigned int fuzzerHash(const char *z){
unsigned int h = 0;
while( *z ){ h = (h<<3) ^ (h>>29) ^ *(z++); }
return h % FUZZER_HASH;
}
static fuzzer_cost fuzzerCost(fuzzer_stem *pStem){
return pStem->rCostX = pStem->rBaseCost + pStem->pRule->rCost;
}
#if 0#endif
static int fuzzerSeen(fuzzer_cursor *pCur, fuzzer_stem *pStem){
unsigned int h;
fuzzer_stem *pLookup;
if( fuzzerRender(pStem, &pCur->zBuf, &pCur->nBuf)==SQLITE_NOMEM ){
return -1;
}
h = fuzzerHash(pCur->zBuf);
pLookup = pCur->apHash[h];
while( pLookup && strcmp(pLookup->zBasis, pCur->zBuf)!=0 ){
pLookup = pLookup->pHash;
}
return pLookup!=0;
}
static int fuzzerSkipRule(
const fuzzer_rule *pRule,
fuzzer_stem *pStem,
int iRuleset
){
return pRule && (
(pRule->iRuleset!=iRuleset)
|| (pStem->nBasis + pRule->nTo - pRule->nFrom)>FUZZER_MX_OUTPUT_LENGTH
);
}
static int fuzzerAdvance(fuzzer_cursor *pCur, fuzzer_stem *pStem){
const fuzzer_rule *pRule;
while( (pRule = pStem->pRule)!=0 ){
assert( pRule==&pCur->nullRule || pRule->iRuleset==pCur->iRuleset );
while( pStem->n < pStem->nBasis - pRule->nFrom ){
pStem->n++;
if( pRule->nFrom==0
|| memcmp(&pStem->zBasis[pStem->n], pRule->zFrom, pRule->nFrom)==0
){
int rc = fuzzerSeen(pCur, pStem);
if( rc<0 ) return -1;
if( rc==0 ){
fuzzerCost(pStem);
return 1;
}
}
}
pStem->n = -1;
do{
pRule = pRule->pNext;
}while( fuzzerSkipRule(pRule, pStem, pCur->iRuleset) );
pStem->pRule = pRule;
if( pRule && fuzzerCost(pStem)>pCur->rLimit ) pStem->pRule = 0;
}
return 0;
}
static fuzzer_stem *fuzzerMergeStems(fuzzer_stem *pA, fuzzer_stem *pB){
fuzzer_stem head;
fuzzer_stem *pTail;
pTail = &head;
while( pA && pB ){
if( pA->rCostX<=pB->rCostX ){
pTail->pNext = pA;
pTail = pA;
pA = pA->pNext;
}else{
pTail->pNext = pB;
pTail = pB;
pB = pB->pNext;
}
}
if( pA==0 ){
pTail->pNext = pB;
}else{
pTail->pNext = pA;
}
return head.pNext;
}
static fuzzer_stem *fuzzerLowestCostStem(fuzzer_cursor *pCur){
fuzzer_stem *pBest, *pX;
int iBest;
int i;
if( pCur->pStem==0 ){
iBest = -1;
pBest = 0;
for(i=0; i<=pCur->mxQueue; i++){
pX = pCur->aQueue[i];
if( pX==0 ) continue;
if( pBest==0 || pBest->rCostX>pX->rCostX ){
pBest = pX;
iBest = i;
}
}
if( pBest ){
pCur->aQueue[iBest] = pBest->pNext;
pBest->pNext = 0;
pCur->pStem = pBest;
}
}
return pCur->pStem;
}
static fuzzer_stem *fuzzerInsert(fuzzer_cursor *pCur, fuzzer_stem *pNew){
fuzzer_stem *pX;
int i;
if( (pX = pCur->pStem)!=0 && pX->rCostX>pNew->rCostX ){
pNew->pNext = 0;
pCur->pStem = pNew;
pNew = pX;
}
pNew->pNext = 0;
pX = pNew;
for(i=0; i<=pCur->mxQueue; i++){
if( pCur->aQueue[i] ){
pX = fuzzerMergeStems(pX, pCur->aQueue[i]);
pCur->aQueue[i] = 0;
}else{
pCur->aQueue[i] = pX;
break;
}
}
if( i>pCur->mxQueue ){
if( i<FUZZER_NQUEUE ){
pCur->mxQueue = i;
pCur->aQueue[i] = pX;
}else{
assert( pCur->mxQueue==FUZZER_NQUEUE-1 );
pX = fuzzerMergeStems(pX, pCur->aQueue[FUZZER_NQUEUE-1]);
pCur->aQueue[FUZZER_NQUEUE-1] = pX;
}
}
return fuzzerLowestCostStem(pCur);
}
static fuzzer_stem *fuzzerNewStem(
fuzzer_cursor *pCur,
const char *zWord,
fuzzer_cost rBaseCost
){
fuzzer_stem *pNew;
fuzzer_rule *pRule;
unsigned int h;
pNew = sqlite3_malloc64( sizeof(*pNew) + strlen(zWord) + 1 );
if( pNew==0 ) return 0;
memset(pNew, 0, sizeof(*pNew));
pNew->zBasis = (char*)&pNew[1];
pNew->nBasis = (fuzzer_len)strlen(zWord);
memcpy(pNew->zBasis, zWord, pNew->nBasis+1);
pRule = pCur->pVtab->pRule;
while( fuzzerSkipRule(pRule, pNew, pCur->iRuleset) ){
pRule = pRule->pNext;
}
pNew->pRule = pRule;
pNew->n = -1;
pNew->rBaseCost = pNew->rCostX = rBaseCost;
h = fuzzerHash(pNew->zBasis);
pNew->pHash = pCur->apHash[h];
pCur->apHash[h] = pNew;
pCur->nStem++;
return pNew;
}
static int fuzzerNext(sqlite3_vtab_cursor *cur){
fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
int rc;
fuzzer_stem *pStem, *pNew;
pCur->iRowid++;
pStem = pCur->pStem;
if( pStem->rCostX>0 ){
rc = fuzzerRender(pStem, &pCur->zBuf, &pCur->nBuf);
if( rc==SQLITE_NOMEM ) return SQLITE_NOMEM;
pNew = fuzzerNewStem(pCur, pCur->zBuf, pStem->rCostX);
if( pNew ){
if( fuzzerAdvance(pCur, pNew)==0 ){
pNew->pNext = pCur->pDone;
pCur->pDone = pNew;
}else{
if( fuzzerInsert(pCur, pNew)==pNew ){
return SQLITE_OK;
}
}
}else{
return SQLITE_NOMEM;
}
}
while( (pStem = pCur->pStem)!=0 ){
int res = fuzzerAdvance(pCur, pStem);
if( res<0 ){
return SQLITE_NOMEM;
}else if( res>0 ){
pCur->pStem = 0;
pStem = fuzzerInsert(pCur, pStem);
if( (rc = fuzzerSeen(pCur, pStem))!=0 ){
if( rc<0 ) return SQLITE_NOMEM;
continue;
}
return SQLITE_OK;
}
pCur->pStem = 0;
pStem->pNext = pCur->pDone;
pCur->pDone = pStem;
if( fuzzerLowestCostStem(pCur) ){
rc = fuzzerSeen(pCur, pCur->pStem);
if( rc<0 ) return SQLITE_NOMEM;
if( rc==0 ){
return SQLITE_OK;
}
}
}
pCur->rLimit = (fuzzer_cost)0;
return SQLITE_OK;
}
static int fuzzerFilter(
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
fuzzer_cursor *pCur = (fuzzer_cursor *)pVtabCursor;
const char *zWord = "";
fuzzer_stem *pStem;
int idx;
fuzzerClearCursor(pCur, 1);
pCur->rLimit = 2147483647;
idx = 0;
if( idxNum & 1 ){
zWord = (const char*)sqlite3_value_text(argv[0]);
idx++;
}
if( idxNum & 2 ){
pCur->rLimit = (fuzzer_cost)sqlite3_value_int(argv[idx]);
idx++;
}
if( idxNum & 4 ){
pCur->iRuleset = (fuzzer_cost)sqlite3_value_int(argv[idx]);
idx++;
}
pCur->nullRule.pNext = pCur->pVtab->pRule;
pCur->nullRule.rCost = 0;
pCur->nullRule.nFrom = 0;
pCur->nullRule.nTo = 0;
pCur->nullRule.zFrom = "";
pCur->iRowid = 1;
assert( pCur->pStem==0 );
if( (int)strlen(zWord)<FUZZER_MX_OUTPUT_LENGTH ){
pCur->pStem = pStem = fuzzerNewStem(pCur, zWord, (fuzzer_cost)0);
if( pStem==0 ) return SQLITE_NOMEM;
pStem->pRule = &pCur->nullRule;
pStem->n = pStem->nBasis;
}else{
pCur->rLimit = 0;
}
return SQLITE_OK;
}
static int fuzzerColumn(sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i){
fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
if( i==0 ){
if( fuzzerRender(pCur->pStem, &pCur->zBuf, &pCur->nBuf)==SQLITE_NOMEM ){
return SQLITE_NOMEM;
}
sqlite3_result_text(ctx, pCur->zBuf, -1, SQLITE_TRANSIENT);
}else if( i==1 ){
sqlite3_result_int(ctx, pCur->pStem->rCostX);
}else{
sqlite3_result_null(ctx);
}
return SQLITE_OK;
}
static int fuzzerRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){
fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
*pRowid = pCur->iRowid;
return SQLITE_OK;
}
static int fuzzerEof(sqlite3_vtab_cursor *cur){
fuzzer_cursor *pCur = (fuzzer_cursor*)cur;
return pCur->rLimit<=(fuzzer_cost)0;
}
static int fuzzerBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
int iPlan = 0;
int iDistTerm = -1;
int iRulesetTerm = -1;
int i;
int seenMatch = 0;
const struct sqlite3_index_constraint *pConstraint;
double rCost = 1e12;
pConstraint = pIdxInfo->aConstraint;
for(i=0; i<pIdxInfo->nConstraint; i++, pConstraint++){
if( pConstraint->iColumn==0
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH ){
seenMatch = 1;
}
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;
rCost /= 1e6;
}
if( (iPlan & 2)==0
&& pConstraint->iColumn==1
&& (pConstraint->op==SQLITE_INDEX_CONSTRAINT_LT
|| pConstraint->op==SQLITE_INDEX_CONSTRAINT_LE)
){
iPlan |= 2;
iDistTerm = i;
rCost /= 10.0;
}
if( (iPlan & 4)==0
&& pConstraint->iColumn==2
&& pConstraint->op==SQLITE_INDEX_CONSTRAINT_EQ
){
iPlan |= 4;
pIdxInfo->aConstraintUsage[i].omit = 1;
iRulesetTerm = i;
rCost /= 10.0;
}
}
if( iPlan & 2 ){
pIdxInfo->aConstraintUsage[iDistTerm].argvIndex = 1+((iPlan&1)!=0);
}
if( iPlan & 4 ){
int idx = 1;
if( iPlan & 1 ) idx++;
if( iPlan & 2 ) idx++;
pIdxInfo->aConstraintUsage[iRulesetTerm].argvIndex = idx;
}
pIdxInfo->idxNum = iPlan;
if( pIdxInfo->nOrderBy==1
&& pIdxInfo->aOrderBy[0].iColumn==1
&& pIdxInfo->aOrderBy[0].desc==0
){
pIdxInfo->orderByConsumed = 1;
}
if( seenMatch && (iPlan&1)==0 ) rCost = 1e99;
pIdxInfo->estimatedCost = rCost;
return SQLITE_OK;
}
static sqlite3_module fuzzerModule = {
0,
fuzzerConnect,
fuzzerConnect,
fuzzerBestIndex,
fuzzerDisconnect,
fuzzerDisconnect,
fuzzerOpen,
fuzzerClose,
fuzzerFilter,
fuzzerNext,
fuzzerEof,
fuzzerColumn,
fuzzerRowid,
0,
0,
0,
0,
0,
0,
0,
};
#endif
#ifdef _WIN32
__declspec(dllexport)
#endif
int sqlite3_fuzzer_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
int rc = SQLITE_OK;
SQLITE_EXTENSION_INIT2(pApi);
#ifndef SQLITE_OMIT_VIRTUALTABLE
rc = sqlite3_create_module(db, "fuzzer", &fuzzerModule, 0);
#endif
return rc;
}