]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add extra tests and fixes for multi-column matches.
authordan <dan@noemail.net>
Fri, 29 May 2015 19:00:22 +0000 (19:00 +0000)
committerdan <dan@noemail.net>
Fri, 29 May 2015 19:00:22 +0000 (19:00 +0000)
FossilOrigin-Name: ae6794ffa23ef6191bd8834422abf322d978c11b

ext/fts5/fts5_expr.c
ext/fts5/test/fts5_common.tcl
ext/fts5/test/fts5ac.test
ext/fts5/test/fts5auto.test [new file with mode: 0644]
ext/fts5/test/fts5fault4.test
manifest
manifest.uuid

index 23827293feeac780157f6b9a5e5d1ebce4375257..18bcd0d374c2e1e0569264cfebbcca36725f88e2 100644 (file)
@@ -333,6 +333,14 @@ void sqlite3Fts5ExprFree(Fts5Expr *p){
   }
 }
 
+static int fts5ExprColsetTest(Fts5ExprColset *pColset, int iCol){
+  int i;
+  for(i=0; i<pColset->nCol; i++){
+    if( pColset->aiCol[i]==iCol ) return 1;
+  }
+  return 0;
+}
+
 /*
 ** All individual term iterators in pPhrase are guaranteed to be valid and
 ** pointing to the same rowid when this function is called. This function 
@@ -355,7 +363,12 @@ static int fts5ExprPhraseIsMatch(
   Fts5PoslistReader *aIter = aStatic;
   int i;
   int rc = SQLITE_OK;
-  int iCol = pColset ? pColset->aiCol[0] : -1;
+  int iCol = -1;
+  
+  if( pColset && pColset->nCol==1 ){
+    iCol = pColset->aiCol[0];
+    pColset = 0;
+  }
 
   fts5BufferZero(&pPhrase->poslist);
 
@@ -396,9 +409,11 @@ static int fts5ExprPhraseIsMatch(
       }
     }while( bMatch==0 );
 
-    /* Append position iPos to the output */
-    rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
-    if( rc!=SQLITE_OK ) goto ismatch_out;
+    if( pColset==0 || fts5ExprColsetTest(pColset, FTS5_POS2COLUMN(iPos)) ){
+      /* Append position iPos to the output */
+      rc = sqlite3Fts5PoslistWriterAppend(&pPhrase->poslist, &writer, iPos);
+      if( rc!=SQLITE_OK ) goto ismatch_out;
+    }
 
     for(i=0; i<pPhrase->nTerm; i++){
       if( sqlite3Fts5PoslistReaderNext(&aIter[i]) ) goto ismatch_out;
@@ -459,25 +474,25 @@ struct Fts5NearTrimmer {
 ** one phrase. All phrases currently point to the same row. The
 ** Fts5ExprPhrase.poslist buffers are populated accordingly. This function
 ** tests if the current row contains instances of each phrase sufficiently
-** close together to meet the NEAR constraint. Output variable *pbMatch
-** is set to true if it does, or false otherwise.
-**
-** If no error occurs, SQLITE_OK is returned. Or, if an error does occur,
-** an SQLite error code. If a value other than SQLITE_OK is returned, the
-** final value of *pbMatch is undefined.
+** close together to meet the NEAR constraint. Non-zero is returned if it
+** does, or zero otherwise.
 **
-** TODO: This function should also edit the position lists associated
-** with each phrase to remove any phrase instances that are not part of
-** a set of intances that collectively matches the NEAR constraint.
+** If in/out parameter (*pRc) is set to other than SQLITE_OK when this
+** function is called, it is a no-op. Or, if an error (e.g. SQLITE_NOMEM)
+** occurs within this function (*pRc) is set accordingly before returning.
+** The return value is undefined in both these cases.
+** 
+** If no error occurs and non-zero (a match) is returned, the position-list
+** of each phrase object is edited to contain only those entries that
+** meet the constraint before returning.
 */
-static int fts5ExprNearIsMatch(Fts5ExprNearset *pNear, int *pbMatch){
+static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){
   Fts5NearTrimmer aStatic[4];
   Fts5NearTrimmer *a = aStatic;
-
   Fts5ExprPhrase **apPhrase = pNear->apPhrase;
 
   int i;
-  int rc = SQLITE_OK;
+  int rc = *pRc;
   int bMatch;
 
   assert( pNear->nPhrase>1 );
@@ -486,12 +501,14 @@ static int fts5ExprNearIsMatch(Fts5ExprNearset *pNear, int *pbMatch){
   ** using sqlite3_malloc(). This approach could be improved upon. */
   if( pNear->nPhrase>(sizeof(aStatic) / sizeof(aStatic[0])) ){
     int nByte = sizeof(Fts5NearTrimmer) * pNear->nPhrase;
-    a = (Fts5NearTrimmer*)sqlite3_malloc(nByte);
-    if( !a ) return SQLITE_NOMEM;
-    memset(a, 0, nByte);
+    a = (Fts5NearTrimmer*)sqlite3Fts5MallocZero(&rc, nByte);
   }else{
     memset(aStatic, 0, sizeof(aStatic));
   }
+  if( rc!=SQLITE_OK ){
+    *pRc = rc;
+    return 0;
+  }
 
   /* Initialize a lookahead iterator for each phrase. After passing the
   ** buffer and buffer size to the lookaside-reader init function, zero
@@ -551,10 +568,12 @@ static int fts5ExprNearIsMatch(Fts5ExprNearset *pNear, int *pbMatch){
     if( fts5LookaheadReaderNext(&a[iAdv].reader) ) goto ismatch_out;
   }
 
- ismatch_out:
-  *pbMatch = (a[0].pOut->n>0);
-  if( a!=aStatic ) sqlite3_free(a);
-  return rc;
+  ismatch_out: {
+    int bRet = a[0].pOut->n>0;
+    *pRc = rc;
+    if( a!=aStatic ) sqlite3_free(a);
+    return bRet;
+  }
 }
 
 /*
@@ -700,6 +719,24 @@ static int fts5ExprExtractCol(
   return p - (*pa);
 }
 
+static int fts5ExprExtractColset (
+  Fts5ExprColset *pColset,        /* Colset to filter on */
+  const u8 *pPos, int nPos,       /* Position list */
+  Fts5Buffer *pBuf                /* Output buffer */
+){
+  int rc = SQLITE_OK;
+  int i;
+
+  fts5BufferZero(pBuf);
+  for(i=0; i<pColset->nCol; i++){
+    const u8 *pSub = pPos;
+    int nSub = fts5ExprExtractCol(&pSub, nPos, pColset->aiCol[i]);
+    if( nSub ){
+      fts5BufferAppendBlob(&rc, pBuf, nSub, pSub);
+    }
+  }
+  return rc;
+}
 
 
 /*
@@ -756,24 +793,14 @@ static int fts5ExprNearNextMatch(
         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);
-          }
-        }
+      }else if( rc==SQLITE_OK ){
+        rc = fts5ExprExtractColset(pColset, pPos, nPos, &pPhrase->poslist);
       }
 
       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);
       if( rc!=SQLITE_OK || pNode->bEof ) break;
@@ -794,12 +821,9 @@ static int fts5ExprNearNextMatch(
         }
       }
 
-      if( rc==SQLITE_OK && i==pNear->nPhrase ){
-        int bMatch = 1;
-        if( pNear->nPhrase>1 ){
-          rc = fts5ExprNearIsMatch(pNear, &bMatch);
-        }
-        if( rc!=SQLITE_OK || bMatch ) break;
+      if( i==pNear->nPhrase ){
+        if( i==1 ) break;
+        if( fts5ExprNearIsMatch(&rc, pNear) ) break;
       }
     }
 
@@ -1558,7 +1582,7 @@ static char *fts5ExprPrintTcl(
     int i; 
     int iTerm;
 
-    zRet = fts5PrintfAppend(zRet, "[%s ", zNearsetCmd);
+    zRet = fts5PrintfAppend(zRet, "%s ", zNearsetCmd);
     if( zRet==0 ) return 0;
     if( pNear->pColset ){
       int *aiCol = pNear->pColset->aiCol;
@@ -1596,7 +1620,6 @@ static char *fts5ExprPrintTcl(
       if( zRet==0 ) return 0;
     }
 
-    zRet = fts5PrintfAppend(zRet, "]");
     if( zRet==0 ) return 0;
 
   }else{
@@ -1604,24 +1627,18 @@ static char *fts5ExprPrintTcl(
     char *z1 = 0;
     char *z2 = 0;
     switch( pExpr->eType ){
-      case FTS5_AND: zOp = "&&"; break;
-      case FTS5_NOT: zOp = "&& !"; break;
+      case FTS5_AND: zOp = "AND"; break;
+      case FTS5_NOT: zOp = "NOT"; break;
       default: 
         assert( pExpr->eType==FTS5_OR );
-        zOp = "||"; 
+        zOp = "OR"; 
         break;
     }
 
     z1 = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pLeft);
     z2 = fts5ExprPrintTcl(pConfig, zNearsetCmd, pExpr->pRight);
     if( z1 && z2 ){
-      int b1 = pExpr->pLeft->eType!=FTS5_STRING;
-      int b2 = pExpr->pRight->eType!=FTS5_STRING;
-      zRet = sqlite3_mprintf("%s%s%s %s %s%s%s", 
-          b1 ? "(" : "", z1, b1 ? ")" : "",
-          zOp, 
-          b2 ? "(" : "", z2, b2 ? ")" : ""
-      );
+      zRet = sqlite3_mprintf("%s [%s] [%s]", zOp, z1, z2);
     }
     sqlite3_free(z1);
     sqlite3_free(z2);
index 70f5063b7906bddb5e7e66c7301bf2730993e918..e4a689bb729c6775fe679366a37ff8b1fb1b5315 100644 (file)
@@ -147,3 +147,139 @@ proc fts5_rnddoc {n} {
   set doc
 }
 
+#-------------------------------------------------------------------------
+# Usage:
+#
+#   nearset aCol ?-pc VARNAME? ?-near N? ?-col C? -- phrase1 phrase2...
+#
+# This command is used to test if a document (set of column values) matches
+# the logical equivalent of a single FTS5 NEAR() clump and, if so, return
+# the equivalent of an FTS5 position list.
+#
+# Parameter $aCol is passed a list of the column values for the document
+# to test. Parameters $phrase1 and so on are the phrases.
+#
+# The result is a list of phrase hits. Each phrase hit is formatted as
+# three integers separated by "." characters, in the following format:
+#
+#   <phrase number> . <column number> . <token offset>
+#
+# Options:
+#
+#   -near N        (NEAR distance. Default 10)
+#   -col  C        (List of column indexes to match against)
+#   -pc   VARNAME  (variable in caller frame to use for phrase numbering)
+#
+proc nearset {aCol args} {
+  set O(-near) 10
+  set O(-col)  {}
+  set O(-pc)   ""
+
+  set nOpt [lsearch -exact $args --]
+  if {$nOpt<0} { error "no -- option" }
+
+  foreach {k v} [lrange $args 0 [expr $nOpt-1]] {
+    if {[info exists O($k)]==0} { error "unrecognized option $k" }
+    set O($k) $v
+  }
+
+  if {$O(-pc) == ""} {
+    set counter 0
+  } else {
+    upvar $O(-pc) counter
+  }
+
+  # Set $phraselist to be a list of phrases. $nPhrase its length.
+  set phraselist [lrange $args [expr $nOpt+1] end]
+  set nPhrase [llength $phraselist]
+
+  for {set j 0} {$j < [llength $aCol]} {incr j} {
+    for {set i 0} {$i < $nPhrase} {incr i} { 
+      set A($j,$i) [list]
+    }
+  }
+
+  set iCol -1
+  foreach col $aCol {
+    incr iCol
+    if {$O(-col)!="" && [lsearch $O(-col) $iCol]<0} continue
+    set nToken [llength $col]
+
+    set iFL [expr $O(-near) >= $nToken ? $nToken - 1 : $O(-near)]
+    for { } {$iFL < $nToken} {incr iFL} {
+      for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
+        set B($iPhrase) [list]
+      }
+      
+      for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
+        set p [lindex $phraselist $iPhrase]
+        set nPm1 [expr {[llength $p] - 1}]
+        set iFirst [expr $iFL - $O(-near) - [llength $p]]
+
+        for {set i $iFirst} {$i <= $iFL} {incr i} {
+          if {[lrange $col $i [expr $i+$nPm1]] == $p} { lappend B($iPhrase) $i }
+        }
+        if {[llength $B($iPhrase)] == 0} break
+      }
+
+      if {$iPhrase==$nPhrase} {
+        for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
+          set A($iCol,$iPhrase) [concat $A($iCol,$iPhrase) $B($iPhrase)]
+          set A($iCol,$iPhrase) [lsort -integer -uniq $A($iCol,$iPhrase)]
+        }
+      }
+    }
+  }
+
+  set res [list]
+  #puts [array names A]
+
+  for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
+    for {set iCol 0} {$iCol < [llength $aCol]} {incr iCol} {
+      foreach a $A($iCol,$iPhrase) {
+        lappend res "$counter.$iCol.$a"
+      }
+    }
+    incr counter
+  }
+
+  #puts $res
+  sort_poslist $res
+}
+
+#-------------------------------------------------------------------------
+# Usage:
+#
+#   sort_poslist LIST
+#
+# Sort a position list of the type returned by command [nearset]
+#
+proc sort_poslist {L} {
+  lsort -command instcompare $L
+}
+proc instcompare {lhs rhs} {
+  foreach {p1 c1 o1} [split $lhs .] {}
+  foreach {p2 c2 o2} [split $rhs .] {}
+
+  set res [expr $c1 - $c2]
+  if {$res==0} { set res [expr $o1 - $o2] }
+  if {$res==0} { set res [expr $p1 - $p2] }
+
+  return $res
+}
+
+#-------------------------------------------------------------------------
+# Logical operators used by the commands returned by fts5_tcl_expr().
+#
+proc AND {a b} {
+  if {[llength $a]==0 || [llength $b]==0} { return [list] }
+  sort_poslist [concat $a $b]
+}
+proc OR {a b} {
+  sort_poslist [concat $a $b]
+}
+proc NOT {a b} {
+  if {[llength $b]} { return [list] }
+  return $a
+}
+
index eb58ca979172de2892d66b53fee0889cbacdbc0b..96c2e9f290b2dedd902df04cf7598982e5eb7104 100644 (file)
@@ -125,126 +125,6 @@ set data {
     99  {r c v w i v h a t a c v c r e}     {h h u m g o f b a e o}
 }
 
-#-------------------------------------------------------------------------
-# Usage:
-#
-#   poslist aCol ?-pc VARNAME? ?-near N? ?-col C? -- phrase1 phrase2...
-#
-# This command is used to test if a document (set of column values) matches
-# the logical equivalent of a single FTS5 NEAR() clump and, if so, return
-# the equivalent of an FTS5 position list.
-#
-# Parameter $aCol is passed a list of the column values for the document
-# to test. Parameters $phrase1 and so on are the phrases.
-#
-# The result is a list of phrase hits. Each phrase hit is formatted as
-# three integers separated by "." characters, in the following format:
-#
-#   <phrase number> . <column number> . <token offset>
-#
-# Options:
-#
-#   -near N        (NEAR distance. Default 10)
-#   -col  C        (List of column indexes to match against)
-#   -pc   VARNAME  (variable in caller frame to use for phrase numbering)
-#
-proc poslist {aCol args} {
-  set O(-near) 10
-  set O(-col)  {}
-  set O(-pc)   ""
-
-  set nOpt [lsearch -exact $args --]
-  if {$nOpt<0} { error "no -- option" }
-
-  foreach {k v} [lrange $args 0 [expr $nOpt-1]] {
-    if {[info exists O($k)]==0} { error "unrecognized option $k" }
-    set O($k) $v
-  }
-
-  if {$O(-pc) == ""} {
-    set counter 0
-  } else {
-    upvar $O(-pc) counter
-  }
-
-  # Set $phraselist to be a list of phrases. $nPhrase its length.
-  set phraselist [lrange $args [expr $nOpt+1] end]
-  set nPhrase [llength $phraselist]
-
-  for {set j 0} {$j < [llength $aCol]} {incr j} {
-    for {set i 0} {$i < $nPhrase} {incr i} { 
-      set A($j,$i) [list]
-    }
-  }
-
-  set iCol -1
-  foreach col $aCol {
-    incr iCol
-    if {$O(-col)!="" && [lsearch $O(-col) $iCol]<0} continue
-    set nToken [llength $col]
-
-    set iFL [expr $O(-near) >= $nToken ? $nToken - 1 : $O(-near)]
-    for { } {$iFL < $nToken} {incr iFL} {
-      for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
-        set B($iPhrase) [list]
-      }
-      
-      for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
-        set p [lindex $phraselist $iPhrase]
-        set nPm1 [expr {[llength $p] - 1}]
-        set iFirst [expr $iFL - $O(-near) - [llength $p]]
-
-        for {set i $iFirst} {$i <= $iFL} {incr i} {
-          if {[lrange $col $i [expr $i+$nPm1]] == $p} { lappend B($iPhrase) $i }
-        }
-        if {[llength $B($iPhrase)] == 0} break
-      }
-
-      if {$iPhrase==$nPhrase} {
-        for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
-          set A($iCol,$iPhrase) [concat $A($iCol,$iPhrase) $B($iPhrase)]
-          set A($iCol,$iPhrase) [lsort -integer -uniq $A($iCol,$iPhrase)]
-        }
-      }
-    }
-  }
-
-  set res [list]
-#puts [array names A]
-
-  for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
-    for {set iCol 0} {$iCol < [llength $aCol]} {incr iCol} {
-      foreach a $A($iCol,$iPhrase) {
-        lappend res "$counter.$iCol.$a"
-      }
-    }
-    incr counter
-  }
-
-    #puts $res
-  return $res
-}
-
-# Usage:
-#
-#   nearset aCol ?-near N? ?-col C? -- phrase1 phrase2...
-#
-proc nearset {args} {
-  set plist [poslist {*}$args]
-  return [expr [llength [lindex $plist 0]]>0]
-}
-
-proc instcompare {lhs rhs} {
-  foreach {p1 c1 o1} [split $lhs .] {}
-  foreach {p2 c2 o2} [split $rhs .] {}
-
-  set res [expr $c1 - $c2]
-  if {$res==0} { set res [expr $o1 - $o2] }
-  if {$res==0} { set res [expr $p1 - $p2] }
-
-  return $res
-}
-
 # Argument $expr is an FTS5 match expression designed to be executed against
 # an FTS5 table with the following schema:
 # 
@@ -262,25 +142,20 @@ proc instcompare {lhs rhs} {
 #
 proc matchdata {bPos expr {bAsc 1}} {
 
-  set tclexpr [db one {SELECT fts5_expr_tcl($expr, 'nearset $cols', 'x', 'y')}]
+  set tclexpr [db one {
+    SELECT fts5_expr_tcl($expr, 'nearset $cols -pc ::pc', 'x', 'y')
+  }]
   set res [list]
 
   #puts $tclexpr
   foreach {id x y} $::data {
     set cols [list $x $y]
-    if $tclexpr {
+    set ::pc 0
+    #set hits [lsort -command instcompare [eval $tclexpr]]
+    set hits [eval $tclexpr]
+    if {[llength $hits]>0} {
       if {$bPos} {
-        set N [regexp -all -inline {\[nearset [^\]]*\]} $tclexpr]
-        set rowres [list]
-        set cnt 0
-        foreach phrase $N {
-          set arglist [string range $phrase 9 end-1]
-          set cmd "poslist [lindex $arglist 0] -pc cnt [lrange $arglist 1 end]"
-          set pos [eval $cmd]
-          set rowres [concat $rowres $pos]
-        }
-        set rowres [lsort -command instcompare $rowres]
-        lappend res [list $id $rowres]
+        lappend res [list $id $hits]
       } else {
         lappend res $id
       }
@@ -425,11 +300,11 @@ foreach {tn2 sql} {
     } $res
   }
 
-  do_test $tn2.4.1  { poslist {{a b c}} -- a } {0.0.0}
-  do_test $tn2.4.2  { poslist {{a b c}} -- c } {0.0.2}
+  do_test $tn2.4.1  { nearset {{a b c}} -- a } {0.0.0}
+  do_test $tn2.4.2  { nearset {{a b c}} -- c } {0.0.2}
 
   foreach {tn expr tclexpr} {
-    1 {a b} {[N $x -- {a}] && [N $x -- {b}]}
+    1 {a b} {AND [N $x -- {a}] [N $x -- {b}]}
   } {
     do_execsql_test $tn2.5.$tn {
       SELECT fts5_expr_tcl($expr, 'N $x')
@@ -477,7 +352,7 @@ foreach {tn2 sql} {
 
 do_execsql_test 3.1 {
   SELECT fts5_expr_tcl('a AND b');
-} {{[nearset -- {a}] && [nearset -- {b}]}}
+} {{AND [nearset -- {a}] [nearset -- {b}]}}
 
 finish_test
 
diff --git a/ext/fts5/test/fts5auto.test b/ext/fts5/test/fts5auto.test
new file mode 100644 (file)
index 0000000..48d9148
--- /dev/null
@@ -0,0 +1,307 @@
+# 2015 May 30
+#
+# 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 contains automatically generated tests for various types
+# of MATCH expressions.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5auto
+
+# If SQLITE_ENABLE_FTS5 is defined, omit this file.
+ifcapable !fts5 {
+  finish_test
+  return
+}
+
+
+set data {
+    -4026076
+    {n x w k b p x b n t t d s}     {f j j s p j o}               
+    {w v i y r}                     {i p y s}                     
+    {a o q v e n q r}               {q v g u c y a z y}           
+    3995120
+    {c}                             {e e w d t}                   
+    {x c p f w r s m l r b f d}     {g g u e}                     
+    {s n u t d v p d}               {b k v p m f}                 
+    -2913881
+    {k m}                           {a}                           
+    {w r j z n s l}                 {m j i w d t w e l}           
+    {z n c}                         {v f b m}                     
+    174082
+    {j}                             {q l w u k e q v r i}         
+    {j l}                           {u v w r s p e l}             
+    {p i k j k q c t g u s}         {g u y s m h q k g t e s o r} 
+    3207399
+    {e t}                           {}                            
+    {p}                             {y v r b e k h d e v}         
+    {t m w z b g q t s d d h}       {o n v u i t o y k j}         
+    182399
+    {}                              {m o s o x d y f a x j z}     
+    {x n z r c d}                   {n r x i r}                   
+    {s v s}                         {a u}                         
+    768994
+    {e u t q v z q k j p u f j p}   {y c b}                       
+    {p s d}                         {k n w p m p p}               
+    {u o x s d}                     {f s g r d b d r m m m z y}   
+    3931037
+    {c j p x e}                     {c n k t h z o i}             
+    {}                              {r r p j k x w q}             
+    {o r d z d}                     {x}                           
+    3105748
+    {p x r u}                       {x i s w o t o g x m z i w}   
+    {q x m z}                       {h c j w b l y w x c o}       
+    {m b k v}                       {t v q i s a d x}             
+    -2501642
+    {o u d n w o m o o s n t r h}   {k p e u y p e z d j r y g}   
+    {v b b h d d q y j q j}         {a m w d t}                   
+    {y e f n}                       {a k x i x}                   
+    -1745680
+    {z u w j f d b f}               {j w i c g u d w e}           
+    {m f p v m a s p v c o s}       {s c r z o t w l b e a q}     
+    {m k q}                         {k b a v o}                   
+    -932328
+    {r v i u m q d r}               {f z u v h c m r f g}         
+    {r x r}                         {k p i d h h w h z u a x}     
+    {k m j p}                       {h l j a e u c i q x x f x g} 
+    -3923818
+    {t t p b n u i h e c k}         {m z}                         
+    {v u d c}                       {v y y j s g}                 
+    {o a f k k q p h g x e n z x}   {h d w c o l}                 
+    -2145922
+    {z z l f a l g e d c d h}       {j b j p k o o u b q}         
+    {d i g q t f d r h k}           {n w g j c x r p t y f l c t} 
+    {d o c u k f o}                 {r y s x z s p p h g t p y c} 
+    4552917
+    {j w j y h l k u}               {n a}                         
+    {y h w c n k}                   {b}                           
+    {w}                             {z l r t s i m v c y}         
+    2292008
+    {q v q j w y y x u t}           {r q z n h a b o}             
+    {d q y}                         {y v o e j}                   
+    {}                              {a b h c d l p d x}           
+    1407892
+    {n j j u q d o a u c f}         {r d b w o q n g}             
+    {d e v w s}                     {v d v o u o x s l s j z y}   
+    {j y w h i f g i h m}           {v n z b n y}                 
+    -4412544
+    {g h h r s}                     {h e r e}                     
+    {n q s}                         {o p z r m l l t}             
+    {p}                             {f s u o b j}                 
+    1209110
+    {o a a z t t u h j}             {z z i r k r}                 
+    {i c x q w g v o x z i z p}     {q o g k i n z x e d v w v}   
+    {p f v b g f e d n p u c y k}   {q z z a i p a a s r e z}     
+    3448977
+    {i v}                           {l u x t b o k}               
+    {f h u v p}                     {k a o y j}                   
+    {d m k c j}                     {v c e r u e f i t}           
+    -4703774
+    {d h v w u z r e h x o l t}     {p s f y w y r q d a m w}     
+    {c h g c g j j f t b i c q}     {s e}                         
+    {c t q j g f}                   {v n r w y r a g e j d}       
+    2414151
+    {s o o s d s k q b f q v p e}   {j r o b t o p d l o o x}     
+    {d d k t v e}                   {}                            
+    {t v o d w}                     {w e q w h y c y y i j b a m} 
+    -3342407
+    {m c h n e p d o c r w n t}     {j d k s p q l}               
+    {t g s r w x j l r z r}         {h}                           
+    {r q v x i r a n h s}           {m y p b v w r a u o g q r}   
+    -993951
+    {l n p u o j d x t u u c o j}   {k r n a r e k v i t o e}     
+    {q f t t a a c z v f}           {o n m p v f o e n}           
+    {h z h i p s b j z h}           {i t w m k c u g n i}         
+    1575251
+    {}                              {z s i j d o x j a r t}       
+    {h g j u j n v e n z}           {p z j n n f}                 
+    {s q q f d w r l y i z d o m}   {b a n d h t b y g h d}       
+    4263668
+    {q g t h f s}                   {s g x p f q z i s o f l i}   
+    {q k}                           {w v h a x n a r b}           
+    {m j a h o b i x k r w z q u}   {m t r g j o e q t m p u l}   
+    2487819
+    {m w g x r n e u t s r}         {b x a t u u j c r n}         
+    {j}                             {w f j r e e y l p}           
+    {o u h b}                       {o c a c a b v}               
+    167966
+    {o d b s d o a u m o x y}       {c}                           
+    {r w d o b v}                   {z e b}                       
+    {i n z a f g z o}               {m u b a g}                   
+    1948599
+    {n r g q d j s}                 {n k}                         
+    {l b p d v t k h y y}           {u m k e c}                   
+    {t b n y o t b}                 {j w c i r x x}               
+    2941631
+    {l d p l b g f}                 {e k e}                       
+    {p j}                           {m c s w t b k n l d x}       
+    {f o v y v l}                   {c w p s w j w c u t y}       
+    3561104
+    {d r j j r j i g p}             {u}                           
+    {g r j q}                       {z l p d s n f c h t d c v z} 
+    {w r c f s x z y}               {g f o k g g}                 
+    -2223281
+    {y e t j j z f p o m m z}       {h k o g o}                   
+    {m x a t}                       {l q x l}                     
+    {r w k d l s y b}               {q g k b}                     
+    -4502874
+    {k k b x k l f}                 {r}                           
+    {}                              {q m z b k h k u n e z}       
+    {z q g y m y u}                 {}                            
+    1757599
+    {d p z j y u r}                 {z p l q w j t j}             
+    {n i r x r y j}                 {}                            
+    {h}                             {w t d q c x z z x e e}       
+    -4809589
+    {}                              {z p x u h i i n g}           
+    {w q s u d b f x n}             {l y k b b r x t i}           
+    {n d v j q o t o d p z e}       {u r y u v u c}               
+    1068408
+    {y e}                           {e g s k e w t p v o b k}     
+    {z c m s}                       {r u r u h n h b p q g b}     
+    {j k b l}                       {m c d t s r s q a d b o f}   
+    -1972554
+    {m s w}                         {d k v s a r k p a r i v}     
+    {g j z k p}                     {y k c v r e u o q f i b a}   
+    {i p i}                         {c z w c y b n z i v}         
+    -2052385
+    {}                              {x e u f f g n c i x n e i e} 
+    {}                              {p s w d x p g}               
+    {}                              {s j a h n}                   
+    2805981
+    {m x g c w o e}                 {k g u y r y i u e g g}       
+    {f k j v t x p h x k u}         {w i}                         
+    {b l f z f v t n}               {i u d o d p h s m u}         
+    2507621
+    {}                              {u b n l x f n j t}           
+    {u r x l h}                     {h r l m r}                   
+    {d y e n b s q v t k n q q}     {x l t v w h a s k}           
+    -3138375
+    {e o f j y x u w v e w z}       {r d q g k n n v r c z n e w} 
+    {l y i q z k j p u f q s k}     {c i l l i m a a g a z r x f} 
+    {a v k h m q z b y n z}         {q g w c y r r o a}           
+    -457971
+    {j x a w e c s h f l f}         {q}                           
+    {j f v j u m d q r v v}         {x n v a w}                   
+    {i e h d h f u w t t z}         {v s u l s v o v i k n e}     
+    2265221
+    {z t c y w n y r t}             {n b a x s}                   
+    {q w a v}                       {a b s d x i g w t e z h}     
+    {t l}                           {j k r w f f y j o k u}       
+    -3941280
+    {r x t o z}                     {f j n z k}                   
+    {t x e b t d b k w i s}         {j t y h i h}                 
+    {y q g n g s u v c z j z n g}   {n n g t l p h}               
+    2084745
+    {z d z d}                       {j}                           
+    {o e k t b k a z l w}           {o p i h k c x}               
+    {c r b t i j f}                 {z e n m}                     
+    1265843
+    {}                              {j s g j j x u y}             
+    {u q t f}                       {g o g}                       
+    {w o j e d}                     {w q n a c t q x j}           
+    -2941116
+    {i n c u o}                     {f b}                         
+    {o m s q d o z a q}             {f s v o b b}                 
+    {o a z c h r}                   {j e w h b f z}               
+    -1265441
+    {p g z q v a o a x a}           {s t h}                       
+    {w i p o c}                     {s n d g f z w q o d v v l j} 
+    {y f b i a s v}                 {u m o z k k s t s d p b l p} 
+    -1989158
+    {r i c n}                       {r e w w i n z}               
+    {q u s y b w u g y g f o}       {y}                           
+    {d}                             {j x i b x u y d c p v a h}   
+    2391989
+    {b n w x w f q h p i}           {e u b b i n a i o c d g}     
+    {v a z o i e n l x l r}         {r u f o r k w m d w}         
+    {k s}                           {r f e j q p w}               
+}
+
+do_test 1.0 {
+  execsql {
+    BEGIN;
+    CREATE VIRTUAL TABLE tt USING fts5(a, b, c, d, e, f);
+  }
+  foreach {rowid a b c d e f} $data {
+    execsql {
+      INSERT INTO tt(rowid, a, b, c, d, e, f) 
+      VALUES($rowid, $a, $b, $c, $d, $e, $f)
+    }
+  }
+  execsql {
+    COMMIT;
+  }
+} {}
+
+proc fts5_test_poslist {cmd} {
+  set res [list]
+  for {set i 0} {$i < [$cmd xInstCount]} {incr i} {
+    lappend res [string map {{ } .} [$cmd xInst $i]]
+  }
+  set res
+}
+sqlite3_fts5_create_function db fts5_test_poslist fts5_test_poslist
+
+proc matchdata {expr} {
+  set tclexpr [db one {
+    SELECT fts5_expr_tcl(
+      $expr, 'nearset $cols -pc ::pc', 'a','b','c','d','e','f'
+    )
+  }]
+  set res [list]
+
+  db eval {SELECT rowid, * FROM tt} {
+    set cols [list $a $b $c $d $e $f]
+    set ::pc 0
+    set rowdata [eval $tclexpr]
+
+    if {$rowdata != ""} {
+      lappend res $rowid $rowdata
+    }
+  }
+
+  set res
+}
+
+#-------------------------------------------------------------------------
+#
+
+do_execsql_test 2.0 {
+  SELECT rowid, fts5_test_poslist(tt) FROM tt WHERE tt MATCH 'a AND b';
+} [matchdata "a AND b"]
+
+do_test 2.1 {
+  llength [matchdata "a AND b"]
+} 62
+
+foreach {tn expr} {
+  1 { [a] : x }
+  2 { [a b] : x }
+  3 { [a b f] : x }
+  4 { [f a b] : x }
+  5 { [f a b] : x y }
+  6 { [f a b] : x + y }
+  7 { [c a b] : x + c }
+  8 { [c d] : "l m" }
+  9 { [c e] : "l m" }
+} {
+  set res [matchdata $expr]
+  do_test 3.$tn.[llength $res] {
+    execsql {
+      SELECT rowid, fts5_test_poslist(tt) FROM tt WHERE tt MATCH $expr
+    }
+  } $res
+}
+
+
+finish_test
+
index fe3fb0796a7a21b345b2fd0867ca5dcd6a194dff..417d470ed30aa32e8be5d91448b0cef04312ed75 100644 (file)
@@ -312,7 +312,7 @@ do_faultsim_test 10.1 -faults oom-t* -body {
 do_faultsim_test 10.2 -faults oom-t* -body {
   db one { SELECT fts5_expr_tcl('x:"a b c" AND b NEAR(a b)', 'ns', 'x') }
 } -test {
-  set res {[ns -col 0 -- {a b c}] && ([ns -- {b}] && [ns -near 10 -- {a} {b}])}
+  set res {AND [ns -col 0 -- {a b c}] [AND [ns -- {b}] [ns -near 10 -- {a} {b}]]}
   faultsim_test_result [list 0 $res]
 }
 
index 47d2f6be5cd4a4bc7adf023bcca70b31ce0f3e13..ecafa77346ae09d2c29286a1291ea1d84c9f1534 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-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
+C Add\sextra\stests\sand\sfixes\sfor\smulti-column\smatches.
+D 2015-05-29T19:00:22.571
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 2c28e557780395095c307a6e5cb539419027eb5e
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -111,7 +111,7 @@ 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 c607282529c7b5747fc2bcf80770d6abc22638bb
+F ext/fts5/fts5_expr.c 1685b331ecb880cb8807e2dc7fc4184d2933bb96
 F ext/fts5/fts5_hash.c 54dd25348a46ea62ea96322c572e08cd1fb37304
 F ext/fts5/fts5_index.c 59b8a3dfde24ddb80c31088148a3dfc779db22ab
 F ext/fts5/fts5_storage.c 5d2b51adb304643d8f825ba89283d628418b20c2
@@ -121,10 +121,10 @@ F ext/fts5/fts5_unicode2.c da3cf712f05cd8347c8c5bc00964cc0361c88da9
 F ext/fts5/fts5_vocab.c 1f8543b2c1ae4427f127a911bc8e60873fcd7bf9
 F ext/fts5/fts5parse.y 4ee667932d561a150d96483cf563281b95a9e523
 F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
-F ext/fts5/test/fts5_common.tcl 6d663e8c3d8409857363f66560df96b8ca813e79
+F ext/fts5/test/fts5_common.tcl 632ff0fd8bf3dd55c2ddaac2c16428548d5af7be
 F ext/fts5/test/fts5aa.test 5f73afe6a1394fdba9bc18302876ded81021bee6
 F ext/fts5/test/fts5ab.test 6fe3a56731d15978afbb74ae51b355fc9310f2ad
-F ext/fts5/test/fts5ac.test d35bbe22dd23b3dbac3e1d3f07eed0206213a480
+F ext/fts5/test/fts5ac.test 999fd5f44579f1eb565ed7cf3861c427537ff097
 F ext/fts5/test/fts5ad.test 312f3c8ed9592533499c5b94d2059ae6382913a0
 F ext/fts5/test/fts5ae.test 9175201baf8c885fc1cbb2da11a0c61fd11224db
 F ext/fts5/test/fts5af.test c2501ec2b61d6b179c305f5d2b8782ab3d4f832a
@@ -134,6 +134,7 @@ F ext/fts5/test/fts5ai.test f20e53bbf0c55bc596f1fd47f2740dae028b8f37
 F ext/fts5/test/fts5aj.test 05b569f5c16ea3098fb1984eec5cf50dbdaae5d8
 F ext/fts5/test/fts5ak.test 7b8c5df96df599293f920b7e5521ebc79f647592
 F ext/fts5/test/fts5al.test fc60ebeac9d8e366e71309d4c31fa72199d711d7
+F ext/fts5/test/fts5auto.test 62e62fa7d60c50d334c5f6cf6b1ed1d49fa3d8d8
 F ext/fts5/test/fts5aux.test e5631607bbc05ac1c38cf7d691000509aca71ef3
 F ext/fts5/test/fts5auxdata.test c69b86092bf1a157172de5f9169731af3403179b
 F ext/fts5/test/fts5bigpl.test b1cfd00561350ab04994ba7dd9d48468e5e0ec3b
@@ -149,7 +150,7 @@ F ext/fts5/test/fts5eb.test 728a1f23f263548f5c29b29dfb851b5f2dbe723e
 F ext/fts5/test/fts5fault1.test b42d3296be8a75f557cf2cbce0d8b483fc9db45b
 F ext/fts5/test/fts5fault2.test 28c36c843bb39ae855ba79827417ecc37f114341
 F ext/fts5/test/fts5fault3.test d6e9577d4312e331a913c72931bf131704efc8f3
-F ext/fts5/test/fts5fault4.test e7170486d71de72fe88018b5b920c0a9f6c19801
+F ext/fts5/test/fts5fault4.test b854f9895cb07cec58204d5a7ca82d03ce824e73
 F ext/fts5/test/fts5fault5.test 54da9fd4c3434a1d4f6abdcb6469299d91cf5875
 F ext/fts5/test/fts5fault6.test 234dc6355f8d3f8b5be2763f30699d770247c215
 F ext/fts5/test/fts5full.test 0924bdca5416a242103239ace79c6f5aa34bab8d
@@ -1331,7 +1332,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P b29ac50af0491a780a5a4c0985d88d0e5e014ba3
-R 34ff180b006ad5f21871399f838e5dbb
+P 0fc0ea20920615f3e48ea2dbe2b7dcd979b0993e
+R 358d1aaaac138ca9e6a38de66a871d33
 U dan
-Z f15f3e2fe41d81aa9045dd94b23ec6a4
+Z c843d103a5028eb0d546bbe1e7e6abdc
index d1b95a249f4738a3cc51e8e105bce88bd9bebec9..6a7e8e7df137072b193e13aa5731cbbc8036cd21 100644 (file)
@@ -1 +1 @@
-0fc0ea20920615f3e48ea2dbe2b7dcd979b0993e
\ No newline at end of file
+ae6794ffa23ef6191bd8834422abf322d978c11b
\ No newline at end of file