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