Fts5ExprTerm aTerm[0]; /* Terms that make up this phrase */
};
+/*
+** If a NEAR() clump may only match a specific set of columns, then
+** Fts5ExprNearset.pColset points to an object of the following type.
+** Each entry in the aiCol[] array
+*/
+struct Fts5ExprColset {
+ int nCol;
+ int aiCol[1];
+};
+
/*
** One or more phrases that must appear within a certain token distance of
** each other within each matching document.
*/
struct Fts5ExprNearset {
int nNear; /* NEAR parameter */
- int iCol; /* Column to search (-1 -> all columns) */
+ Fts5ExprColset *pColset; /* Columns to search (NULL -> all columns) */
int nPhrase; /* Number of entries in aPhrase[] array */
Fts5ExprPhrase *apPhrase[0]; /* Array of phrase pointers */
};
switch( *z ){
case '(': tok = FTS5_LP; break;
case ')': tok = FTS5_RP; break;
+ case '[': tok = FTS5_LSP; break;
+ case ']': tok = FTS5_RSP; break;
case ':': tok = FTS5_COLON; break;
case ',': tok = FTS5_COMMA; break;
case '+': tok = FTS5_PLUS; break;
pNode->eType = FTS5_STRING;
pNode->pNear = pNear;
- pNear->iCol = -1;
pNear->nPhrase = 1;
pNear->apPhrase[0] = pCopy;
*/
static int fts5ExprPhraseIsMatch(
Fts5Expr *pExpr, /* Expression pPhrase belongs to */
- int iCol, /* If >=0, search for matches in iCol only */
+ Fts5ExprColset *pColset, /* Restrict matches to these columns */
Fts5ExprPhrase *pPhrase, /* Phrase object to initialize */
int *pbMatch /* OUT: Set to true if really a match */
){
Fts5PoslistReader *aIter = aStatic;
int i;
int rc = SQLITE_OK;
+ int iCol = pColset ? pColset->aiCol[0] : -1;
fts5BufferZero(&pPhrase->poslist);
int n, /* IN: Size of poslist in bytes */
int iCol /* Column to extract from poslist */
){
- int ii;
int iCurrent = 0;
const u8 *p = *pa;
const u8 *pEnd = &p[n]; /* One byte past end of position list */
int rc = SQLITE_OK;
while( 1 ){
- int i;
if( pNear->nPhrase==1 && pNear->apPhrase[0]->nTerm==1 ){
/* If this "NEAR" object is actually a single phrase that consists
** complicated phrase or NEAR expressions. */
Fts5ExprPhrase *pPhrase = pNear->apPhrase[0];
Fts5IndexIter *pIter = pPhrase->aTerm[0].pIter;
- assert( pPhrase->poslist.nSpace==0 );
- rc = sqlite3Fts5IterPoslist(pIter,
- (const u8**)&pPhrase->poslist.p, &pPhrase->poslist.n, &pNode->iRowid
- );
+ Fts5ExprColset *pColset = pNear->pColset;
+ const u8 *pPos;
+ int nPos;
+
+ rc = sqlite3Fts5IterPoslist(pIter, &pPos, &nPos, &pNode->iRowid);
/* If the term may match any column, then this must be a match.
** Return immediately in this case. Otherwise, try to find the
** If it can be found, return. If it cannot, the next iteration
** of the loop will test the next rowid in the database for this
** term. */
- if( pNear->iCol<0 ) return rc;
+ if( pColset==0 ){
+ assert( pPhrase->poslist.nSpace==0 );
+ pPhrase->poslist.p = (u8*)pPos;
+ pPhrase->poslist.n = nPos;
+ }else if( pColset->nCol==1 ){
+ assert( pPhrase->poslist.nSpace==0 );
+ pPhrase->poslist.n = fts5ExprExtractCol(&pPos, nPos, pColset->aiCol[0]);
+ pPhrase->poslist.p = (u8*)pPos;
+ }else{
+ int i;
+ fts5BufferZero(&pPhrase->poslist);
+ for(i=0; i<pColset->nCol; i++){
+ const u8 *pSub = pPos;
+ int nSub = fts5ExprExtractCol(&pSub, nPos, pColset->aiCol[i]);
+ if( nSub ){
+ fts5BufferAppendBlob(&rc, &pPhrase->poslist, nSub, pSub);
+ }
+ }
+ }
- pPhrase->poslist.n = fts5ExprExtractCol(
- (const u8**)&pPhrase->poslist.p,
- pPhrase->poslist.n,
- pNear->iCol
- );
if( pPhrase->poslist.n ) return rc;
}else{
+ int i;
+
+ assert( pNear->pColset==0 || pNear->pColset->nCol==1 );
/* Advance the iterators until they all point to the same rowid */
rc = fts5ExprNearNextRowidMatch(pExpr, pNode);
** phrase is not a match, break out of the loop early. */
for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
- if( pPhrase->nTerm>1 || pNear->iCol>=0 ){
+ if( pPhrase->nTerm>1 || pNear->pColset ){
int bMatch = 0;
- rc = fts5ExprPhraseIsMatch(pExpr, pNear->iCol, pPhrase, &bMatch);
+ rc = fts5ExprPhraseIsMatch(pExpr, pNear->pColset, pPhrase, &bMatch);
if( bMatch==0 ) break;
}else{
rc = sqlite3Fts5IterPoslistBuffer(
pPhrase->aTerm[0].pIter, &pPhrase->poslist
- );
+ );
}
}
pParse->rc = SQLITE_NOMEM;
}else{
memset(pRet, 0, nByte);
- pRet->iCol = -1;
}
}else if( (pNear->nPhrase % SZALLOC)==0 ){
int nNew = pNear->nPhrase + SZALLOC;
for(i=0; i<pNear->nPhrase; i++){
fts5ExprPhraseFree(pNear->apPhrase[i]);
}
+ sqlite3_free(pNear->pColset);
sqlite3_free(pNear);
}
}
void sqlite3Fts5ParseSetDistance(
Fts5Parse *pParse,
- Fts5ExprNearset *pNear,
+ Fts5ExprNearset *pNear,
Fts5Token *p
){
int nNear = 0;
pNear->nNear = nNear;
}
-void sqlite3Fts5ParseSetColumn(
- Fts5Parse *pParse,
- Fts5ExprNearset *pNear,
+/*
+** The second argument passed to this function may be NULL, or it may be
+** an existing Fts5ExprColset object. This function returns a pointer to
+** a new colset object containing the contents of (p) with new value column
+** number iCol appended.
+**
+** If an OOM error occurs, store an error code in pParse and return NULL.
+** The old colset object (if any) is not freed in this case.
+*/
+static Fts5ExprColset *fts5ParseColset(
+ Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */
+ Fts5ExprColset *p, /* Existing colset object */
+ int iCol /* New column to add to colset object */
+){
+ int nCol = p ? p->nCol : 0; /* Num. columns already in colset object */
+ Fts5ExprColset *pNew; /* New colset object to return */
+
+ assert( pParse->rc==SQLITE_OK );
+ assert( iCol>=0 && iCol<pParse->pConfig->nCol );
+
+ pNew = sqlite3_realloc(p, sizeof(Fts5ExprColset) + sizeof(int)*nCol);
+ if( pNew==0 ){
+ pParse->rc = SQLITE_NOMEM;
+ }else{
+ int *aiCol = pNew->aiCol;
+ int i, j;
+ for(i=0; i<nCol; i++){
+ if( aiCol[i]==iCol ) return pNew;
+ if( aiCol[i]>iCol ) break;
+ }
+ for(j=nCol; j>i; j--){
+ aiCol[j] = aiCol[j-1];
+ }
+ aiCol[i] = iCol;
+ pNew->nCol = nCol+1;
+
+#ifndef NDEBUG
+ /* Check that the array is in order and contains no duplicate entries. */
+ for(i=1; i<pNew->nCol; i++) assert( pNew->aiCol[i]>pNew->aiCol[i-1] );
+#endif
+ }
+
+ return pNew;
+}
+
+Fts5ExprColset *sqlite3Fts5ParseColset(
+ Fts5Parse *pParse, /* Store SQLITE_NOMEM here if required */
+ Fts5ExprColset *pColset, /* Existing colset object */
Fts5Token *p
){
+ Fts5ExprColset *pRet = 0;
+
if( pParse->rc==SQLITE_OK ){
+ int iCol;
char *z = 0;
int rc = fts5ParseStringFromToken(p, &z);
if( rc==SQLITE_OK ){
Fts5Config *pConfig = pParse->pConfig;
- int i;
- for(i=0; i<pConfig->nCol; i++){
- if( 0==sqlite3_stricmp(pConfig->azCol[i], z) ){
- pNear->iCol = i;
+ sqlite3Fts5Dequote(z);
+ for(iCol=0; iCol<pConfig->nCol; iCol++){
+ if( 0==sqlite3_stricmp(pConfig->azCol[iCol], z) ){
break;
}
}
- if( i==pConfig->nCol ){
+ if( iCol==pConfig->nCol ){
sqlite3Fts5ParseError(pParse, "no such column: %s", z);
}
sqlite3_free(z);
}else{
pParse->rc = rc;
}
+
+ if( pParse->rc==SQLITE_OK ){
+ pRet = fts5ParseColset(pParse, pColset, iCol);
+ }
+ }
+
+ if( pParse->rc!=SQLITE_OK ){
+ assert( pRet==0 );
+ sqlite3_free(pColset);
+ }
+
+ return pRet;
+}
+
+void sqlite3Fts5ParseSetColset(
+ Fts5Parse *pParse,
+ Fts5ExprNearset *pNear,
+ Fts5ExprColset *pColset
+){
+ if( pNear ){
+ pNear->pColset = pColset;
+ }else{
+ sqlite3_free(pColset);
}
}
zRet = fts5PrintfAppend(zRet, "[%s ", zNearsetCmd);
if( zRet==0 ) return 0;
- if( pNear->iCol>=0 ){
- zRet = fts5PrintfAppend(zRet, "-col %d ", pNear->iCol);
+ if( pNear->pColset ){
+ int *aiCol = pNear->pColset->aiCol;
+ int nCol = pNear->pColset->nCol;
+ if( nCol==1 ){
+ zRet = fts5PrintfAppend(zRet, "-col %d ", aiCol[0]);
+ }else{
+ zRet = fts5PrintfAppend(zRet, "-col {%d", aiCol[0]);
+ for(i=1; i<pNear->pColset->nCol; i++){
+ zRet = fts5PrintfAppend(zRet, " %d", aiCol[i]);
+ }
+ zRet = fts5PrintfAppend(zRet, "} ");
+ }
if( zRet==0 ) return 0;
}
int i;
int iTerm;
- if( pNear->iCol>=0 ){
- zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[pNear->iCol]);
+ if( pNear->pColset ){
+ int iCol = pNear->pColset->aiCol[0];
+ zRet = fts5PrintfAppend(zRet, "%s : ", pConfig->azCol[iCol]);
if( zRet==0 ) return 0;
}
-C Optimizations\sfor\sfts5\squeries\sthat\smatch\sagainst\sa\sspecific\scolumn.
-D 2015-05-28T19:57:12.367
+C Add\ssyntax\sto\sfts5\sused\sto\sspecify\sthat\sa\sphrase\sor\sNEAR\sgroup\sshould\smatch\sa\ssubset\sof\scolumns.\sFor\sexample\s"[col1\scol2\s...]\s:\s<phrase>".
+D 2015-05-29T15:55:30.046
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 2c28e557780395095c307a6e5cb539419027eb5e
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F ext/fts5/extract_api_docs.tcl 55a6d648d516f35d9a1e580ac00de27154e1904a
F ext/fts5/fts5.c 74d18b4dc7518c7cd85609f1541e83bc564619a2
F ext/fts5/fts5.h 4266c6231094005b051dbfc8dd85d2bc57243d34
-F ext/fts5/fts5Int.h 2ce5c5e68852dd16de404b7a9a2a78f4f4588eb4
+F ext/fts5/fts5Int.h 3bcecc469fe570ab188d123e1d33d6e5e11a5129
F ext/fts5/fts5_aux.c d53f00f31ad615ca4f139dd8751f9041afa00971
F ext/fts5/fts5_buffer.c 861599a0abe2383f0cd0352c57001140a26b0930
F ext/fts5/fts5_config.c 11f969ed711a0a8b611d47431d74c372ad78c713
-F ext/fts5/fts5_expr.c c94983eaff58391d7c0d62e99de917cecd0f1dbc
+F ext/fts5/fts5_expr.c c607282529c7b5747fc2bcf80770d6abc22638bb
F ext/fts5/fts5_hash.c 54dd25348a46ea62ea96322c572e08cd1fb37304
-F ext/fts5/fts5_index.c a693ba741b82539da5779329214e5d2609e82e5f
+F ext/fts5/fts5_index.c 59b8a3dfde24ddb80c31088148a3dfc779db22ab
F ext/fts5/fts5_storage.c 5d2b51adb304643d8f825ba89283d628418b20c2
F ext/fts5/fts5_tcl.c 7ea165878e4ae3598e89acd470a0ee1b5a00e33c
F ext/fts5/fts5_tokenize.c 24649425adfea2c4877d8f69f2754b70374940ec
F ext/fts5/fts5_unicode2.c da3cf712f05cd8347c8c5bc00964cc0361c88da9
F ext/fts5/fts5_vocab.c 1f8543b2c1ae4427f127a911bc8e60873fcd7bf9
-F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9
+F ext/fts5/fts5parse.y 4ee667932d561a150d96483cf563281b95a9e523
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
F ext/fts5/test/fts5_common.tcl 6d663e8c3d8409857363f66560df96b8ca813e79
F ext/fts5/test/fts5aa.test 5f73afe6a1394fdba9bc18302876ded81021bee6
F ext/fts5/test/fts5ab.test 6fe3a56731d15978afbb74ae51b355fc9310f2ad
-F ext/fts5/test/fts5ac.test 05008e00bd2761cc45df838a0988ecf318cbe1fd
+F ext/fts5/test/fts5ac.test d35bbe22dd23b3dbac3e1d3f07eed0206213a480
F ext/fts5/test/fts5ad.test 312f3c8ed9592533499c5b94d2059ae6382913a0
F ext/fts5/test/fts5ae.test 9175201baf8c885fc1cbb2da11a0c61fd11224db
F ext/fts5/test/fts5af.test c2501ec2b61d6b179c305f5d2b8782ab3d4f832a
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 0f9df202cc58097afddb8dad662b7c7fdc2c7d0c
-R f25569d3bfd1393da78f5986e0e8acff
+P b29ac50af0491a780a5a4c0985d88d0e5e014ba3
+R 34ff180b006ad5f21871399f838e5dbb
U dan
-Z d652fde1b36e85f62688dc3a9737ccda
+Z f15f3e2fe41d81aa9045dd94b23ec6a4