From: dan Date: Wed, 19 Jun 2013 20:13:28 +0000 (+0000) Subject: Add the languageid_bits= option to fts. Still some problems to work out. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1abd0ae27c161806c9ad6a01951041ad2ddc5339;p=thirdparty%2Fsqlite.git Add the languageid_bits= option to fts. Still some problems to work out. FossilOrigin-Name: d36d7e68334c0685d1941dd0323b1a9c5c7368bf --- diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 374d690688..7a05371da4 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -1081,6 +1081,7 @@ static int fts3InitVtab( char *zUncompress = 0; /* uncompress=? parameter (or NULL) */ char *zContent = 0; /* content=? parameter (or NULL) */ char *zLanguageid = 0; /* languageid=? parameter (or NULL) */ + char *zLanguageidBits = 0; /* languageid_bits=? parameter (or NULL) */ assert( strlen(argv[0])==4 ); assert( (sqlite3_strnicmp(argv[0], "fts4", 4)==0 && isFts4) @@ -1125,13 +1126,14 @@ static int fts3InitVtab( const char *zOpt; int nOpt; } aFts4Opt[] = { - { "matchinfo", 9 }, /* 0 -> MATCHINFO */ - { "prefix", 6 }, /* 1 -> PREFIX */ - { "compress", 8 }, /* 2 -> COMPRESS */ - { "uncompress", 10 }, /* 3 -> UNCOMPRESS */ - { "order", 5 }, /* 4 -> ORDER */ - { "content", 7 }, /* 5 -> CONTENT */ - { "languageid", 10 } /* 6 -> LANGUAGEID */ + { "matchinfo", 9 }, /* 0 -> MATCHINFO */ + { "prefix", 6 }, /* 1 -> PREFIX */ + { "compress", 8 }, /* 2 -> COMPRESS */ + { "uncompress", 10 }, /* 3 -> UNCOMPRESS */ + { "order", 5 }, /* 4 -> ORDER */ + { "content", 7 }, /* 5 -> CONTENT */ + { "languageid", 10 }, /* 6 -> LANGUAGEID */ + { "languageid_bits", 15 } /* 7 -> LANGUAGEID_BITS */ }; int iOpt; @@ -1197,6 +1199,13 @@ static int fts3InitVtab( zLanguageid = zVal; zVal = 0; break; + + case 7: /* LANGUAGEID_BITS */ + assert( iOpt==7 ); + sqlite3_free(zLanguageidBits); + zLanguageidBits = zVal; + zVal = 0; + break; } } sqlite3_free(zVal); @@ -1292,6 +1301,15 @@ static int fts3InitVtab( p->zLanguageid = zLanguageid; zContent = 0; zLanguageid = 0; + if( zLanguageidBits && p->zLanguageid && p->zContentTbl==0 ){ + p->nLanguageidBits = atoi(zLanguageidBits); + if( p->nLanguageidBits>32 || p->nLanguageidBits<0 ){ + rc = SQLITE_ERROR; + *pzErr = sqlite3_mprintf("languageid_bits parameter out of range"); + goto fts3_init_out; + } + } + TESTONLY( p->inTransaction = -1 ); TESTONLY( p->mxSavepoint = -1 ); @@ -1365,6 +1383,7 @@ fts3_init_out: sqlite3_free(zUncompress); sqlite3_free(zContent); sqlite3_free(zLanguageid); + sqlite3_free(zLanguageidBits); sqlite3_free((void *)aCol); if( rc!=SQLITE_OK ){ if( p ){ @@ -3062,10 +3081,10 @@ static int fts3ColumnMethod( assert( iCol>=0 && iCol<=p->nColumn+2 ); if( iCol==p->nColumn+1 ){ - /* This call is a request for the "docid" column. Since "docid" is an - ** alias for "rowid", use the xRowid() method to obtain the value. - */ - sqlite3_result_int64(pCtx, pCsr->iPrevId); + /* This call is a request for the "docid" column. The value currently + ** stored in pCsr->iPrevId is a rowid. Transform this to a docid and + ** return it. */ + sqlite3_result_int64(pCtx, sqlite3Fts3RowidToDocid(p, pCsr->iPrevId)); }else if( iCol==p->nColumn ){ /* The extra column whose name is the same as the table. ** Return a blob which is a pointer to the cursor. */ diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index 5d1706c927..18337dbe13 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -209,6 +209,7 @@ struct Fts3Table { sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ char *zContentTbl; /* content=xxx option, or NULL */ char *zLanguageid; /* languageid=xxx option, or NULL */ + int nLanguageidBits; /* languageid_bits=N option, or 0 */ u8 bAutoincrmerge; /* True if automerge=1 */ u32 nLeafAdd; /* Number of leaf blocks added this trans */ @@ -421,8 +422,9 @@ struct Fts3Expr { #define FTSQUERY_OR 4 #define FTSQUERY_PHRASE 5 - /* fts3_write.c */ +i64 sqlite3Fts3DocidToRowid(Fts3Table *p, i64 iDocid, int iLangid); +i64 sqlite3Fts3RowidToDocid(Fts3Table *p, i64 iRowid); int sqlite3Fts3UpdateMethod(sqlite3_vtab*,int,sqlite3_value**,sqlite3_int64*); int sqlite3Fts3PendingTermsFlush(Fts3Table *); void sqlite3Fts3PendingTermsClear(Fts3Table *); diff --git a/ext/fts3/fts3_write.c b/ext/fts3/fts3_write.c index 2ee0e3d5fa..362ec8e919 100644 --- a/ext/fts3/fts3_write.c +++ b/ext/fts3/fts3_write.c @@ -487,6 +487,24 @@ static void fts3SqlExec( *pRC = rc; } +static void fts3SqlExecI64( + int *pRC, /* Result code */ + Fts3Table *p, /* The FTS3 table */ + int eStmt, /* Index of statement to evaluate */ + i64 iVal +){ + sqlite3_stmt *pStmt; + int rc; + if( *pRC ) return; + rc = fts3SqlStmt(p, eStmt, &pStmt, 0); + if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, iVal); + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + } + *pRC = rc; +} + /* ** This function ensures that the caller has obtained an exclusive @@ -927,20 +945,23 @@ static int fts3InsertTerms( static int fts3InsertData( Fts3Table *p, /* Full-text table */ sqlite3_value **apVal, /* Array of values to insert */ - sqlite3_int64 *piDocid /* OUT: Docid for row just inserted */ + sqlite3_int64 *piRowid, /* OUT: Rowid for row just inserted */ + i64 iRowid /* Explicit rowid, if piRowid==NULL */ ){ int rc; /* Return code */ sqlite3_stmt *pContentInsert; /* INSERT INTO %_content VALUES(...) */ if( p->zContentTbl ){ - sqlite3_value *pRowid = apVal[p->nColumn+3]; + sqlite3_value *pRowid; + assert( p->nLanguageidBits==0 && piRowid ); + pRowid = apVal[p->nColumn+3]; if( sqlite3_value_type(pRowid)==SQLITE_NULL ){ pRowid = apVal[1]; } if( sqlite3_value_type(pRowid)!=SQLITE_INTEGER ){ return SQLITE_CONSTRAINT; } - *piDocid = sqlite3_value_int64(pRowid); + *piRowid = sqlite3_value_int64(pRowid); return SQLITE_OK; } @@ -953,11 +974,16 @@ static int fts3InsertData( ** defined columns in the FTS3 table, plus one for the docid field. */ rc = fts3SqlStmt(p, SQL_CONTENT_INSERT, &pContentInsert, &apVal[1]); - if( rc==SQLITE_OK && p->zLanguageid ){ - rc = sqlite3_bind_int( - pContentInsert, p->nColumn+2, - sqlite3_value_int(apVal[p->nColumn+4]) - ); + if( rc==SQLITE_OK ){ + if( piRowid==0 ){ + sqlite3_bind_int64(pContentInsert, 1, iRowid); + } + if( p->zLanguageid ){ + rc = sqlite3_bind_int( + pContentInsert, p->nColumn+2, + sqlite3_value_int(apVal[p->nColumn+4]) + ); + } } if( rc!=SQLITE_OK ) return rc; @@ -971,7 +997,12 @@ static int fts3InsertData( ** In FTS3, this is an error. It is an error to specify non-NULL values ** for both docid and some other rowid alias. */ - if( SQLITE_NULL!=sqlite3_value_type(apVal[3+p->nColumn]) ){ + assert( p->nLanguageidBits==0 || piRowid==0 + || sqlite3_value_type(apVal[1])!=SQLITE_NULL + ); + if( piRowid && p->nLanguageidBits==0 + && SQLITE_NULL!=sqlite3_value_type(apVal[3+p->nColumn]) + ){ if( SQLITE_NULL==sqlite3_value_type(apVal[0]) && SQLITE_NULL!=sqlite3_value_type(apVal[1]) ){ @@ -982,13 +1013,15 @@ static int fts3InsertData( if( rc!=SQLITE_OK ) return rc; } - /* Execute the statement to insert the record. Set *piDocid to the + /* Execute the statement to insert the record. Set *pRowid to the ** new docid value. */ sqlite3_step(pContentInsert); rc = sqlite3_reset(pContentInsert); - *piDocid = sqlite3_last_insert_rowid(p->db); + if( piRowid ){ + *piRowid = sqlite3_last_insert_rowid(p->db); + } return rc; } @@ -1036,7 +1069,7 @@ static int langidFromSelect(Fts3Table *p, sqlite3_stmt *pSelect){ static void fts3DeleteTerms( int *pRC, /* Result code */ Fts3Table *p, /* The FTS table to delete from */ - sqlite3_value *pRowid, /* The docid to be deleted */ + i64 iRowid, /* The rowid to be deleted */ u32 *aSz, /* Sizes of deleted document written here */ int *pbFound /* OUT: Set to true if row really does exist */ ){ @@ -1045,8 +1078,9 @@ static void fts3DeleteTerms( assert( *pbFound==0 ); if( *pRC ) return; - rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid); + rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, 0); if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pSelect, 1, iRowid); if( SQLITE_ROW==sqlite3_step(pSelect) ){ int i; int iLangid = langidFromSelect(p, pSelect); @@ -2346,7 +2380,7 @@ static void fts3SegWriterFree(SegmentWriter *pWriter){ ** document pRowid, or false otherwise, and SQLITE_OK is returned. If an ** error occurs, an SQLite error code is returned. */ -static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ +static int fts3IsEmpty(Fts3Table *p, i64 iRowid, int *pisEmpty){ sqlite3_stmt *pStmt; int rc; if( p->zContentTbl ){ @@ -2354,8 +2388,9 @@ static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ *pisEmpty = 0; rc = SQLITE_OK; }else{ - rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); + rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, 0); if( rc==SQLITE_OK ){ + sqlite3_bind_int64(pStmt, 1, iRowid); if( SQLITE_ROW==sqlite3_step(pStmt) ){ *pisEmpty = sqlite3_column_int(pStmt, 0); } @@ -5197,17 +5232,17 @@ int sqlite3Fts3DeferToken( */ static int fts3DeleteByRowid( Fts3Table *p, - sqlite3_value *pRowid, + i64 iRowid, int *pnChng, /* IN/OUT: Decrement if row is deleted */ u32 *aSzDel ){ int rc = SQLITE_OK; /* Return code */ int bFound = 0; /* True if *pRowid really is in the table */ - fts3DeleteTerms(&rc, p, pRowid, aSzDel, &bFound); + fts3DeleteTerms(&rc, p, iRowid, aSzDel, &bFound); if( bFound && rc==SQLITE_OK ){ int isEmpty = 0; /* Deleting *pRowid leaves the table empty */ - rc = fts3IsEmpty(p, pRowid, &isEmpty); + rc = fts3IsEmpty(p, iRowid, &isEmpty); if( rc==SQLITE_OK ){ if( isEmpty ){ /* Deleting this row means the whole table is empty. In this case @@ -5219,10 +5254,10 @@ static int fts3DeleteByRowid( }else{ *pnChng = *pnChng - 1; if( p->zContentTbl==0 ){ - fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); + fts3SqlExecI64(&rc, p, SQL_DELETE_CONTENT, iRowid); } if( p->bHasDocsize ){ - fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); + fts3SqlExecI64(&rc, p, SQL_DELETE_DOCSIZE, iRowid); } } } @@ -5231,6 +5266,23 @@ static int fts3DeleteByRowid( return rc; } +/* +** Convert a docid (iDocid) and a language id (iLangid) to a rowid, +** according to the configured languageid_bits= value belonging to +** FTS table *p. +*/ +i64 sqlite3Fts3DocidToRowid(Fts3Table *p, i64 iDocid, int iLangid){ + i64 iRowid = iDocid; + if( p->nLanguageidBits ){ + iRowid = (iRowid << p->nLanguageidBits) + iLangid; + } + return iRowid; +} + +i64 sqlite3Fts3RowidToDocid(Fts3Table *p, i64 iRowid){ + return (iRowid >> p->nLanguageidBits); +} + /* ** This function does the work for the xUpdate method of FTS3 virtual ** tables. The schema of the virtual table being: @@ -5242,7 +5294,6 @@ static int fts3DeleteByRowid( ** HIDDEN ** ); ** -** */ int sqlite3Fts3UpdateMethod( sqlite3_vtab *pVtab, /* FTS3 vtab object */ @@ -5257,6 +5308,7 @@ int sqlite3Fts3UpdateMethod( u32 *aSzDel = 0; /* Sizes of deleted documents */ int nChng = 0; /* Net change in number of documents */ int bInsertDone = 0; + int iLangid = 0; assert( p->pSegments==0 ); assert( @@ -5276,9 +5328,28 @@ int sqlite3Fts3UpdateMethod( goto update_out; } - if( nArg>1 && sqlite3_value_int(apVal[2 + p->nColumn + 2])<0 ){ - rc = SQLITE_CONSTRAINT; - goto update_out; + /* If this is an INSERT or UPDATE, check that the new value for the + ** languageid is within range. A languageid can never be a negative + ** value. If the languageid_bits option was specified when this table + ** was created, it must also be less than (2 ^ nLanguageidBits). + ** + ** Also check that if a non-zero languageid_bits value was configured, + ** the specified rowid value must be NULL. + */ + if( nArg>1 ){ + iLangid = sqlite3_value_int(apVal[2 + p->nColumn + 2]); + if( iLangid<0 || (p->nLanguageidBits && iLangid>=(1<nLanguageidBits)) ){ + rc = SQLITE_CONSTRAINT; + goto update_out; + } + + if( p->nLanguageidBits + && sqlite3_value_type(apVal[0])==SQLITE_NULL + && sqlite3_value_type(apVal[1])!=SQLITE_NULL + ){ + rc = SQLITE_CONSTRAINT; + goto update_out; + } } /* Allocate space to hold the change in document sizes */ @@ -5304,37 +5375,67 @@ int sqlite3Fts3UpdateMethod( */ if( nArg>1 && p->zContentTbl==0 ){ /* Find the value object that holds the new rowid value. */ - sqlite3_value *pNewRowid = apVal[3+p->nColumn]; - if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ - pNewRowid = apVal[1]; - } - - if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && ( - sqlite3_value_type(apVal[0])==SQLITE_NULL - || sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid) - )){ - /* The new rowid is not NULL (in this case the rowid will be - ** automatically assigned and there is no chance of a conflict), and - ** the statement is either an INSERT or an UPDATE that modifies the - ** rowid column. So if the conflict mode is REPLACE, then delete any - ** existing row with rowid=pNewRowid. - ** - ** Or, if the conflict mode is not REPLACE, insert the new record into - ** the %_content table. If we hit the duplicate rowid constraint (or any - ** other error) while doing so, return immediately. - ** - ** This branch may also run if pNewRowid contains a value that cannot - ** be losslessly converted to an integer. In this case, the eventual - ** call to fts3InsertData() (either just below or further on in this - ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is - ** invoked, it will delete zero rows (since no row will have - ** docid=$pNewRowid if $pNewRowid is not an integer value). - */ - if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ - rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel); - }else{ - rc = fts3InsertData(p, apVal, pRowid); - bInsertDone = 1; + sqlite3_value *pNewDocid = apVal[3+p->nColumn]; + if( sqlite3_value_type(pNewDocid)==SQLITE_NULL ){ + if( p->nLanguageidBits ){ + rc = SQLITE_CONSTRAINT; + goto update_out; + } + pNewDocid = apVal[1]; + } + + if( sqlite3_value_type(pNewDocid)!=SQLITE_NULL ){ + int e = sqlite3_value_numeric_type(pNewDocid); + i64 iRowid = sqlite3_value_int64(pNewDocid); + + /* Check that the value specified by the user may be losslessly + ** converted to an integer. If not, return a "data mismatch" error. */ + if( (e!=SQLITE_INTEGER) + && (e!=SQLITE_FLOAT || (double)iRowid!=sqlite3_value_double(pNewDocid)) + ){ + rc = SQLITE_MISMATCH; + goto update_out; + } + + if( p->nLanguageidBits ){ + /* Check for an out-of-range docid value. */ + if( iRowid>=((i64)1 << (63 - p->nLanguageidBits)) + || iRowid<-1*((i64)1 << (63 - p->nLanguageidBits)) + ){ + rc = SQLITE_CONSTRAINT; + goto update_out; + } + + iRowid = sqlite3Fts3DocidToRowid(p, iRowid, iLangid); + } + + if( sqlite3_value_type(apVal[0])==SQLITE_NULL + || sqlite3_value_int64(apVal[0])!=iRowid + ){ + /* The new rowid is not NULL (in this case the rowid will be + ** automatically assigned and there is no chance of a conflict), and + ** the statement is either an INSERT or an UPDATE that modifies the + ** rowid column. So if the conflict mode is REPLACE, then delete any + ** existing row with rowid=pNewRowid. + ** + ** Or, if the conflict mode is not REPLACE, insert the new record into + ** the %_content table. If we hit the duplicate rowid constraint (or + ** any other error) while doing so, return immediately. + ** + ** This branch may also run if pNewRowid contains a value that cannot + ** be losslessly converted to an integer. In this case, the eventual + ** call to fts3InsertData() (either just below or further on in this + ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is + ** invoked, it will delete zero rows (since no row will have + ** docid=$pNewRowid if $pNewRowid is not an integer value). + */ + if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ + rc = fts3DeleteByRowid(p, iRowid, &nChng, aSzDel); + }else{ + rc = fts3InsertData(p, apVal, 0, iRowid); + bInsertDone = 1; + *pRowid = iRowid; + } } } } @@ -5345,15 +5446,14 @@ int sqlite3Fts3UpdateMethod( /* If this is a DELETE or UPDATE operation, remove the old record. */ if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ); - rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel); + rc = fts3DeleteByRowid(p, sqlite3_value_int64(apVal[0]), &nChng, aSzDel); isRemove = 1; } /* If this is an INSERT or UPDATE operation, insert the new record. */ if( nArg>1 && rc==SQLITE_OK ){ - int iLangid = sqlite3_value_int(apVal[2 + p->nColumn + 2]); if( bInsertDone==0 ){ - rc = fts3InsertData(p, apVal, pRowid); + rc = fts3InsertData(p, apVal, pRowid, 0); if( rc==SQLITE_CONSTRAINT && p->zContentTbl==0 ){ rc = FTS_CORRUPT_VTAB; } diff --git a/manifest b/manifest index aab16234de..81b7173fc8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Only\sdefault\sHAVE_POSIX_FALLOCATE\son\sfor\slinux,\sand\sthen\sonly\sif\sit\sis\snot\npreviously\sdefined. -D 2013-06-19T14:49:14.627 +C Add\sthe\slanguageid_bits=\soption\sto\sfts.\sStill\ssome\sproblems\sto\swork\sout. +D 2013-06-19T20:13:28.631 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -78,9 +78,9 @@ F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 931b3c83abdd1ab3bb389b2130431c2a9ff73b91 +F ext/fts3/fts3.c 2d86f9b356b5e309fa68e20f6891b2ca1e694dc3 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h cb4df04cf886d9920a71df9e8faaa5aae2fa48c6 +F ext/fts3/fts3Int.h 9bef3710aa94fc27b117eca41088aa29ed99d4f1 F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd F ext/fts3/fts3_expr.c f8eb1046063ba342c7114eba175cabb31c4a64e7 F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914 @@ -96,7 +96,7 @@ F ext/fts3/fts3_tokenizer.h 64c6ef6c5272c51ebe60fc607a896e84288fcbc3 F ext/fts3/fts3_tokenizer1.c 5c98225a53705e5ee34824087478cf477bdb7004 F ext/fts3/fts3_unicode.c 92391b4b4fb043564c6539ea9b8661e3bcba47b9 F ext/fts3/fts3_unicode2.c 0113d3acf13429e6dc38e0647d1bc71211c31a4d -F ext/fts3/fts3_write.c 6a1fc0e922e76b68e594bf7bc33bac72af9dc47b +F ext/fts3/fts3_write.c b057e0f72a3d684b812732db0d4a5d9614936db3 F ext/fts3/fts3speed.tcl b54caf6a18d38174f1a6e84219950d85e98bb1e9 F ext/fts3/mkfts3amal.tcl 252ecb7fe6467854f2aa237bf2c390b74e71f100 F ext/fts3/tool/fts3view.c 6cfc5b67a5f0e09c0d698f9fd012c784bfaa9197 @@ -546,6 +546,7 @@ F test/fts4aa.test 95f448fb02c4a976968b08d1b4ce134e720946ae F test/fts4check.test 66fa274cab2b615f2fb338b257713aba8fad88a8 F test/fts4content.test 6efc53b4fd03cab167e6998d2b0b7d4b7d419ee6 F test/fts4langid.test 24a6e41063b416bbdf371ff6b4476fa41c194aa7 +F test/fts4langid2.test 50736df3c3adbb2a05d8685802453a16db6c458f F test/fts4merge.test c424309743fdd203f8e56a1f1cd7872cd66cc0ee F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891 F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7 @@ -1093,7 +1094,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P b9b30d4f9845d212e2d3206abbf2795099e5d71d -R 051331ae49dcb9481117487fe2ddd3f7 -U drh -Z f091211d6e3ac84847a4aa6c11062c5e +P 2b2ade92788be623af6f57e37d98994be2cec142 +R 1066cd04ca715945e7e0705efe840790 +T *branch * fts-languageid-bits +T *sym-fts-languageid-bits * +T -sym-trunk * +U dan +Z 9fcd5c1627466406b038b9233ae97f20 diff --git a/manifest.uuid b/manifest.uuid index edfc6bc72c..3c5e98cdff 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2b2ade92788be623af6f57e37d98994be2cec142 \ No newline at end of file +d36d7e68334c0685d1941dd0323b1a9c5c7368bf \ No newline at end of file diff --git a/test/fts4langid2.test b/test/fts4langid2.test new file mode 100644 index 0000000000..9a854ed6ae --- /dev/null +++ b/test/fts4langid2.test @@ -0,0 +1,134 @@ +# 2012 March 01 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#************************************************************************* +# This file implements regression tests for SQLite library. The +# focus of this script is testing the languageid=xxx FTS4 option. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix fts4langid2 + +# If SQLITE_ENABLE_FTS3 is defined, omit this file. +ifcapable !fts3 { + finish_test + return +} + + +#------------------------------------------------------------------------- +# Test out-of-range values for the languageid_bits= parameter. +# +do_catchsql_test 1.1 { + CREATE VIRTUAL TABLE t1 USING fts4(languageid=lid, languageid_bits=33); +} {1 {languageid_bits parameter out of range}} + +do_catchsql_test 1.2 { + CREATE VIRTUAL TABLE t1 USING fts4(languageid=lid, languageid_bits=-1); +} {1 {languageid_bits parameter out of range}} + +do_catchsql_test 1.3 { + CREATE VIRTUAL TABLE t1 USING fts4(languageid=lid, languageid_bits=0); + CREATE VIRTUAL TABLE t2 USING fts4(languageid=lid, languageid_bits=32); +} {0 {}} + +do_execsql_test 1.4 { + DROP TABLE t1; + DROP TABLE t2; +} + +#------------------------------------------------------------------------- +# Test out-of-range values in the languageid column. +# +do_execsql_test 2.1 { + CREATE VIRTUAL TABLE t1 USING fts4(languageid=lid, languageid_bits=8); + CREATE VIRTUAL TABLE t2 USING fts4(languageid=lid, languageid_bits=7); +} + +do_catchsql_test 2.2 { + INSERT INTO t1(docid, lid, content) VALUES(1, 256, 'abc def'); +} {1 {constraint failed}} + +do_catchsql_test 2.3 { + INSERT INTO t2(docid, lid, content) VALUES(1, 128, 'abc def'); +} {1 {constraint failed}} + +do_catchsql_test 2.3 { + INSERT INTO t1(docid, lid, content) VALUES(1, -1, 'abc def'); +} {1 {constraint failed}} + +do_execsql_test 2.4 { + DROP TABLE t1; + DROP TABLE t2; +} + +#------------------------------------------------------------------------- +# Test that if languageid_bits is set to a non-zero value it is +# not possible to specify a non-NULL rowid, even if it is the same +# as the docid. +# +do_execsql_test 3.1 { + CREATE VIRTUAL TABLE t1 USING fts4(languageid=lid, languageid_bits=4); + CREATE VIRTUAL TABLE t2 USING fts4(languageid=lid, languageid_bits=0); +} + +do_catchsql_test 3.2.1 { + INSERT INTO t1(rowid, lid, content) VALUES(1, 0, 'abc def'); +} {1 {constraint failed}} + +do_catchsql_test 3.2.2 { + INSERT INTO t2(rowid, lid, content) VALUES(1, 0, 'abc def'); +} {0 {}} + +do_catchsql_test 3.3 { + INSERT INTO t1(rowid, docid, lid, content) VALUES(2, 2, 0, 'abc def'); +} {1 {constraint failed}} + +do_catchsql_test 3.4 { + INSERT INTO t1(lid, content) VALUES(0, 'one two def'); +} {1 {constraint failed}} + +do_execsql_test 3.4 { + DROP TABLE t1; + DROP TABLE t2; +} + +#------------------------------------------------------------------------- +# +do_execsql_test 4.1 { + CREATE VIRTUAL TABLE t1 USING fts4(languageid=lid, languageid_bits=5); +} + +do_execsql_test 4.2 { + INSERT INTO t1 (docid, lid, content) VALUES(1, 0, '1 2 3'); + INSERT INTO t1 (docid, lid, content) VALUES(1, 1, '1 2 3 4'); +} + +do_execsql_test 4.3 { + SELECT docid, lid FROM t1; +} {1 0 1 1} + +do_execsql_test 4.4 { + SELECT docid, lid, content FROM t1 WHERE t1 MATCH '2'; +} {1 0 {1 2 3}} + +do_execsql_test 4.5 { + SELECT docid, lid, content FROM t1 WHERE t1 MATCH '2' AND lid=1; +} {1 1 {1 2 3 4}} + +breakpoint +do_execsql_test 4.6 { + UPDATE t1 SET content = 'x y z' || lid; + SELECT docid, lid FROM t1; +} {1 0 1 1} + + +finish_test +