]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the "languageid" hidden column to fts4aux.
authordan <dan@noemail.net>
Tue, 15 Oct 2013 19:06:17 +0000 (19:06 +0000)
committerdan <dan@noemail.net>
Tue, 15 Oct 2013 19:06:17 +0000 (19:06 +0000)
FossilOrigin-Name: 891df358e51075fb937f34952ce43bf51130b0d0

ext/fts3/fts3_aux.c
manifest
manifest.uuid
test/fts3aux2.test [new file with mode: 0644]

index 9b582fcf8bfcfd226f8a62858694cfbd8275e966..c68b1a9d9be93f40b6ff81a0dddc0bfe7e0d4cfe 100644 (file)
@@ -31,6 +31,7 @@ struct Fts3auxCursor {
   Fts3SegFilter filter;
   char *zStop;
   int nStop;                      /* Byte-length of string zStop */
+  int iLangid;                    /* Language id to query */
   int isEof;                      /* True if cursor is at EOF */
   sqlite3_int64 iRowid;           /* Current rowid */
 
@@ -45,7 +46,8 @@ struct Fts3auxCursor {
 /*
 ** Schema of the terms table.
 */
-#define FTS3_TERMS_SCHEMA "CREATE TABLE x(term, col, documents, occurrences)"
+#define FTS3_AUX_SCHEMA \
+  "CREATE TABLE x(term, col, documents, occurrences, languageid HIDDEN)"
 
 /*
 ** This function does all the work for both the xConnect and xCreate methods.
@@ -92,7 +94,7 @@ static int fts3auxConnectMethod(
   }
   nFts3 = (int)strlen(zFts3);
 
-  rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
+  rc = sqlite3_declare_vtab(db, FTS3_AUX_SCHEMA);
   if( rc!=SQLITE_OK ) return rc;
 
   nByte = sizeof(Fts3auxTable) + sizeof(Fts3Table) + nDb + nFts3 + 2;
@@ -152,6 +154,8 @@ static int fts3auxBestIndexMethod(
   int iEq = -1;
   int iGe = -1;
   int iLe = -1;
+  int iLangid = -1;
+  int iNext = 1;                  /* Next free argvIndex value */
 
   UNUSED_PARAMETER(pVTab);
 
@@ -163,36 +167,48 @@ static int fts3auxBestIndexMethod(
     pInfo->orderByConsumed = 1;
   }
 
-  /* Search for equality and range constraints on the "term" column. */
+  /* Search for equality and range constraints on the "term" column. 
+  ** And equality constraints on the hidden "languageid" column. */
   for(i=0; i<pInfo->nConstraint; i++){
-    if( pInfo->aConstraint[i].usable && pInfo->aConstraint[i].iColumn==0 ){
+    if( pInfo->aConstraint[i].usable ){
       int op = pInfo->aConstraint[i].op;
-      if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iEq = i;
-      if( op==SQLITE_INDEX_CONSTRAINT_LT ) iLe = i;
-      if( op==SQLITE_INDEX_CONSTRAINT_LE ) iLe = i;
-      if( op==SQLITE_INDEX_CONSTRAINT_GT ) iGe = i;
-      if( op==SQLITE_INDEX_CONSTRAINT_GE ) iGe = i;
+      int iCol = pInfo->aConstraint[i].iColumn;
+
+      if( iCol==0 ){
+        if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iEq = i;
+        if( op==SQLITE_INDEX_CONSTRAINT_LT ) iLe = i;
+        if( op==SQLITE_INDEX_CONSTRAINT_LE ) iLe = i;
+        if( op==SQLITE_INDEX_CONSTRAINT_GT ) iGe = i;
+        if( op==SQLITE_INDEX_CONSTRAINT_GE ) iGe = i;
+      }
+      if( iCol==4 ){
+        if( op==SQLITE_INDEX_CONSTRAINT_EQ ) iLangid = i;
+      }
     }
   }
 
   if( iEq>=0 ){
     pInfo->idxNum = FTS4AUX_EQ_CONSTRAINT;
-    pInfo->aConstraintUsage[iEq].argvIndex = 1;
+    pInfo->aConstraintUsage[iEq].argvIndex = iNext++;
     pInfo->estimatedCost = 5;
   }else{
     pInfo->idxNum = 0;
     pInfo->estimatedCost = 20000;
     if( iGe>=0 ){
       pInfo->idxNum += FTS4AUX_GE_CONSTRAINT;
-      pInfo->aConstraintUsage[iGe].argvIndex = 1;
+      pInfo->aConstraintUsage[iGe].argvIndex = iNext++;
       pInfo->estimatedCost /= 2;
     }
     if( iLe>=0 ){
       pInfo->idxNum += FTS4AUX_LE_CONSTRAINT;
-      pInfo->aConstraintUsage[iLe].argvIndex = 1 + (iGe>=0);
+      pInfo->aConstraintUsage[iLe].argvIndex = iNext++;
       pInfo->estimatedCost /= 2;
     }
   }
+  if( iLangid>=0 ){
+    pInfo->aConstraintUsage[iLangid].argvIndex = iNext++;
+    pInfo->estimatedCost--;
+  }
 
   return SQLITE_OK;
 }
@@ -352,7 +368,14 @@ static int fts3auxFilterMethod(
   Fts3auxCursor *pCsr = (Fts3auxCursor *)pCursor;
   Fts3Table *pFts3 = ((Fts3auxTable *)pCursor->pVtab)->pFts3Tab;
   int rc;
-  int isScan;
+  int isScan = 0;
+  int iLangVal = 0;               /* Language id to query */
+
+  int iEq = -1;                   /* Index of term=? value in apVal */
+  int iGe = -1;                   /* Index of term>=? value in apVal */
+  int iLe = -1;                   /* Index of term<=? value in apVal */
+  int iLangid = -1;               /* Index of languageid=? value in apVal */
+  int iNext = 0;
 
   UNUSED_PARAMETER(nVal);
   UNUSED_PARAMETER(idxStr);
@@ -362,7 +385,21 @@ static int fts3auxFilterMethod(
        || idxNum==FTS4AUX_LE_CONSTRAINT || idxNum==FTS4AUX_GE_CONSTRAINT
        || idxNum==(FTS4AUX_LE_CONSTRAINT|FTS4AUX_GE_CONSTRAINT)
   );
-  isScan = (idxNum!=FTS4AUX_EQ_CONSTRAINT);
+
+  if( idxNum==FTS4AUX_EQ_CONSTRAINT ){
+    iEq = iNext++;
+  }else{
+    isScan = 1;
+    if( idxNum & FTS4AUX_GE_CONSTRAINT ){
+      iGe = iNext++;
+    }
+    if( idxNum & FTS4AUX_LE_CONSTRAINT ){
+      iLe = iNext++;
+    }
+  }
+  if( iNext<nVal ){
+    iLangid = iNext++;
+  }
 
   /* In case this cursor is being reused, close and zero it. */
   testcase(pCsr->filter.zTerm);
@@ -374,22 +411,35 @@ static int fts3auxFilterMethod(
   pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY;
   if( isScan ) pCsr->filter.flags |= FTS3_SEGMENT_SCAN;
 
-  if( idxNum&(FTS4AUX_EQ_CONSTRAINT|FTS4AUX_GE_CONSTRAINT) ){
+  if( iEq>=0 || iGe>=0 ){
     const unsigned char *zStr = sqlite3_value_text(apVal[0]);
+    assert( (iEq==0 && iGe==-1) || (iEq==-1 && iGe==0) );
     if( zStr ){
       pCsr->filter.zTerm = sqlite3_mprintf("%s", zStr);
       pCsr->filter.nTerm = sqlite3_value_bytes(apVal[0]);
       if( pCsr->filter.zTerm==0 ) return SQLITE_NOMEM;
     }
   }
-  if( idxNum&FTS4AUX_LE_CONSTRAINT ){
-    int iIdx = (idxNum&FTS4AUX_GE_CONSTRAINT) ? 1 : 0;
-    pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iIdx]));
-    pCsr->nStop = sqlite3_value_bytes(apVal[iIdx]);
+
+  if( iLe>=0 ){
+    pCsr->zStop = sqlite3_mprintf("%s", sqlite3_value_text(apVal[iLe]));
+    pCsr->nStop = sqlite3_value_bytes(apVal[iLe]);
     if( pCsr->zStop==0 ) return SQLITE_NOMEM;
   }
+  
+  if( iLangid>=0 ){
+    iLangVal = sqlite3_value_int(apVal[iLangid]);
+
+    /* If the user specified a negative value for the languageid, use zero
+    ** instead. This works, as the "languageid=?" constraint will also
+    ** be tested by the VDBE layer. The test will always be false (since
+    ** this module will not return a row with a negative languageid), and
+    ** so the overall query will return zero rows.  */
+    if( iLangVal<0 ) iLangVal = 0;
+  }
+  pCsr->iLangid = iLangVal;
 
-  rc = sqlite3Fts3SegReaderCursor(pFts3, 0, 0, FTS3_SEGCURSOR_ALL,
+  rc = sqlite3Fts3SegReaderCursor(pFts3, iLangVal, 0, FTS3_SEGCURSOR_ALL,
       pCsr->filter.zTerm, pCsr->filter.nTerm, 0, isScan, &pCsr->csr
   );
   if( rc==SQLITE_OK ){
@@ -413,24 +463,37 @@ static int fts3auxEofMethod(sqlite3_vtab_cursor *pCursor){
 */
 static int fts3auxColumnMethod(
   sqlite3_vtab_cursor *pCursor,   /* Cursor to retrieve value from */
-  sqlite3_context *pContext,      /* Context for sqlite3_result_xxx() calls */
+  sqlite3_context *pCtx,          /* Context for sqlite3_result_xxx() calls */
   int iCol                        /* Index of column to read value from */
 ){
   Fts3auxCursor *p = (Fts3auxCursor *)pCursor;
 
   assert( p->isEof==0 );
-  if( iCol==0 ){        /* Column "term" */
-    sqlite3_result_text(pContext, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT);
-  }else if( iCol==1 ){  /* Column "col" */
-    if( p->iCol ){
-      sqlite3_result_int(pContext, p->iCol-1);
-    }else{
-      sqlite3_result_text(pContext, "*", -1, SQLITE_STATIC);
-    }
-  }else if( iCol==2 ){  /* Column "documents" */
-    sqlite3_result_int64(pContext, p->aStat[p->iCol].nDoc);
-  }else{                /* Column "occurrences" */
-    sqlite3_result_int64(pContext, p->aStat[p->iCol].nOcc);
+  switch( iCol ){
+    case 0: /* term */
+      sqlite3_result_text(pCtx, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT);
+      break;
+
+    case 1: /* col */
+      if( p->iCol ){
+        sqlite3_result_int(pCtx, p->iCol-1);
+      }else{
+        sqlite3_result_text(pCtx, "*", -1, SQLITE_STATIC);
+      }
+      break;
+
+    case 2: /* documents */
+      sqlite3_result_int64(pCtx, p->aStat[p->iCol].nDoc);
+      break;
+
+    case 3: /* occurrences */
+      sqlite3_result_int64(pCtx, p->aStat[p->iCol].nOcc);
+      break;
+
+    default: /* languageid */
+      assert( iCol==4 );
+      sqlite3_result_int(pCtx, p->iLangid);
+      break;
   }
 
   return SQLITE_OK;
index 1e4c57ea65f15eb512f12839d8fbba3669132c37..1cb1c24283ffcaefa23f946e22b9035eb8bdfcc3 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Changes\sto\stest\scode\sto\smake\ssure\sno\sserver\sthreads\sare\sleft\srunning\safter\sserver1.test\sfinishes.
-D 2013-10-15T15:35:27.035
+C Add\sthe\s"languageid"\shidden\scolumn\sto\sfts4aux.
+D 2013-10-15T19:06:17.574
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -81,7 +81,7 @@ F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
 F ext/fts3/fts3.c f25ae5729d40cc4e661c0a552685038f27e72bc9
 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
 F ext/fts3/fts3Int.h 8689f7cf85020e7f88d1e761eeac480c3b0ea7ad
-F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd
+F ext/fts3/fts3_aux.c 5c211e17a64885faeb16b9ba7772f9d5445c2365
 F ext/fts3/fts3_expr.c f8eb1046063ba342c7114eba175cabb31c4a64e7
 F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914
 F ext/fts3/fts3_hash.h 39cf6874dc239d6b4e30479b1975fe5b22a3caaf
@@ -523,6 +523,7 @@ F test/fts3ao.test 71b0675e3df5c512a5a03daaa95ee1916de23dda
 F test/fts3atoken.test fca30fd86db9241d571c637751e9a8a2f50f1451
 F test/fts3auto.test b981fea19b132b4e6878f50d7c1f369b28f68eb9
 F test/fts3aux1.test f8f287a4a73f381f8fa15b6a70f36245f903d221
+F test/fts3aux2.test 7ae2b2c13aefdf4169279a27a5f51780ce57f6ba
 F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
 F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
 F test/fts3comp1.test a0f5b16a2df44dd0b15751787130af2183167c0c
@@ -1125,7 +1126,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P bcbc65030fa7c61f94100142e94ba2a5774f85b0
-R f33feda2582cfad813fcab88c99564f2
+P 1086e00bcaacc88ef2a9dda8a20698b0899ad2f7
+R 278f7d19feecc0e16083c2fb7945cca7
 U dan
-Z 117b667e81ae101d694479399cf015f3
+Z 3437f433e75ea0cb69bfd1b37e4271cf
index 723c74dc7c4f63e526bba0d9919dc9b632865e59..2e66ae8df42548faa43d39b52f3d0445c20d960d 100644 (file)
@@ -1 +1 @@
-1086e00bcaacc88ef2a9dda8a20698b0899ad2f7
\ No newline at end of file
+891df358e51075fb937f34952ce43bf51130b0d0
\ No newline at end of file
diff --git a/test/fts3aux2.test b/test/fts3aux2.test
new file mode 100644 (file)
index 0000000..e108fc4
--- /dev/null
@@ -0,0 +1,144 @@
+# 2011 January 27
+#
+# 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 FTS3 module.
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+ifcapable !fts3 { finish_test ; return }
+set ::testprefix fts3aux2
+
+do_execsql_test 1.1 {
+  CREATE VIRTUAL TABLE t1 USING fts4(a, b, languageid=l);
+  INSERT INTO t1(a, b, l) VALUES
+    ('zero zero', 'zero zero', 0),
+    ('one two', 'three four', 1),
+    ('five six', 'seven eight', 2)
+  ;
+  CREATE VIRTUAL TABLE terms USING fts4aux(t1);
+} {}
+
+do_execsql_test 1.2.1 {
+  SELECT term, documents, occurrences, languageid FROM terms WHERE col = '*';
+} {zero 1 4 0}
+
+do_execsql_test 1.2.2 {
+  SELECT * FROM terms;
+} {zero * 1 4 zero 0 1 2 zero 1 1 2}
+
+do_execsql_test 1.2.3 {
+  SELECT * FROM terms WHERE languageid='';
+} {}
+
+do_execsql_test 1.2.4 {
+  SELECT * FROM terms WHERE languageid=-1;
+} {}
+
+do_execsql_test 1.2.5 {
+  SELECT * FROM terms WHERE languageid=9223372036854775807;
+} {}
+
+do_execsql_test 1.2.6 {
+  SELECT * FROM terms WHERE languageid=-9223372036854775808;
+} {}
+
+do_execsql_test 1.2.7 {
+  SELECT * FROM terms WHERE languageid=NULL;
+} {}
+
+do_execsql_test 1.3.1 {
+  SELECT term, documents, occurrences, languageid 
+  FROM terms WHERE col = '*' AND languageid=1;
+} {
+  four 1 1 1 one 1 1 1 three 1 1 1 two 1 1 1 
+}
+
+do_execsql_test 1.3.2 {
+  SELECT term, col, documents, occurrences, languageid 
+  FROM terms WHERE languageid=1;
+} {
+  four * 1 1 1   four 1 1 1 1 
+  one * 1 1 1    one 0 1 1 1 
+  three * 1 1 1  three 1 1 1 1 
+  two * 1 1 1    two 0 1 1 1 
+}
+
+do_execsql_test 1.3.3 {
+  SELECT term, col, documents, occurrences, languageid 
+  FROM terms WHERE languageid=1 AND term='zero'
+} {
+}
+
+do_execsql_test 1.3.4 {
+  SELECT term, col, documents, occurrences, languageid 
+  FROM terms WHERE languageid='1' AND term='two'
+} {
+  two * 1 1 1    two 0 1 1 1 
+}
+
+do_execsql_test 1.3.5 {
+  SELECT term, col, documents, occurrences, languageid 
+  FROM terms WHERE languageid='+1' AND term>'four'
+} {
+  one * 1 1 1    one 0 1 1 1 
+  three * 1 1 1  three 1 1 1 1 
+  two * 1 1 1    two 0 1 1 1 
+}
+
+do_execsql_test 1.4.1 {
+  SELECT term, documents, occurrences, languageid 
+  FROM terms WHERE col = '*' AND languageid=2;
+} {
+  eight 1 1 2 five 1 1 2 seven 1 1 2 six 1 1 2
+}
+
+do_execsql_test 1.4.2 {
+  SELECT term, col, documents, occurrences, languageid 
+  FROM terms WHERE languageid=2;
+} {
+  eight * 1 1 2    eight 1 1 1 2 
+  five * 1 1 2     five 0 1 1 2 
+  seven * 1 1 2    seven 1 1 1 2 
+  six * 1 1 2      six 0 1 1 2
+}
+
+do_execsql_test 1.4.3 {
+  SELECT term, col, documents, occurrences, languageid 
+  FROM terms WHERE languageid=2 AND term='five';
+} {
+  five * 1 1 2     five 0 1 1 2 
+}
+
+do_execsql_test 1.4.4 {
+  SELECT term, col, documents, occurrences, languageid 
+  FROM terms WHERE term='five' AND languageid=2 
+} {
+  five * 1 1 2     five 0 1 1 2 
+}
+
+do_execsql_test 1.4.5 {
+  SELECT term, col, documents, occurrences, languageid 
+  FROM terms WHERE term>='seven' AND languageid=2
+} {
+  seven * 1 1 2    seven 1 1 1 2 
+  six * 1 1 2      six 0 1 1 2
+}
+
+do_execsql_test 1.4.6 {
+  SELECT term, col, documents, occurrences, languageid 
+  FROM terms WHERE term>='e' AND term<'seven' AND languageid=2
+} {
+  eight * 1 1 2    eight 1 1 1 2 
+  five * 1 1 2     five 0 1 1 2 
+}
+
+finish_test