Fix a bug exposed by combining matchinfo(), NEAR and "ORDER BY rowid DESC".

FossilOrigin-Name: 5f6b87f420f21749aa7c72e020c50aca74890086
This commit is contained in:
dan 2011-06-13 09:11:01 +00:00
parent 786b068967
commit 99ebad90e3
9 changed files with 481 additions and 16 deletions

View File

@ -379,7 +379,8 @@ TESTSRC = \
$(TOP)/src/test_vfs.c \
$(TOP)/src/test_wholenumber.c \
$(TOP)/src/test_wsd.c \
$(TOP)/ext/fts3/fts3_term.c
$(TOP)/ext/fts3/fts3_term.c \
$(TOP)/ext/fts3/fts3_test.c
# Source code to the library files needed by the test fixture
#

View File

@ -2727,8 +2727,10 @@ static int fts3RollbackMethod(sqlite3_vtab *pVtab){
** same position list.
*/
static void fts3ReversePoslist(char *pStart, char **ppPoslist){
char *p = &(*ppPoslist)[-3];
char c = p[1];
char *p = &(*ppPoslist)[-2];
char c;
while( p>pStart && (c=*p--)==0 );
while( p>pStart && (*p & 0x80) | c ){
c = *p--;
}
@ -3422,6 +3424,7 @@ void sqlite3Fts3DoclistPrev(
iDocid += (iMul * iDelta);
pNext = pDocid;
fts3PoslistCopy(0, &pDocid);
while( pDocid<pEnd && *pDocid==0 ) pDocid++;
}
*pnList = pEnd - pNext;

249
ext/fts3/fts3_test.c Normal file
View File

@ -0,0 +1,249 @@
/*
** 2011 Jun 13
**
** 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 is not part of the production FTS code. It is only used for
** testing. It contains a Tcl command that can be used to test if a document
** matches an FTS NEAR expression.
*/
#include <tcl.h>
#include <string.h>
#include <assert.h>
#define NM_MAX_TOKEN 12
typedef struct NearPhrase NearPhrase;
typedef struct NearDocument NearDocument;
typedef struct NearToken NearToken;
struct NearDocument {
int nToken; /* Length of token in bytes */
NearToken *aToken; /* Token array */
};
struct NearToken {
int n; /* Length of token in bytes */
const char *z; /* Pointer to token string */
};
struct NearPhrase {
int nNear; /* Preceding NEAR value */
int nToken; /* Number of tokens in this phrase */
NearToken aToken[NM_MAX_TOKEN]; /* Array of tokens in this phrase */
};
static int nm_phrase_match(
NearPhrase *p,
NearToken *aToken
){
int ii;
for(ii=0; ii<p->nToken; ii++){
NearToken *pToken = &p->aToken[ii];
if( pToken->n>0 && pToken->z[pToken->n-1]=='*' ){
if( aToken[ii].n<(pToken->n-1) ) return 0;
if( memcmp(aToken[ii].z, pToken->z, pToken->n-1) ) return 0;
}else{
if( aToken[ii].n!=pToken->n ) return 0;
if( memcmp(aToken[ii].z, pToken->z, pToken->n) ) return 0;
}
}
return 1;
}
static int nm_near_chain(
int iDir, /* Direction to iterate through aPhrase[] */
NearDocument *pDoc, /* Document to match against */
int iPos, /* Position at which iPhrase was found */
int nPhrase, /* Size of phrase array */
NearPhrase *aPhrase, /* Phrase array */
int iPhrase /* Index of phrase found */
){
int iStart;
int iStop;
int ii;
int nNear;
int iPhrase2;
NearPhrase *p;
NearPhrase *pPrev;
assert( iDir==1 || iDir==-1 );
if( iDir==1 ){
if( (iPhrase+1)==nPhrase ) return 1;
nNear = aPhrase[iPhrase+1].nNear;
}else{
if( iPhrase==0 ) return 1;
nNear = aPhrase[iPhrase].nNear;
}
pPrev = &aPhrase[iPhrase];
iPhrase2 = iPhrase+iDir;
p = &aPhrase[iPhrase2];
iStart = iPos - nNear - p->nToken;
iStop = iPos + nNear + pPrev->nToken;
if( iStart<0 ) iStart = 0;
if( iStop > pDoc->nToken - p->nToken ) iStop = pDoc->nToken - p->nToken;
for(ii=iStart; ii<=iStop; ii++){
if( nm_phrase_match(p, &pDoc->aToken[ii]) ){
if( nm_near_chain(iDir, pDoc, ii, nPhrase, aPhrase, iPhrase2) ) return 1;
}
}
return 0;
}
static int nm_match_count(
NearDocument *pDoc, /* Document to match against */
int nPhrase, /* Size of phrase array */
NearPhrase *aPhrase, /* Phrase array */
int iPhrase /* Index of phrase to count matches for */
){
int nOcc = 0;
int ii;
NearPhrase *p = &aPhrase[iPhrase];
for(ii=0; ii<(pDoc->nToken + 1 - p->nToken); ii++){
if( nm_phrase_match(p, &pDoc->aToken[ii]) ){
/* Test forward NEAR chain (i>iPhrase) */
if( 0==nm_near_chain(1, pDoc, ii, nPhrase, aPhrase, iPhrase) ) continue;
/* Test reverse NEAR chain (i<iPhrase) */
if( 0==nm_near_chain(-1, pDoc, ii, nPhrase, aPhrase, iPhrase) ) continue;
/* This is a real match. Increment the counter. */
nOcc++;
}
}
return nOcc;
}
/*
** Tclcmd: fts3_near_match DOCUMENT EXPR ?OPTIONS?
*/
static int fts3_near_match_cmd(
ClientData clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
int nTotal = 0;
int rc;
int ii;
int nPhrase;
NearPhrase *aPhrase = 0;
NearDocument doc = {0, 0};
Tcl_Obj **apDocToken;
Tcl_Obj *pRet;
Tcl_Obj *pPhrasecount = 0;
Tcl_Obj **apExprToken;
int nExprToken;
/* Must have 3 or more arguments. */
if( objc<3 || (objc%2)==0 ){
Tcl_WrongNumArgs(interp, 1, objv, "DOCUMENT EXPR ?OPTION VALUE?...");
rc = TCL_ERROR;
goto near_match_out;
}
for(ii=3; ii<objc; ii+=2){
enum NM_enum { NM_PHRASECOUNTS };
struct TestnmSubcmd {
char *zName;
enum NM_enum eOpt;
} aOpt[] = {
{ "-phrasecountvar", NM_PHRASECOUNTS },
{ 0, 0 }
};
int iOpt;
if( Tcl_GetIndexFromObjStruct(
interp, objv[ii], aOpt, sizeof(aOpt[0]), "option", 0, &iOpt)
){
return TCL_ERROR;
}
switch( aOpt[iOpt].eOpt ){
case NM_PHRASECOUNTS:
pPhrasecount = objv[ii+1];
break;
}
}
rc = Tcl_ListObjGetElements(interp, objv[1], &doc.nToken, &apDocToken);
if( rc!=TCL_OK ) goto near_match_out;
doc.aToken = (NearToken *)ckalloc(doc.nToken*sizeof(NearToken));
for(ii=0; ii<doc.nToken; ii++){
doc.aToken[ii].z = Tcl_GetStringFromObj(apDocToken[ii], &doc.aToken[ii].n);
}
rc = Tcl_ListObjGetElements(interp, objv[2], &nExprToken, &apExprToken);
if( rc!=TCL_OK ) goto near_match_out;
nPhrase = (nExprToken + 1) / 2;
aPhrase = (NearPhrase *)ckalloc(nPhrase * sizeof(NearPhrase));
memset(aPhrase, 0, nPhrase * sizeof(NearPhrase));
for(ii=0; ii<nPhrase; ii++){
Tcl_Obj *pPhrase = apExprToken[ii*2];
Tcl_Obj **apToken;
int nToken;
int jj;
rc = Tcl_ListObjGetElements(interp, pPhrase, &nToken, &apToken);
if( rc!=TCL_OK ) goto near_match_out;
if( nToken>NM_MAX_TOKEN ){
Tcl_AppendResult(interp, "Too many tokens in phrase", 0);
rc = TCL_ERROR;
goto near_match_out;
}
for(jj=0; jj<nToken; jj++){
NearToken *pT = &aPhrase[ii].aToken[jj];
pT->z = Tcl_GetStringFromObj(apToken[jj], &pT->n);
}
aPhrase[ii].nToken = nToken;
}
for(ii=1; ii<nPhrase; ii++){
Tcl_Obj *pNear = apExprToken[2*ii-1];
int nNear;
rc = Tcl_GetIntFromObj(interp, pNear, &nNear);
if( rc!=TCL_OK ) goto near_match_out;
aPhrase[ii].nNear = nNear;
}
pRet = Tcl_NewObj();
Tcl_IncrRefCount(pRet);
for(ii=0; ii<nPhrase; ii++){
int nOcc = nm_match_count(&doc, nPhrase, aPhrase, ii);
Tcl_ListObjAppendElement(interp, pRet, Tcl_NewIntObj(nOcc));
nTotal += nOcc;
}
if( pPhrasecount ){
Tcl_ObjSetVar2(interp, pPhrasecount, 0, pRet, 0);
}
Tcl_DecrRefCount(pRet);
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(nTotal>0));
near_match_out:
ckfree((char *)aPhrase);
ckfree((char *)doc.aToken);
return rc;
}
int Sqlitetestfts3_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "fts3_near_match", fts3_near_match_cmd, 0, 0);
return TCL_OK;
}

View File

@ -220,6 +220,7 @@ SRC += \
# Source code to the test files.
#
TESTSRC = \
$(TOP)/ext/fts3/fts3_test.c \
$(TOP)/src/test1.c \
$(TOP)/src/test2.c \
$(TOP)/src/test3.c \

View File

@ -1,7 +1,7 @@
C Fix\sproblems\sto\sdo\swith\susing\sboth\sOR\sand\sNEAR\soperators\sin\sa\ssingle\sexpression.
D 2011-06-09T10:48:02.352
C Fix\sa\sbug\sexposed\sby\scombining\smatchinfo(),\sNEAR\sand\s"ORDER\sBY\srowid\sDESC".
D 2011-06-13T09:11:01.953
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 11dcc00a8d0e5202def00e81732784fb0cc4fe1d
F Makefile.in c1d7a7f4fd8da6b1815032efca950e3d5125407e
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F Makefile.vxworks c85ec1d8597fe2f7bc225af12ac1666e21379151
F README cd04a36fbc7ea56932a4052d7d0b7f09f27c33d6
@ -61,7 +61,7 @@ F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0
F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a
F ext/fts3/README.tokenizers 998756696647400de63d5ba60e9655036cb966e9
F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d
F ext/fts3/fts3.c 5df3b5797522d3d17949ee12d5918d6d213b5114
F ext/fts3/fts3.c e71dafb1f324358d12fd02ea12644d8c6cea577a
F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe
F ext/fts3/fts3Int.h a999cfbf605efec293a88519f74192f5204c84d6
F ext/fts3/fts3_aux.c baed9dab7fb4604ae8cafdb2d7700abe93beffbe
@ -72,6 +72,7 @@ F ext/fts3/fts3_icu.c ac494aed69835008185299315403044664bda295
F ext/fts3/fts3_porter.c d61cfd81fb0fd8fbcb25adcaee0ba671aefaa5c2
F ext/fts3/fts3_snippet.c 82e2c1e420c871c02f6e85ea438570118d7105c8
F ext/fts3/fts3_term.c 6c7f33ab732a2a0f281898685650e3a492e1e2f1
F ext/fts3/fts3_test.c 9376cc865447e63c671f0f9ffd1a2c9a29678230
F ext/fts3/fts3_tokenizer.c 055f3dc7369585350b28db1ee0f3b214dca6724d
F ext/fts3/fts3_tokenizer.h 13ffd9fcb397fec32a05ef5cd9e0fa659bf3dbd3
F ext/fts3/fts3_tokenizer1.c 6e5cbaa588924ac578263a598e4fb9f5c9bb179d
@ -102,7 +103,7 @@ F ext/rtree/tkt3363.test 142ab96eded44a3615ec79fba98c7bde7d0f96de
F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F main.mk 6111163d4e9720e4212ef288e967b4aa2c2ce379
F main.mk 6de0d92dcae3d399a6bafaeb23b57f6ef0f41955
F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a
F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f
F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac
@ -185,7 +186,7 @@ F src/sqliteInt.h 6e58c558c57c8f44011736d5fa5295eb3130f9de
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac64842c86cec2fc1a1d0e5c16d3beb8ad332bf
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 501c9a200fd998a268be475be5858febc90b725b
F src/tclsqlite.c c83f5b4a15ed92cb35aa04320aa4a30b95071b2f
F src/test1.c efca486a25fb894988e7a82e84579a4e57388a02
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
@ -454,6 +455,7 @@ F test/fts3am.test 218aa6ba0dfc50c7c16b2022aac5c6be593d08d8
F test/fts3an.test a49ccadc07a2f7d646ec1b81bc09da2d85a85b18
F test/fts3ao.test b83f99f70e9eec85f27d75801a974b3f820e01f9
F test/fts3atoken.test 402ef2f7c2fb4b3d4fa0587df6441c1447e799b3
F test/fts3auto.test 696a2d32dd64a03aa47818c26ea64f8f27e7eb07
F test/fts3aux1.test 0b02743955d56fc0d4d66236a26177bd1b726de0
F test/fts3b.test e93bbb653e52afde110ad53bbd793f14fe7a8984
F test/fts3c.test fc723a9cf10b397fdfc2b32e73c53c8b1ec02958
@ -692,7 +694,7 @@ F test/tclsqlite.test 8c154101e704170c2be10f137a5499ac2c6da8d3
F test/tempdb.test 19d0f66e2e3eeffd68661a11c83ba5e6ace9128c
F test/temptable.test f42121a0d29a62f00f93274464164177ab1cc24a
F test/temptrigger.test b0273db072ce5f37cf19140ceb1f0d524bbe9f05
F test/tester.tcl a791ee74cb6b8f8613079ccc018bf2c8b952a26c
F test/tester.tcl 76222602e59047c6ef119473c7a2ea7c6ee73d09
F test/thread001.test a3e6a7254d1cb057836cb3145b60c10bf5b7e60f
F test/thread002.test afd20095e6e845b405df4f2c920cb93301ca69db
F test/thread003.test b824d4f52b870ae39fc5bae4d8070eca73085dca
@ -943,7 +945,7 @@ F tool/split-sqlite3c.tcl d9be87f1c340285a3e081eb19b4a247981ed290c
F tool/symbols.sh bc2a3709940d47c8ac8e0a1fdf17ec801f015a00
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings.sh 347d974d143cf132f953b565fbc03026f19fcb4d
P 3972a787df5ec253b99b148385655e7b68d851fa
R 9f88ec7fe13b9820fcb74aa4a46dd50c
P 4e8dd19eef04777d800977faf1859a405e396f30
R 6b4754b974de210b10ad796c5876a1bc
U dan
Z 78f71a9a33e1daee77ff848d72b67bf4
Z f1c93614cce7c70636f14d06ee6a3496

View File

@ -1 +1 @@
4e8dd19eef04777d800977faf1859a405e396f30
5f6b87f420f21749aa7c72e020c50aca74890086

View File

@ -3585,6 +3585,10 @@ static void init_all(Tcl_Interp *interp){
extern int Sqlitetestfuzzer_Init(Tcl_Interp*);
extern int Sqlitetestwholenumber_Init(Tcl_Interp*);
#ifdef SQLITE_ENABLE_FTS3
extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
#endif
#ifdef SQLITE_ENABLE_ZIPVFS
extern int Zipvfs_Init(Tcl_Interp*);
Zipvfs_Init(interp);
@ -3625,6 +3629,10 @@ static void init_all(Tcl_Interp *interp){
Sqlitetestfuzzer_Init(interp);
Sqlitetestwholenumber_Init(interp);
#ifdef SQLITE_ENABLE_FTS3
Sqlitetestfts3_Init(interp);
#endif
Tcl_CreateObjCommand(interp,"load_testfixture_extensions",init_all_cmd,0,0);
#ifdef SQLITE_SSE

201
test/fts3auto.test Normal file
View File

@ -0,0 +1,201 @@
# 2011 June 10
#
# 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# If this build does not include FTS3, skip the tests in this file.
#
ifcapable !fts3 { finish_test ; return }
source $testdir/fts3_common.tcl
source $testdir/malloc_common.tcl
set testprefix fts3rnd2
proc test_fts3_near_match {tn doc expr res} {
fts3_near_match $doc $expr -phrasecountvar p
uplevel do_test [list $tn] [list [list set {} $p]] [list $res]
}
# Simple test cases for C routine [fts3_near_match].
#
test_fts3_near_match 1.1.1 {a b c a b} a {2}
test_fts3_near_match 1.1.2 {a b c a b} {a 5 b 6 c} {2 2 1}
test_fts3_near_match 1.1.3 {a b c a b} {"a b"} {2}
test_fts3_near_match 1.1.4 {a b c a b} {"b c"} {1}
test_fts3_near_match 1.1.5 {a b c a b} {"c c"} {0}
test_fts3_near_match 1.2.1 "a b c d e f g" {b 2 f} {0 0}
test_fts3_near_match 1.2.2 "a b c d e f g" {b 3 f} {1 1}
test_fts3_near_match 1.2.3 "a b c d e f g" {f 2 b} {0 0}
test_fts3_near_match 1.2.4 "a b c d e f g" {f 3 b} {1 1}
test_fts3_near_match 1.2.5 "a b c d e f g" {"a b" 2 "f g"} {0 0}
test_fts3_near_match 1.2.6 "a b c d e f g" {"a b" 3 "f g"} {1 1}
set A "a b c d e f g h i j k l m n o p q r s t u v w x y z"
test_fts3_near_match 1.3.1 $A {"c d" 5 "i j" 1 "e f"} {0 0 0}
test_fts3_near_match 1.3.2 $A {"c d" 5 "i j" 2 "e f"} {1 1 1}
proc mit {blob} {
set scan(littleEndian) i*
set scan(bigEndian) I*
binary scan $blob $scan($::tcl_platform(byteOrder)) r
return $r
}
db func mit mit
proc fix_near_expr {expr} {
set out [list]
lappend out [lindex $expr 0]
foreach {a b} [lrange $expr 1 end] {
if {[string match -nocase near $a]} { set a 10 }
if {[string match -nocase near/* $a]} { set a [string range $a 5 end] }
lappend out $a
lappend out $b
}
return $out
}
proc do_near_test {tn tbl expr} {
set expr [fix_near_expr $expr]
# Create the MATCH expression from $expr
#
set match [lindex $expr 0]
if {[llength $match]>1} {
set match "\"$match\""
}
foreach {nNear phrase} [lrange $expr 1 end] {
if {[llength $phrase]>1} {
append match " NEAR/$nNear \"$phrase\""
} else {
append match " NEAR/$nNear $phrase"
}
}
# Calculate the expected results using [fts3_near_match]. The following
# loop populates the "hits" and "counts" arrays as follows:
#
# 1. For each document in the table that matches the NEAR expression,
# hits($docid) is set to 1. The set of docids that match the expression
# can therefore be found using [array names hits].
#
# 2. For each column of each document in the table, counts($docid,$iCol)
# is set to the -phrasecountvar output.
#
set res [list]
catch { array unset hits }
db eval "SELECT docid, * FROM $tbl" d {
set iCol 0
foreach col [lrange $d(*) 1 end] {
set docid $d(docid)
set hit [fts3_near_match $d($col) $expr -p counts($docid,$iCol)]
if {$hit} { set hits($docid) 1 }
incr iCol
}
}
set nPhrase [expr ([llength $expr]+1)/2]
set nCol $iCol
# This block populates the nHit and nDoc arrays. For each phrase/column
# in the query/table, array elements are set as follows:
#
# nHit($iPhrase,$iCol) - Total number of hits for phrase $iPhrase in
# column $iCol.
#
# nDoc($iPhrase,$iCol) - Number of documents with at least one hit for
# phrase $iPhrase in column $iCol.
#
for {set iPhrase 0} {$iPhrase < $nPhrase} {incr iPhrase} {
for {set iCol 0} {$iCol < $nCol} {incr iCol} {
set nHit($iPhrase,$iCol) 0
set nDoc($iPhrase,$iCol) 0
}
}
foreach key [array names counts] {
set iCol [lindex [split $key ,] 1]
set iPhrase 0
foreach c $counts($key) {
if {$c>0} { incr nHit($iPhrase,$iCol) 1 }
incr nDoc($iPhrase,$iCol) $c
incr iPhrase
}
}
# Set up the aMatchinfo array. For each document, set aMatchinfo($docid) to
# contain the output of matchinfo('x') for the document.
#
foreach docid [array names hits] {
set mi [list]
for {set iPhrase 0} {$iPhrase<$nPhrase} {incr iPhrase} {
for {set iCol 0} {$iCol<$nCol} {incr iCol} {
lappend mi [lindex $counts($docid,$iCol) $iPhrase]
lappend mi $nDoc($iPhrase,$iCol)
lappend mi $nHit($iPhrase,$iCol)
}
}
set aMatchinfo($docid) $mi
}
set matchinfo_asc [list]
foreach docid [lsort -integer -incr [array names aMatchinfo]] {
lappend matchinfo_asc $docid $aMatchinfo($docid)
}
set matchinfo_desc [list]
foreach docid [lsort -integer -decr [array names aMatchinfo]] {
lappend matchinfo_desc $docid $aMatchinfo($docid)
}
set title "(\"$match\" -> [llength [array names hits]] rows)"
do_execsql_test $tn$title.1 "
SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid ASC
" [lsort -integer -incr [array names hits]]
do_execsql_test $tn$title.2 "
SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid DESC
" [lsort -integer -decr [array names hits]]
do_execsql_test $tn$title.3 "
SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl
WHERE $tbl MATCH '$match' ORDER BY docid DESC
" $matchinfo_desc
do_execsql_test $tn$title.4 "
SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl
WHERE $tbl MATCH '$match' ORDER BY docid ASC
" $matchinfo_asc
}
do_test 2.1 {
execsql { CREATE VIRTUAL TABLE t1 USING fts3(a, b) }
for {set i 0} {$i<32} {incr i} {
set doc [list]
if {$i&0x01} {lappend doc one}
if {$i&0x02} {lappend doc two}
if {$i&0x04} {lappend doc three}
if {$i&0x08} {lappend doc four}
if {$i&0x10} {lappend doc five}
execsql { INSERT INTO t1 VALUES($doc, null) }
}
} {}
foreach {tn expr} {
1 {one}
2 {one NEAR/1 five}
3 {t*}
4 {t* NEAR/0 five}
5 {o* NEAR/1 f*}
6 {one NEAR five NEAR two NEAR four NEAR three}
} {
do_near_test 2.2.$tn t1 $expr
}
finish_test

View File

@ -374,11 +374,11 @@ proc fix_testname {varname} {
proc do_execsql_test {testname sql {result {}}} {
fix_testname testname
uplevel do_test $testname [list "execsql {$sql}"] [list [list {*}$result]]
uplevel do_test [list $testname] [list "execsql {$sql}"] [list [list {*}$result]]
}
proc do_catchsql_test {testname sql result} {
fix_testname testname
uplevel do_test $testname [list "catchsql {$sql}"] [list $result]
uplevel do_test [list $testname] [list "catchsql {$sql}"] [list $result]
}
proc do_eqp_test {name sql res} {
uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res]