1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-08 14:02:16 +03:00

Merge the latest trunk enhancements into the bedrock branch.

FossilOrigin-Name: c1f616ce802fbb9c3652f8cb43970e4bda18464e765f23fb5f96029721431092
This commit is contained in:
drh
2024-08-01 00:47:59 +00:00
294 changed files with 4683 additions and 2273 deletions

View File

@@ -456,6 +456,7 @@ TESTSRC += \
$(TOP)/ext/misc/remember.c \ $(TOP)/ext/misc/remember.c \
$(TOP)/ext/misc/series.c \ $(TOP)/ext/misc/series.c \
$(TOP)/ext/misc/spellfix.c \ $(TOP)/ext/misc/spellfix.c \
$(TOP)/ext/misc/stmtrand.c \
$(TOP)/ext/misc/totype.c \ $(TOP)/ext/misc/totype.c \
$(TOP)/ext/misc/unionvtab.c \ $(TOP)/ext/misc/unionvtab.c \
$(TOP)/ext/misc/wholenumber.c \ $(TOP)/ext/misc/wholenumber.c \

View File

@@ -1597,6 +1597,7 @@ TESTEXT = \
$(TOP)\ext\misc\remember.c \ $(TOP)\ext\misc\remember.c \
$(TOP)\ext\misc\series.c \ $(TOP)\ext\misc\series.c \
$(TOP)\ext\misc\spellfix.c \ $(TOP)\ext\misc\spellfix.c \
$(TOP)\ext\misc\stmtrand.c \
$(TOP)\ext\misc\totype.c \ $(TOP)\ext\misc\totype.c \
$(TOP)\ext\misc\unionvtab.c \ $(TOP)\ext\misc\unionvtab.c \
$(TOP)\ext\misc\wholenumber.c \ $(TOP)\ext\misc\wholenumber.c \

View File

@@ -1 +1 @@
3.46.0 3.47.0

View File

@@ -19,7 +19,7 @@ dnl to configure the system for the local environment.
# so that we create the export library with the dll. # so that we create the export library with the dll.
#----------------------------------------------------------------------- #-----------------------------------------------------------------------
AC_INIT([sqlite],[3.46.0]) AC_INIT([sqlite],[3.47.0])
#-------------------------------------------------------------------- #--------------------------------------------------------------------
# Call TEA_INIT as the first TEA_ macro to set up initial vars. # Call TEA_INIT as the first TEA_ macro to set up initial vars.

View File

@@ -708,4 +708,3 @@ TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib"
!message *** Link options '$(LINKERFLAGS)' !message *** Link options '$(LINKERFLAGS)'
!endif !endif

40
configure vendored
View File

@@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for sqlite 3.46.0. # Generated by GNU Autoconf 2.69 for sqlite 3.47.0.
# #
# #
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -726,8 +726,8 @@ MAKEFLAGS=
# Identity of this package. # Identity of this package.
PACKAGE_NAME='sqlite' PACKAGE_NAME='sqlite'
PACKAGE_TARNAME='sqlite' PACKAGE_TARNAME='sqlite'
PACKAGE_VERSION='3.46.0' PACKAGE_VERSION='3.47.0'
PACKAGE_STRING='sqlite 3.46.0' PACKAGE_STRING='sqlite 3.47.0'
PACKAGE_BUGREPORT='' PACKAGE_BUGREPORT=''
PACKAGE_URL='' PACKAGE_URL=''
@@ -1472,7 +1472,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing. # Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh. # This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF cat <<_ACEOF
\`configure' configures sqlite 3.46.0 to adapt to many kinds of systems. \`configure' configures sqlite 3.47.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]... Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1537,7 +1537,7 @@ fi
if test -n "$ac_init_help"; then if test -n "$ac_init_help"; then
case $ac_init_help in case $ac_init_help in
short | recursive ) echo "Configuration of sqlite 3.46.0:";; short | recursive ) echo "Configuration of sqlite 3.47.0:";;
esac esac
cat <<\_ACEOF cat <<\_ACEOF
@@ -1668,7 +1668,7 @@ fi
test -n "$ac_init_help" && exit $ac_status test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then if $ac_init_version; then
cat <<\_ACEOF cat <<\_ACEOF
sqlite configure 3.46.0 sqlite configure 3.47.0
generated by GNU Autoconf 2.69 generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc. Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2087,7 +2087,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake. running configure, to aid debugging if configure makes a mistake.
It was created by sqlite $as_me 3.46.0, which was It was created by sqlite $as_me 3.47.0, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@ $ $0 $@
@@ -10318,7 +10318,20 @@ USE_AMALGAMATION=1
# if not, then we fall back to plain tclsh. # if not, then we fall back to plain tclsh.
# TODO: try other versions before falling back? # TODO: try other versions before falling back?
# #
for ac_prog in tclsh8.7 tclsh8.6 tclsh8.5 tclsh if test x"${with_tcl}" != x; then
if test ! -r ${with_tcl}/tclConfig.sh; then
as_fn_error $? "no tclConfig.sh file found in --with-tcl: ${with_tcl}" "$LINENO" 5
else
. ${with_tcl}/tclConfig.sh
TCLSH_CMD=${TCL_EXEC_PREFIX}/bin/tclsh${TCL_VERSION}
if test ! -x ${TCLSH_CMD}; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot use tclsh at: ${TCLSH_CMD}" >&5
$as_echo "$as_me: WARNING: cannot use tclsh at: ${TCLSH_CMD}" >&2;}
TCLSH_CMD=none
fi
fi
else
for ac_prog in tclsh8.6 tclsh8.5 tclsh
do do
# Extract the first word of "$ac_prog", so it can be a program name with args. # Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2 set dummy $ac_prog; ac_word=$2
@@ -10361,6 +10374,7 @@ fi
done done
test -n "$TCLSH_CMD" || TCLSH_CMD="none" test -n "$TCLSH_CMD" || TCLSH_CMD="none"
fi
if test "$TCLSH_CMD" = "none"; then if test "$TCLSH_CMD" = "none"; then
# If we can't find a local tclsh, then building the amalgamation will fail. # If we can't find a local tclsh, then building the amalgamation will fail.
# We act as though --disable-amalgamation has been used. # We act as though --disable-amalgamation has been used.
@@ -10368,6 +10382,12 @@ if test "$TCLSH_CMD" = "none"; then
USE_AMALGAMATION=0 USE_AMALGAMATION=0
TCLSH_CMD="tclsh" TCLSH_CMD="tclsh"
fi fi
if test x"$TCLSH_CMD" = x; then
as_fn_error $? "cannot find a usable tclsh" "$LINENO" 5
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: using $TCLSH_CMD" >&5
$as_echo "using $TCLSH_CMD" >&6; }
fi
@@ -12481,7 +12501,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their # report actual input values of CONFIG_FILES etc. instead of their
# values after options handling. # values after options handling.
ac_log=" ac_log="
This file was extended by sqlite $as_me 3.46.0, which was This file was extended by sqlite $as_me 3.47.0, which was
generated by GNU Autoconf 2.69. Invocation command line was generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES CONFIG_FILES = $CONFIG_FILES
@@ -12547,7 +12567,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\ ac_cs_version="\\
sqlite config.status 3.46.0 sqlite config.status 3.47.0
configured by $0, generated by GNU Autoconf 2.69, configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\" with options \\"\$ac_cs_config\\"

View File

@@ -120,7 +120,20 @@ USE_AMALGAMATION=1
# if not, then we fall back to plain tclsh. # if not, then we fall back to plain tclsh.
# TODO: try other versions before falling back? # TODO: try other versions before falling back?
# #
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.7 tclsh8.6 tclsh8.5 tclsh], none) if test x"${with_tcl}" != x; then
if test ! -r ${with_tcl}/tclConfig.sh; then
AC_MSG_ERROR([no tclConfig.sh file found in --with-tcl: ${with_tcl}])
else
. ${with_tcl}/tclConfig.sh
TCLSH_CMD=${TCL_EXEC_PREFIX}/bin/tclsh${TCL_VERSION}
if test ! -x ${TCLSH_CMD}; then
AC_MSG_WARN([cannot use tclsh at: ${TCLSH_CMD}])
TCLSH_CMD=none
fi
fi
else
AC_CHECK_PROGS(TCLSH_CMD, [tclsh8.6 tclsh8.5 tclsh], none)
fi
if test "$TCLSH_CMD" = "none"; then if test "$TCLSH_CMD" = "none"; then
# If we can't find a local tclsh, then building the amalgamation will fail. # If we can't find a local tclsh, then building the amalgamation will fail.
# We act as though --disable-amalgamation has been used. # We act as though --disable-amalgamation has been used.
@@ -128,6 +141,11 @@ if test "$TCLSH_CMD" = "none"; then
USE_AMALGAMATION=0 USE_AMALGAMATION=0
TCLSH_CMD="tclsh" TCLSH_CMD="tclsh"
fi fi
if test x"$TCLSH_CMD" = x; then
AC_MSG_ERROR([cannot find a usable tclsh])
else
AC_MSG_RESULT([using $TCLSH_CMD])
fi
AC_SUBST(TCLSH_CMD) AC_SUBST(TCLSH_CMD)
AC_ARG_VAR([TCLLIBDIR], [Where to install tcl plugin]) AC_ARG_VAR([TCLLIBDIR], [Where to install tcl plugin])

View File

@@ -59,8 +59,16 @@ canonical source on a new Windows 11 PC, as of 2023-11-01:
<li> `nmake /f makefile.msc sqlite3.c` <li> `nmake /f makefile.msc sqlite3.c`
<li> `nmake /f makefile.msc devtest` <li> `nmake /f makefile.msc devtest`
<li> `nmake /f makefile.msc releasetest` <li> `nmake /f makefile.msc releasetest`
<li> `nmake /f makefile.msc sqlite3.exe`
</ul> </ul>
7. For a debugging build of the CLI, where the ".treetrace" and ".wheretrace"
commands work, add the DEBUG=3 argument to nmake. Like this:
<ul>
<li> `nmake /f makefile.msc DEBUG=3 clean sqlite3.exe`
</ul>
## 32-bit Builds ## 32-bit Builds
Doing a 32-bit build is just like doing a 64-bit build with the Doing a 32-bit build is just like doing a 64-bit build with the

View File

@@ -16,15 +16,7 @@
#include "sqlite3expert.h" #include "sqlite3expert.h"
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
#include "tclsqlite.h"
#if defined(INCLUDE_SQLITE_TCL_H)
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#ifndef SQLITE_OMIT_VIRTUALTABLE #ifndef SQLITE_OMIT_VIRTUALTABLE

View File

@@ -79,6 +79,8 @@ static int fts3termConnectMethod(
argc--; argc--;
} }
*ppVtab = 0;
/* The user should specify a single argument - the name of an fts3 table. */ /* The user should specify a single argument - the name of an fts3 table. */
if( argc!=4 ){ if( argc!=4 ){
sqlite3Fts3ErrMsg(pzErr, sqlite3Fts3ErrMsg(pzErr,
@@ -95,12 +97,17 @@ static int fts3termConnectMethod(
rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA); rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
nByte = sizeof(Fts3termTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; nByte = sizeof(Fts3termTable);
p = (Fts3termTable *)sqlite3_malloc64(nByte); p = (Fts3termTable *)sqlite3Fts3MallocZero(nByte);
if( !p ) return SQLITE_NOMEM; if( !p ) return SQLITE_NOMEM;
memset(p, 0, (size_t)nByte);
p->pFts3Tab = (Fts3Table *)&p[1]; p->pFts3Tab = (Fts3Table*)sqlite3Fts3MallocZero(
sizeof(Fts3Table) + nDb + nFts3 + 2
);
if( p->pFts3Tab==0 ){
sqlite3_free(p);
return SQLITE_NOMEM;
}
p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1];
p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1];
p->pFts3Tab->db = db; p->pFts3Tab->db = db;
@@ -130,6 +137,7 @@ static int fts3termDisconnectMethod(sqlite3_vtab *pVtab){
sqlite3_finalize(pFts3->aStmt[i]); sqlite3_finalize(pFts3->aStmt[i]);
} }
sqlite3_free(pFts3->zSegmentsTbl); sqlite3_free(pFts3->zSegmentsTbl);
sqlite3_free(pFts3);
sqlite3_free(p); sqlite3_free(p);
return SQLITE_OK; return SQLITE_OK;
} }

View File

@@ -18,14 +18,7 @@
** that the sqlite3_tokenizer_module.xLanguage() method is invoked correctly. ** that the sqlite3_tokenizer_module.xLanguage() method is invoked correctly.
*/ */
#if defined(INCLUDE_SQLITE_TCL_H) #include "tclsqlite.h"
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
@@ -167,7 +160,8 @@ static int SQLITE_TCLAPI fts3_near_match_cmd(
Tcl_Obj *pPhrasecount = 0; Tcl_Obj *pPhrasecount = 0;
Tcl_Obj **apExprToken; Tcl_Obj **apExprToken;
int nExprToken; Tcl_Size nExprToken;
Tcl_Size nn;
UNUSED_PARAMETER(clientData); UNUSED_PARAMETER(clientData);
@@ -201,23 +195,25 @@ static int SQLITE_TCLAPI fts3_near_match_cmd(
} }
} }
rc = Tcl_ListObjGetElements(interp, objv[1], &doc.nToken, &apDocToken); rc = Tcl_ListObjGetElements(interp, objv[1], &nn, &apDocToken);
doc.nToken = (int)nn;
if( rc!=TCL_OK ) goto near_match_out; if( rc!=TCL_OK ) goto near_match_out;
doc.aToken = (NearToken *)ckalloc(doc.nToken*sizeof(NearToken)); doc.aToken = (NearToken *)ckalloc(doc.nToken*sizeof(NearToken));
for(ii=0; ii<doc.nToken; ii++){ for(ii=0; ii<doc.nToken; ii++){
doc.aToken[ii].z = Tcl_GetStringFromObj(apDocToken[ii], &doc.aToken[ii].n); doc.aToken[ii].z = Tcl_GetStringFromObj(apDocToken[ii], &nn);
doc.aToken[ii].n = (int)nn;
} }
rc = Tcl_ListObjGetElements(interp, objv[2], &nExprToken, &apExprToken); rc = Tcl_ListObjGetElements(interp, objv[2], &nExprToken, &apExprToken);
if( rc!=TCL_OK ) goto near_match_out; if( rc!=TCL_OK ) goto near_match_out;
nPhrase = (nExprToken + 1) / 2; nPhrase = (int)(nExprToken + 1) / 2;
aPhrase = (NearPhrase *)ckalloc(nPhrase * sizeof(NearPhrase)); aPhrase = (NearPhrase *)ckalloc(nPhrase * sizeof(NearPhrase));
memset(aPhrase, 0, nPhrase * sizeof(NearPhrase)); memset(aPhrase, 0, nPhrase * sizeof(NearPhrase));
for(ii=0; ii<nPhrase; ii++){ for(ii=0; ii<nPhrase; ii++){
Tcl_Obj *pPhrase = apExprToken[ii*2]; Tcl_Obj *pPhrase = apExprToken[ii*2];
Tcl_Obj **apToken; Tcl_Obj **apToken;
int nToken; Tcl_Size nToken;
int jj; int jj;
rc = Tcl_ListObjGetElements(interp, pPhrase, &nToken, &apToken); rc = Tcl_ListObjGetElements(interp, pPhrase, &nToken, &apToken);
@@ -227,11 +223,12 @@ static int SQLITE_TCLAPI fts3_near_match_cmd(
rc = TCL_ERROR; rc = TCL_ERROR;
goto near_match_out; goto near_match_out;
} }
for(jj=0; jj<nToken; jj++){ for(jj=0; jj<(int)nToken; jj++){
NearToken *pT = &aPhrase[ii].aToken[jj]; NearToken *pT = &aPhrase[ii].aToken[jj];
pT->z = Tcl_GetStringFromObj(apToken[jj], &pT->n); pT->z = Tcl_GetStringFromObj(apToken[jj], &nn);
pT->n = (int)nn;
} }
aPhrase[ii].nToken = nToken; aPhrase[ii].nToken = (int)nToken;
} }
for(ii=1; ii<nPhrase; ii++){ for(ii=1; ii<nPhrase; ii++){
Tcl_Obj *pNear = apExprToken[2*ii-1]; Tcl_Obj *pNear = apExprToken[2*ii-1];

View File

@@ -226,11 +226,7 @@ int sqlite3Fts3InitTokenizer(
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
#if defined(INCLUDE_SQLITE_TCL_H) #include "tclsqlite.h"
# include "sqlite_tcl.h"
#else
# include "tcl.h"
#endif
#include <string.h> #include <string.h>
/* /*

View File

@@ -238,6 +238,10 @@ struct Fts5PhraseIter {
** (i.e. if it is a contentless table), then this API always iterates ** (i.e. if it is a contentless table), then this API always iterates
** through an empty set (all calls to xPhraseFirst() set iCol to -1). ** through an empty set (all calls to xPhraseFirst() set iCol to -1).
** **
** In all cases, matches are visited in (column ASC, offset ASC) order.
** i.e. all those in column 0, sorted by offset, followed by those in
** column 1, etc.
**
** xPhraseNext() ** xPhraseNext()
** See xPhraseFirst above. ** See xPhraseFirst above.
** **

View File

@@ -59,6 +59,22 @@ typedef sqlite3_uint64 u64;
# define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32)) # define LARGEST_INT64 (0xffffffff|(((i64)0x7fffffff)<<32))
# define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64) # define SMALLEST_INT64 (((i64)-1) - LARGEST_INT64)
/* The uptr type is an unsigned integer large enough to hold a pointer
*/
#if defined(HAVE_STDINT_H)
typedef uintptr_t uptr;
#elif SQLITE_PTRSIZE==4
typedef u32 uptr;
#else
typedef u64 uptr;
#endif
#ifdef SQLITE_4_BYTE_ALIGNED_MALLOC
# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&3)==0)
#else
# define EIGHT_BYTE_ALIGNMENT(X) ((((uptr)(X) - (uptr)0)&7)==0)
#endif
#endif #endif
/* Truncate very long tokens to this many bytes. Hard limit is /* Truncate very long tokens to this many bytes. Hard limit is
@@ -142,6 +158,15 @@ struct Fts5Colset {
*/ */
typedef struct Fts5Config Fts5Config; typedef struct Fts5Config Fts5Config;
typedef struct Fts5TokenizerConfig Fts5TokenizerConfig;
struct Fts5TokenizerConfig {
Fts5Tokenizer *pTok;
fts5_tokenizer *pTokApi;
const char **azArg;
int nArg;
int ePattern; /* FTS_PATTERN_XXX constant */
};
/* /*
** An instance of the following structure encodes all information that can ** An instance of the following structure encodes all information that can
@@ -184,6 +209,7 @@ typedef struct Fts5Config Fts5Config;
*/ */
struct Fts5Config { struct Fts5Config {
sqlite3 *db; /* Database handle */ sqlite3 *db; /* Database handle */
Fts5Global *pGlobal; /* Global fts5 object for handle db */
char *zDb; /* Database holding FTS index (e.g. "main") */ char *zDb; /* Database holding FTS index (e.g. "main") */
char *zName; /* Name of FTS index */ char *zName; /* Name of FTS index */
int nCol; /* Number of columns */ int nCol; /* Number of columns */
@@ -199,10 +225,8 @@ struct Fts5Config {
int bTokendata; /* "tokendata=" option value (dflt==0) */ int bTokendata; /* "tokendata=" option value (dflt==0) */
int eDetail; /* FTS5_DETAIL_XXX value */ int eDetail; /* FTS5_DETAIL_XXX value */
char *zContentExprlist; char *zContentExprlist;
Fts5Tokenizer *pTok; Fts5TokenizerConfig t;
fts5_tokenizer *pTokApi;
int bLock; /* True when table is preparing statement */ int bLock; /* True when table is preparing statement */
int ePattern; /* FTS_PATTERN_XXX constant */
/* Values loaded from the %_config table */ /* Values loaded from the %_config table */
int iVersion; /* fts5 file format 'version' */ int iVersion; /* fts5 file format 'version' */
@@ -597,13 +621,7 @@ struct Fts5Table {
Fts5Index *pIndex; /* Full-text index */ Fts5Index *pIndex; /* Full-text index */
}; };
int sqlite3Fts5GetTokenizer( int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig);
Fts5Global*,
const char **azArg,
int nArg,
Fts5Config*,
char **pzErr
);
Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64); Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64);
@@ -866,6 +884,7 @@ int sqlite3Fts5TokenizerPattern(
int (*xCreate)(void*, const char**, int, Fts5Tokenizer**), int (*xCreate)(void*, const char**, int, Fts5Tokenizer**),
Fts5Tokenizer *pTok Fts5Tokenizer *pTok
); );
int sqlite3Fts5TokenizerPreload(Fts5TokenizerConfig*);
/* /*
** End of interface to code in fts5_tokenizer.c. ** End of interface to code in fts5_tokenizer.c.
**************************************************************************/ **************************************************************************/

View File

@@ -234,7 +234,6 @@ static int fts5ConfigSetEnum(
** eventually free any such error message using sqlite3_free(). ** eventually free any such error message using sqlite3_free().
*/ */
static int fts5ConfigParseSpecial( static int fts5ConfigParseSpecial(
Fts5Global *pGlobal,
Fts5Config *pConfig, /* Configuration object to update */ Fts5Config *pConfig, /* Configuration object to update */
const char *zCmd, /* Special command to parse */ const char *zCmd, /* Special command to parse */
const char *zArg, /* Argument to parse */ const char *zArg, /* Argument to parse */
@@ -298,12 +297,11 @@ static int fts5ConfigParseSpecial(
if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){ if( sqlite3_strnicmp("tokenize", zCmd, nCmd)==0 ){
const char *p = (const char*)zArg; const char *p = (const char*)zArg;
sqlite3_int64 nArg = strlen(zArg) + 1; sqlite3_int64 nArg = strlen(zArg) + 1;
char **azArg = sqlite3Fts5MallocZero(&rc, sizeof(char*) * nArg); char **azArg = sqlite3Fts5MallocZero(&rc, (sizeof(char*) + 2) * nArg);
char *pDel = sqlite3Fts5MallocZero(&rc, nArg * 2);
char *pSpace = pDel;
if( azArg && pSpace ){ if( azArg ){
if( pConfig->pTok ){ char *pSpace = (char*)&azArg[nArg];
if( pConfig->t.azArg ){
*pzErr = sqlite3_mprintf("multiple tokenize=... directives"); *pzErr = sqlite3_mprintf("multiple tokenize=... directives");
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
}else{ }else{
@@ -326,16 +324,14 @@ static int fts5ConfigParseSpecial(
*pzErr = sqlite3_mprintf("parse error in tokenize directive"); *pzErr = sqlite3_mprintf("parse error in tokenize directive");
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
}else{ }else{
rc = sqlite3Fts5GetTokenizer(pGlobal, pConfig->t.azArg = (const char**)azArg;
(const char**)azArg, (int)nArg, pConfig, pConfig->t.nArg = nArg;
pzErr azArg = 0;
);
} }
} }
} }
sqlite3_free(azArg); sqlite3_free(azArg);
sqlite3_free(pDel);
return rc; return rc;
} }
@@ -412,16 +408,6 @@ static int fts5ConfigParseSpecial(
return SQLITE_ERROR; return SQLITE_ERROR;
} }
/*
** Allocate an instance of the default tokenizer ("simple") at
** Fts5Config.pTokenizer. Return SQLITE_OK if successful, or an SQLite error
** code if an error occurs.
*/
static int fts5ConfigDefaultTokenizer(Fts5Global *pGlobal, Fts5Config *pConfig){
assert( pConfig->pTok==0 && pConfig->pTokApi==0 );
return sqlite3Fts5GetTokenizer(pGlobal, 0, 0, pConfig, 0);
}
/* /*
** Gobble up the first bareword or quoted word from the input buffer zIn. ** Gobble up the first bareword or quoted word from the input buffer zIn.
** Return a pointer to the character immediately following the last in ** Return a pointer to the character immediately following the last in
@@ -554,6 +540,7 @@ int sqlite3Fts5ConfigParse(
*ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config)); *ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
if( pRet==0 ) return SQLITE_NOMEM; if( pRet==0 ) return SQLITE_NOMEM;
memset(pRet, 0, sizeof(Fts5Config)); memset(pRet, 0, sizeof(Fts5Config));
pRet->pGlobal = pGlobal;
pRet->db = db; pRet->db = db;
pRet->iCookie = -1; pRet->iCookie = -1;
@@ -602,7 +589,7 @@ int sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
}else{ }else{
if( bOption ){ if( bOption ){
rc = fts5ConfigParseSpecial(pGlobal, pRet, rc = fts5ConfigParseSpecial(pRet,
ALWAYS(zOne)?zOne:"", ALWAYS(zOne)?zOne:"",
zTwo?zTwo:"", zTwo?zTwo:"",
pzErr pzErr
@@ -640,13 +627,6 @@ int sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
} }
/* If a tokenizer= option was successfully parsed, the tokenizer has
** already been allocated. Otherwise, allocate an instance of the default
** tokenizer (unicode61) now. */
if( rc==SQLITE_OK && pRet->pTok==0 ){
rc = fts5ConfigDefaultTokenizer(pGlobal, pRet);
}
/* If no zContent option was specified, fill in the default values. */ /* If no zContent option was specified, fill in the default values. */
if( rc==SQLITE_OK && pRet->zContent==0 ){ if( rc==SQLITE_OK && pRet->zContent==0 ){
const char *zTail = 0; const char *zTail = 0;
@@ -688,9 +668,10 @@ int sqlite3Fts5ConfigParse(
void sqlite3Fts5ConfigFree(Fts5Config *pConfig){ void sqlite3Fts5ConfigFree(Fts5Config *pConfig){
if( pConfig ){ if( pConfig ){
int i; int i;
if( pConfig->pTok ){ if( pConfig->t.pTok ){
pConfig->pTokApi->xDelete(pConfig->pTok); pConfig->t.pTokApi->xDelete(pConfig->t.pTok);
} }
sqlite3_free((char*)pConfig->t.azArg);
sqlite3_free(pConfig->zDb); sqlite3_free(pConfig->zDb);
sqlite3_free(pConfig->zName); sqlite3_free(pConfig->zName);
for(i=0; i<pConfig->nCol; i++){ for(i=0; i<pConfig->nCol; i++){
@@ -765,11 +746,19 @@ int sqlite3Fts5Tokenize(
void *pCtx, /* Context passed to xToken() */ void *pCtx, /* Context passed to xToken() */
int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ int (*xToken)(void*, int, const char*, int, int, int) /* Callback */
){ ){
if( pText==0 ) return SQLITE_OK; int rc = SQLITE_OK;
return pConfig->pTokApi->xTokenize( if( pText ){
pConfig->pTok, pCtx, flags, pText, nText, xToken if( pConfig->t.pTok==0 ){
rc = sqlite3Fts5LoadTokenizer(pConfig);
}
if( rc==SQLITE_OK ){
rc = pConfig->t.pTokApi->xTokenize(
pConfig->t.pTok, pCtx, flags, pText, nText, xToken
); );
} }
}
return rc;
}
/* /*
** Argument pIn points to the first character in what is expected to be ** Argument pIn points to the first character in what is expected to be

View File

@@ -324,7 +324,11 @@ int sqlite3Fts5ExprNew(
} }
sqlite3_free(sParse.apPhrase); sqlite3_free(sParse.apPhrase);
if( 0==*pzErr ){
*pzErr = sParse.zErr; *pzErr = sParse.zErr;
}else{
sqlite3_free(sParse.zErr);
}
return sParse.rc; return sParse.rc;
} }
@@ -1871,6 +1875,7 @@ Fts5ExprPhrase *sqlite3Fts5ParseTerm(
}else if( sCtx.pPhrase->nTerm ){ }else if( sCtx.pPhrase->nTerm ){
sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix; sCtx.pPhrase->aTerm[sCtx.pPhrase->nTerm-1].bPrefix = (u8)bPrefix;
} }
assert( pParse->apPhrase!=0 );
pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase; pParse->apPhrase[pParse->nPhrase-1] = sCtx.pPhrase;
} }
@@ -1890,7 +1895,7 @@ int sqlite3Fts5ExprClonePhrase(
Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */ Fts5ExprPhrase *pOrig = 0; /* The phrase extracted from pExpr */
Fts5Expr *pNew = 0; /* Expression to return via *ppNew */ Fts5Expr *pNew = 0; /* Expression to return via *ppNew */
TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */ TokenCtx sCtx = {0,0,0}; /* Context object for fts5ParseTokenize */
if( iPhrase<0 || iPhrase>=pExpr->nPhrase ){ if( !pExpr || iPhrase<0 || iPhrase>=pExpr->nPhrase ){
rc = SQLITE_RANGE; rc = SQLITE_RANGE;
}else{ }else{
pOrig = pExpr->apExprPhrase[iPhrase]; pOrig = pExpr->apExprPhrase[iPhrase];
@@ -2465,6 +2470,8 @@ Fts5ExprNode *sqlite3Fts5ParseImplicitAnd(
); );
if( pRight->eType==FTS5_EOF ){ if( pRight->eType==FTS5_EOF ){
assert( pParse->apPhrase!=0 );
assert( pParse->nPhrase>0 );
assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] ); assert( pParse->apPhrase[pParse->nPhrase-1]==pRight->pNear->apPhrase[0] );
sqlite3Fts5ParseNodeFree(pRight); sqlite3Fts5ParseNodeFree(pRight);
pRet = pLeft; pRet = pLeft;

View File

@@ -831,11 +831,12 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
u8 *aOut = 0; /* Read blob data into this buffer */ u8 *aOut = 0; /* Read blob data into this buffer */
int nByte = sqlite3_blob_bytes(p->pReader); int nByte = sqlite3_blob_bytes(p->pReader);
sqlite3_int64 nAlloc = sizeof(Fts5Data) + nByte + FTS5_DATA_PADDING; int szData = (sizeof(Fts5Data) + 7) & ~7;
sqlite3_int64 nAlloc = szData + nByte + FTS5_DATA_PADDING;
pRet = (Fts5Data*)sqlite3_malloc64(nAlloc); pRet = (Fts5Data*)sqlite3_malloc64(nAlloc);
if( pRet ){ if( pRet ){
pRet->nn = nByte; pRet->nn = nByte;
aOut = pRet->p = (u8*)&pRet[1]; aOut = pRet->p = (u8*)pRet + szData;
}else{ }else{
rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
} }
@@ -858,6 +859,7 @@ static Fts5Data *fts5DataRead(Fts5Index *p, i64 iRowid){
} }
assert( (pRet==0)==(p->rc!=SQLITE_OK) ); assert( (pRet==0)==(p->rc!=SQLITE_OK) );
assert( pRet==0 || EIGHT_BYTE_ALIGNMENT( pRet->p ) );
return pRet; return pRet;
} }

View File

@@ -377,8 +377,12 @@ static int fts5InitVtab(
assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 ); assert( (rc==SQLITE_OK && *pzErr==0) || pConfig==0 );
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pConfig->pzErrmsg = pzErr;
pTab->p.pConfig = pConfig; pTab->p.pConfig = pConfig;
pTab->pGlobal = pGlobal; pTab->pGlobal = pGlobal;
if( bCreate || sqlite3Fts5TokenizerPreload(&pConfig->t) ){
rc = sqlite3Fts5LoadTokenizer(pConfig);
}
} }
/* Open the index sub-system */ /* Open the index sub-system */
@@ -400,11 +404,8 @@ static int fts5InitVtab(
/* Load the initial configuration */ /* Load the initial configuration */
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
assert( pConfig->pzErrmsg==0 );
pConfig->pzErrmsg = pzErr;
rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex); rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
sqlite3Fts5IndexRollback(pTab->p.pIndex); sqlite3Fts5IndexRollback(pTab->p.pIndex);
pConfig->pzErrmsg = 0;
} }
if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){ if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
@@ -414,6 +415,7 @@ static int fts5InitVtab(
rc = sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS); rc = sqlite3_vtab_config(db, SQLITE_VTAB_INNOCUOUS);
} }
if( pConfig ) pConfig->pzErrmsg = 0;
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
fts5FreeVtab(pTab); fts5FreeVtab(pTab);
pTab = 0; pTab = 0;
@@ -481,10 +483,10 @@ static int fts5UsePatternMatch(
){ ){
assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB ); assert( FTS5_PATTERN_GLOB==SQLITE_INDEX_CONSTRAINT_GLOB );
assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE ); assert( FTS5_PATTERN_LIKE==SQLITE_INDEX_CONSTRAINT_LIKE );
if( pConfig->ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){ if( pConfig->t.ePattern==FTS5_PATTERN_GLOB && p->op==FTS5_PATTERN_GLOB ){
return 1; return 1;
} }
if( pConfig->ePattern==FTS5_PATTERN_LIKE if( pConfig->t.ePattern==FTS5_PATTERN_LIKE
&& (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB) && (p->op==FTS5_PATTERN_LIKE || p->op==FTS5_PATTERN_GLOB)
){ ){
return 1; return 1;
@@ -531,10 +533,10 @@ static int fts5UsePatternMatch(
** This function ensures that there is at most one "r" or "=". And that if ** This function ensures that there is at most one "r" or "=". And that if
** there exists an "=" then there is no "<" or ">". ** there exists an "=" then there is no "<" or ">".
** **
** Costs are assigned as follows: ** If an unusable MATCH operator is present in the WHERE clause, then
** SQLITE_CONSTRAINT is returned.
** **
** a) If an unusable MATCH operator is present in the WHERE clause, the ** Costs are assigned as follows:
** cost is unconditionally set to 1e50 (a really big number).
** **
** a) If a MATCH operator is present, the cost depends on the other ** a) If a MATCH operator is present, the cost depends on the other
** constraints also present. As follows: ** constraints also present. As follows:
@@ -567,7 +569,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
int bSeenEq = 0; int bSeenEq = 0;
int bSeenGt = 0; int bSeenGt = 0;
int bSeenLt = 0; int bSeenLt = 0;
int bSeenMatch = 0; int nSeenMatch = 0;
int bSeenRank = 0; int bSeenRank = 0;
@@ -598,18 +600,15 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
/* A MATCH operator or equivalent */ /* A MATCH operator or equivalent */
if( p->usable==0 || iCol<0 ){ if( p->usable==0 || iCol<0 ){
/* As there exists an unusable MATCH constraint this is an /* As there exists an unusable MATCH constraint this is an
** unusable plan. Set a prohibitively high cost. */ ** unusable plan. Return SQLITE_CONSTRAINT. */
pInfo->estimatedCost = 1e50; return SQLITE_CONSTRAINT;
assert( iIdxStr < pInfo->nConstraint*6 + 1 );
idxStr[iIdxStr] = 0;
return SQLITE_OK;
}else{ }else{
if( iCol==nCol+1 ){ if( iCol==nCol+1 ){
if( bSeenRank ) continue; if( bSeenRank ) continue;
idxStr[iIdxStr++] = 'r'; idxStr[iIdxStr++] = 'r';
bSeenRank = 1; bSeenRank = 1;
}else if( iCol>=0 ){ }else if( iCol>=0 ){
bSeenMatch = 1; nSeenMatch++;
idxStr[iIdxStr++] = 'M'; idxStr[iIdxStr++] = 'M';
sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol); sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol);
idxStr += strlen(&idxStr[iIdxStr]); idxStr += strlen(&idxStr[iIdxStr]);
@@ -626,6 +625,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
idxStr += strlen(&idxStr[iIdxStr]); idxStr += strlen(&idxStr[iIdxStr]);
pInfo->aConstraintUsage[i].argvIndex = ++iCons; pInfo->aConstraintUsage[i].argvIndex = ++iCons;
assert( idxStr[iIdxStr]=='\0' ); assert( idxStr[iIdxStr]=='\0' );
nSeenMatch++;
}else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){ }else if( bSeenEq==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ && iCol<0 ){
idxStr[iIdxStr++] = '='; idxStr[iIdxStr++] = '=';
bSeenEq = 1; bSeenEq = 1;
@@ -662,7 +662,7 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
*/ */
if( pInfo->nOrderBy==1 ){ if( pInfo->nOrderBy==1 ){
int iSort = pInfo->aOrderBy[0].iColumn; int iSort = pInfo->aOrderBy[0].iColumn;
if( iSort==(pConfig->nCol+1) && bSeenMatch ){ if( iSort==(pConfig->nCol+1) && nSeenMatch>0 ){
idxFlags |= FTS5_BI_ORDER_RANK; idxFlags |= FTS5_BI_ORDER_RANK;
}else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){ }else if( iSort==-1 && (!pInfo->aOrderBy[0].desc || !pConfig->bTokendata) ){
idxFlags |= FTS5_BI_ORDER_ROWID; idxFlags |= FTS5_BI_ORDER_ROWID;
@@ -677,14 +677,17 @@ static int fts5BestIndexMethod(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){
/* Calculate the estimated cost based on the flags set in idxFlags. */ /* Calculate the estimated cost based on the flags set in idxFlags. */
if( bSeenEq ){ if( bSeenEq ){
pInfo->estimatedCost = bSeenMatch ? 100.0 : 10.0; pInfo->estimatedCost = nSeenMatch ? 1000.0 : 10.0;
if( bSeenMatch==0 ) fts5SetUniqueFlag(pInfo); if( nSeenMatch==0 ) fts5SetUniqueFlag(pInfo);
}else if( bSeenLt && bSeenGt ){ }else if( bSeenLt && bSeenGt ){
pInfo->estimatedCost = bSeenMatch ? 500.0 : 250000.0; pInfo->estimatedCost = nSeenMatch ? 5000.0 : 250000.0;
}else if( bSeenLt || bSeenGt ){ }else if( bSeenLt || bSeenGt ){
pInfo->estimatedCost = bSeenMatch ? 750.0 : 750000.0; pInfo->estimatedCost = nSeenMatch ? 7500.0 : 750000.0;
}else{ }else{
pInfo->estimatedCost = bSeenMatch ? 1000.0 : 1000000.0; pInfo->estimatedCost = nSeenMatch ? 10000.0 : 1000000.0;
}
for(i=1; i<nSeenMatch; i++){
pInfo->estimatedCost *= 0.4;
} }
pInfo->idxNum = idxFlags; pInfo->idxNum = idxFlags;
@@ -960,6 +963,7 @@ static int fts5NextMethod(sqlite3_vtab_cursor *pCursor){
} }
}else{ }else{
rc = SQLITE_OK; rc = SQLITE_OK;
CsrFlagSet(pCsr, FTS5CSR_REQUIRE_DOCSIZE);
} }
break; break;
} }
@@ -1213,6 +1217,18 @@ static i64 fts5GetRowidLimit(sqlite3_value *pVal, i64 iDefault){
return iDefault; return iDefault;
} }
/*
** Set the error message on the virtual table passed as the first argument.
*/
static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
va_list ap; /* ... printf arguments */
va_start(ap, zFormat);
sqlite3_free(p->p.base.zErrMsg);
p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
}
/* /*
** This is the xFilter interface for the virtual table. See ** This is the xFilter interface for the virtual table. See
** the virtual table xFilter method documentation for additional ** the virtual table xFilter method documentation for additional
@@ -1388,9 +1404,7 @@ static int fts5FilterMethod(
} }
} }
}else if( pConfig->zContent==0 ){ }else if( pConfig->zContent==0 ){
*pConfig->pzErrmsg = sqlite3_mprintf( fts5SetVtabError(pTab,"%s: table does not support scanning",pConfig->zName);
"%s: table does not support scanning", pConfig->zName
);
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
}else{ }else{
/* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup /* This is either a full-table scan (ePlan==FTS5_PLAN_SCAN) or a lookup
@@ -1433,9 +1447,13 @@ static i64 fts5CursorRowid(Fts5Cursor *pCsr){
assert( pCsr->ePlan==FTS5_PLAN_MATCH assert( pCsr->ePlan==FTS5_PLAN_MATCH
|| pCsr->ePlan==FTS5_PLAN_SORTED_MATCH || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH
|| pCsr->ePlan==FTS5_PLAN_SOURCE || pCsr->ePlan==FTS5_PLAN_SOURCE
|| pCsr->ePlan==FTS5_PLAN_SCAN
|| pCsr->ePlan==FTS5_PLAN_ROWID
); );
if( pCsr->pSorter ){ if( pCsr->pSorter ){
return pCsr->pSorter->iRowid; return pCsr->pSorter->iRowid;
}else if( pCsr->ePlan>=FTS5_PLAN_SCAN ){
return sqlite3_column_int64(pCsr->pStmt, 0);
}else{ }else{
return sqlite3Fts5ExprRowid(pCsr->pExpr); return sqlite3Fts5ExprRowid(pCsr->pExpr);
} }
@@ -1452,25 +1470,16 @@ static int fts5RowidMethod(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){
int ePlan = pCsr->ePlan; int ePlan = pCsr->ePlan;
assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 ); assert( CsrFlagTest(pCsr, FTS5CSR_EOF)==0 );
switch( ePlan ){ if( ePlan==FTS5_PLAN_SPECIAL ){
case FTS5_PLAN_SPECIAL:
*pRowid = 0; *pRowid = 0;
break; }else{
case FTS5_PLAN_SOURCE:
case FTS5_PLAN_MATCH:
case FTS5_PLAN_SORTED_MATCH:
*pRowid = fts5CursorRowid(pCsr); *pRowid = fts5CursorRowid(pCsr);
break;
default:
*pRowid = sqlite3_column_int64(pCsr->pStmt, 0);
break;
} }
return SQLITE_OK; return SQLITE_OK;
} }
/* /*
** If the cursor requires seeking (bSeekRequired flag is set), seek it. ** If the cursor requires seeking (bSeekRequired flag is set), seek it.
** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise. ** Return SQLITE_OK if no error occurs, or an SQLite error code otherwise.
@@ -1507,8 +1516,13 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
rc = sqlite3_reset(pCsr->pStmt); rc = sqlite3_reset(pCsr->pStmt);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = FTS5_CORRUPT; rc = FTS5_CORRUPT;
fts5SetVtabError((Fts5FullTable*)pTab,
"fts5: missing row %lld from content table %s",
fts5CursorRowid(pCsr),
pTab->pConfig->zContent
);
}else if( pTab->pConfig->pzErrmsg ){ }else if( pTab->pConfig->pzErrmsg ){
*pTab->pConfig->pzErrmsg = sqlite3_mprintf( fts5SetVtabError((Fts5FullTable*)pTab,
"%s", sqlite3_errmsg(pTab->pConfig->db) "%s", sqlite3_errmsg(pTab->pConfig->db)
); );
} }
@@ -1517,14 +1531,6 @@ static int fts5SeekCursor(Fts5Cursor *pCsr, int bErrormsg){
return rc; return rc;
} }
static void fts5SetVtabError(Fts5FullTable *p, const char *zFormat, ...){
va_list ap; /* ... printf arguments */
va_start(ap, zFormat);
assert( p->p.base.zErrMsg==0 );
p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap);
va_end(ap);
}
/* /*
** This function is called to handle an FTS INSERT command. In other words, ** This function is called to handle an FTS INSERT command. In other words,
** an INSERT statement of the form: ** an INSERT statement of the form:
@@ -1700,6 +1706,7 @@ static int fts5UpdateMethod(
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
}else{ }else{
rc = fts5SpecialDelete(pTab, apVal); rc = fts5SpecialDelete(pTab, apVal);
bUpdateOrDelete = 1;
} }
}else{ }else{
rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]); rc = fts5SpecialInsert(pTab, z, apVal[2 + pConfig->nCol + 1]);
@@ -2498,7 +2505,10 @@ static void fts5ApiCallback(
sqlite3_result_error(context, zErr, -1); sqlite3_result_error(context, zErr, -1);
sqlite3_free(zErr); sqlite3_free(zErr);
}else{ }else{
sqlite3_vtab *pTab = pCsr->base.pVtab;
fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]); fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
sqlite3_free(pTab->zErrMsg);
pTab->zErrMsg = 0;
} }
} }
@@ -2861,7 +2871,7 @@ static int fts5FindTokenizer(
return rc; return rc;
} }
int sqlite3Fts5GetTokenizer( int fts5GetTokenizer(
Fts5Global *pGlobal, Fts5Global *pGlobal,
const char **azArg, const char **azArg,
int nArg, int nArg,
@@ -2875,29 +2885,42 @@ int sqlite3Fts5GetTokenizer(
if( pMod==0 ){ if( pMod==0 ){
assert( nArg>0 ); assert( nArg>0 );
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
*pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]); if( pzErr ) *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]);
}else{ }else{
rc = pMod->x.xCreate( rc = pMod->x.xCreate(
pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->pTok pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok
); );
pConfig->pTokApi = &pMod->x; pConfig->t.pTokApi = &pMod->x;
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
if( pzErr ) *pzErr = sqlite3_mprintf("error in tokenizer constructor"); if( pzErr && rc!=SQLITE_NOMEM ){
*pzErr = sqlite3_mprintf("error in tokenizer constructor");
}
}else{ }else{
pConfig->ePattern = sqlite3Fts5TokenizerPattern( pConfig->t.ePattern = sqlite3Fts5TokenizerPattern(
pMod->x.xCreate, pConfig->pTok pMod->x.xCreate, pConfig->t.pTok
); );
} }
} }
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
pConfig->pTokApi = 0; pConfig->t.pTokApi = 0;
pConfig->pTok = 0; pConfig->t.pTok = 0;
} }
return rc; return rc;
} }
/*
** Attempt to instantiate the tokenizer.
*/
int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){
return fts5GetTokenizer(
pConfig->pGlobal, pConfig->t.azArg, pConfig->t.nArg,
pConfig, pConfig->pzErrmsg
);
}
static void fts5ModuleDestroy(void *pCtx){ static void fts5ModuleDestroy(void *pCtx){
Fts5TokenizerModule *pTok, *pNextTok; Fts5TokenizerModule *pTok, *pNextTok;
Fts5Auxiliary *pAux, *pNextAux; Fts5Auxiliary *pAux, *pNextAux;
@@ -2976,17 +2999,23 @@ static int fts5IntegrityMethod(
assert( pzErr!=0 && *pzErr==0 ); assert( pzErr!=0 && *pzErr==0 );
UNUSED_PARAM(isQuick); UNUSED_PARAM(isQuick);
assert( pTab->p.pConfig->pzErrmsg==0 );
pTab->p.pConfig->pzErrmsg = pzErr;
rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, 0); rc = sqlite3Fts5StorageIntegrity(pTab->pStorage, 0);
if( *pzErr==0 && rc!=SQLITE_OK ){
if( (rc&0xff)==SQLITE_CORRUPT ){ if( (rc&0xff)==SQLITE_CORRUPT ){
*pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s", *pzErr = sqlite3_mprintf("malformed inverted index for FTS5 table %s.%s",
zSchema, zTabname); zSchema, zTabname);
rc = (*pzErr) ? SQLITE_OK : SQLITE_NOMEM; rc = (*pzErr) ? SQLITE_OK : SQLITE_NOMEM;
}else if( rc!=SQLITE_OK ){ }else{
*pzErr = sqlite3_mprintf("unable to validate the inverted index for" *pzErr = sqlite3_mprintf("unable to validate the inverted index for"
" FTS5 table %s.%s: %s", " FTS5 table %s.%s: %s",
zSchema, zTabname, sqlite3_errstr(rc)); zSchema, zTabname, sqlite3_errstr(rc));
} }
}
sqlite3Fts5IndexCloseReader(pTab->p.pIndex); sqlite3Fts5IndexCloseReader(pTab->p.pIndex);
pTab->p.pConfig->pzErrmsg = 0;
return rc; return rc;
} }

View File

@@ -447,7 +447,7 @@ static int fts5StorageDeleteFromIndex(
zText, nText, (void*)&ctx, fts5StorageInsertCallback zText, nText, (void*)&ctx, fts5StorageInsertCallback
); );
p->aTotalSize[iCol-1] -= (i64)ctx.szCol; p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
if( p->aTotalSize[iCol-1]<0 ){ if( p->aTotalSize[iCol-1]<0 && rc==SQLITE_OK ){
rc = FTS5_CORRUPT; rc = FTS5_CORRUPT;
} }
} }

View File

@@ -14,14 +14,7 @@
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
#if defined(INCLUDE_SQLITE_TCL_H) #include "tclsqlite.h"
# include "sqlite_tcl.h"
#else
# include "tcl.h"
# ifndef SQLITE_TCLAPI
# define SQLITE_TCLAPI
# endif
#endif
#ifdef SQLITE_ENABLE_FTS5 #ifdef SQLITE_ENABLE_FTS5
@@ -297,12 +290,12 @@ static int SQLITE_TCLAPI xF5tApi(
break; break;
} }
CASE(3, "xTokenize") { CASE(3, "xTokenize") {
int nText; Tcl_Size nText;
char *zText = Tcl_GetStringFromObj(objv[2], &nText); char *zText = Tcl_GetStringFromObj(objv[2], &nText);
F5tFunction ctx; F5tFunction ctx;
ctx.interp = interp; ctx.interp = interp;
ctx.pScript = objv[3]; ctx.pScript = objv[3];
rc = p->pApi->xTokenize(p->pFts, zText, nText, &ctx, xTokenizeCb); rc = p->pApi->xTokenize(p->pFts, zText, (int)nText, &ctx, xTokenizeCb);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
Tcl_ResetResult(interp); Tcl_ResetResult(interp);
} }
@@ -605,15 +598,16 @@ static void xF5tFunction(
sqlite3_result_error(pCtx, Tcl_GetStringResult(p->interp), -1); sqlite3_result_error(pCtx, Tcl_GetStringResult(p->interp), -1);
}else{ }else{
Tcl_Obj *pVar = Tcl_GetObjResult(p->interp); Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
int n;
const char *zType = (pVar->typePtr ? pVar->typePtr->name : ""); const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
char c = zType[0]; char c = zType[0];
if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){ if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
/* Only return a BLOB type if the Tcl variable is a bytearray and /* Only return a BLOB type if the Tcl variable is a bytearray and
** has no string representation. */ ** has no string representation. */
unsigned char *data = Tcl_GetByteArrayFromObj(pVar, &n); Tcl_Size nn;
sqlite3_result_blob(pCtx, data, n, SQLITE_TRANSIENT); unsigned char *data = Tcl_GetByteArrayFromObj(pVar, &nn);
sqlite3_result_blob(pCtx, data, (int)nn, SQLITE_TRANSIENT);
}else if( c=='b' && strcmp(zType,"boolean")==0 ){ }else if( c=='b' && strcmp(zType,"boolean")==0 ){
int n;
Tcl_GetIntFromObj(0, pVar, &n); Tcl_GetIntFromObj(0, pVar, &n);
sqlite3_result_int(pCtx, n); sqlite3_result_int(pCtx, n);
}else if( c=='d' && strcmp(zType,"double")==0 ){ }else if( c=='d' && strcmp(zType,"double")==0 ){
@@ -626,8 +620,9 @@ static void xF5tFunction(
Tcl_GetWideIntFromObj(0, pVar, &v); Tcl_GetWideIntFromObj(0, pVar, &v);
sqlite3_result_int64(pCtx, v); sqlite3_result_int64(pCtx, v);
}else{ }else{
unsigned char *data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n); Tcl_Size nn;
sqlite3_result_text(pCtx, (char *)data, n, SQLITE_TRANSIENT); unsigned char *data = (unsigned char *)Tcl_GetStringFromObj(pVar, &nn);
sqlite3_result_text(pCtx, (char*)data, (int)nn, SQLITE_TRANSIENT);
} }
} }
} }
@@ -720,7 +715,7 @@ static int SQLITE_TCLAPI f5tTokenize(
Tcl_Obj *CONST objv[] Tcl_Obj *CONST objv[]
){ ){
char *zText; char *zText;
int nText; Tcl_Size nText;
sqlite3 *db = 0; sqlite3 *db = 0;
fts5_api *pApi = 0; fts5_api *pApi = 0;
Fts5Tokenizer *pTok = 0; Fts5Tokenizer *pTok = 0;
@@ -729,7 +724,7 @@ static int SQLITE_TCLAPI f5tTokenize(
void *pUserdata; void *pUserdata;
int rc; int rc;
int nArg; Tcl_Size nArg;
const char **azArg; const char **azArg;
F5tTokenizeCtx ctx; F5tTokenizeCtx ctx;
@@ -761,7 +756,7 @@ static int SQLITE_TCLAPI f5tTokenize(
return TCL_ERROR; return TCL_ERROR;
} }
rc = tokenizer.xCreate(pUserdata, &azArg[1], nArg-1, &pTok); rc = tokenizer.xCreate(pUserdata, &azArg[1], (int)(nArg-1), &pTok);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, "error in tokenizer.xCreate()", 0); Tcl_AppendResult(interp, "error in tokenizer.xCreate()", 0);
return TCL_ERROR; return TCL_ERROR;
@@ -773,7 +768,7 @@ static int SQLITE_TCLAPI f5tTokenize(
ctx.pRet = pRet; ctx.pRet = pRet;
ctx.zInput = zText; ctx.zInput = zText;
rc = tokenizer.xTokenize( rc = tokenizer.xTokenize(
pTok, (void*)&ctx, FTS5_TOKENIZE_DOCUMENT, zText, nText, xTokenizeCb2 pTok, (void*)&ctx, FTS5_TOKENIZE_DOCUMENT, zText,(int)nText, xTokenizeCb2
); );
tokenizer.xDelete(pTok); tokenizer.xDelete(pTok);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@@ -928,13 +923,13 @@ static int SQLITE_TCLAPI f5tTokenizerReturn(
F5tTokenizerContext *p = (F5tTokenizerContext*)clientData; F5tTokenizerContext *p = (F5tTokenizerContext*)clientData;
int iStart; int iStart;
int iEnd; int iEnd;
int nToken; Tcl_Size nToken;
int tflags = 0; int tflags = 0;
char *zToken; char *zToken;
int rc; int rc;
if( objc==5 ){ if( objc==5 ){
int nArg; Tcl_Size nArg;
char *zArg = Tcl_GetStringFromObj(objv[1], &nArg); char *zArg = Tcl_GetStringFromObj(objv[1], &nArg);
if( nArg<=10 && nArg>=2 && memcmp("-colocated", zArg, nArg)==0 ){ if( nArg<=10 && nArg>=2 && memcmp("-colocated", zArg, nArg)==0 ){
tflags |= FTS5_TOKEN_COLOCATED; tflags |= FTS5_TOKEN_COLOCATED;
@@ -959,7 +954,7 @@ static int SQLITE_TCLAPI f5tTokenizerReturn(
return TCL_ERROR; return TCL_ERROR;
} }
rc = p->xToken(p->pCtx, tflags, zToken, nToken, iStart, iEnd); rc = p->xToken(p->pCtx, tflags, zToken, (int)nToken, iStart, iEnd);
Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE);
return rc==SQLITE_OK ? TCL_OK : TCL_ERROR; return rc==SQLITE_OK ? TCL_OK : TCL_ERROR;
@@ -1083,7 +1078,7 @@ static int SQLITE_TCLAPI f5tTokenHash(
Tcl_Obj *CONST objv[] Tcl_Obj *CONST objv[]
){ ){
char *z; char *z;
int n; Tcl_Size n;
unsigned int iVal; unsigned int iVal;
int nSlot; int nSlot;
@@ -1096,7 +1091,7 @@ static int SQLITE_TCLAPI f5tTokenHash(
} }
z = Tcl_GetStringFromObj(objv[2], &n); z = Tcl_GetStringFromObj(objv[2], &n);
iVal = f5t_fts5HashKey(nSlot, z, n); iVal = f5t_fts5HashKey(nSlot, z, (int)n);
Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal)); Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal));
return TCL_OK; return TCL_OK;
} }

View File

@@ -1428,6 +1428,16 @@ int sqlite3Fts5TokenizerPattern(
return FTS5_PATTERN_NONE; return FTS5_PATTERN_NONE;
} }
/*
** Return true if the tokenizer described by p->azArg[] is the trigram
** tokenizer. This tokenizer needs to be loaded before xBestIndex is
** called for the first time in order to correctly handle LIKE/GLOB.
*/
int sqlite3Fts5TokenizerPreload(Fts5TokenizerConfig *p){
return (p->nArg>=1 && 0==sqlite3_stricmp(p->azArg[0], "trigram"));
}
/* /*
** Register all built-in tokenizers with FTS5. ** Register all built-in tokenizers with FTS5.
*/ */

View File

@@ -64,6 +64,7 @@ struct Fts5VocabCursor {
int nLeTerm; /* Size of zLeTerm in bytes */ int nLeTerm; /* Size of zLeTerm in bytes */
char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */ char *zLeTerm; /* (term <= $zLeTerm) paramater, or NULL */
int colUsed; /* Copy of sqlite3_index_info.colUsed */
/* These are used by 'col' tables only */ /* These are used by 'col' tables only */
int iCol; int iCol;
@@ -90,9 +91,11 @@ struct Fts5VocabCursor {
/* /*
** Bits for the mask used as the idxNum value by xBestIndex/xFilter. ** Bits for the mask used as the idxNum value by xBestIndex/xFilter.
*/ */
#define FTS5_VOCAB_TERM_EQ 0x01 #define FTS5_VOCAB_TERM_EQ 0x0100
#define FTS5_VOCAB_TERM_GE 0x02 #define FTS5_VOCAB_TERM_GE 0x0200
#define FTS5_VOCAB_TERM_LE 0x04 #define FTS5_VOCAB_TERM_LE 0x0400
#define FTS5_VOCAB_COLUSED_MASK 0xFF
/* /*
@@ -269,11 +272,13 @@ static int fts5VocabBestIndexMethod(
int iTermEq = -1; int iTermEq = -1;
int iTermGe = -1; int iTermGe = -1;
int iTermLe = -1; int iTermLe = -1;
int idxNum = 0; int idxNum = (int)pInfo->colUsed;
int nArg = 0; int nArg = 0;
UNUSED_PARAM(pUnused); UNUSED_PARAM(pUnused);
assert( (pInfo->colUsed & FTS5_VOCAB_COLUSED_MASK)==pInfo->colUsed );
for(i=0; i<pInfo->nConstraint; i++){ for(i=0; i<pInfo->nConstraint; i++){
struct sqlite3_index_constraint *p = &pInfo->aConstraint[i]; struct sqlite3_index_constraint *p = &pInfo->aConstraint[i];
if( p->usable==0 ) continue; if( p->usable==0 ) continue;
@@ -525,11 +530,21 @@ static int fts5VocabNextMethod(sqlite3_vtab_cursor *pCursor){
switch( pTab->eType ){ switch( pTab->eType ){
case FTS5_VOCAB_ROW: case FTS5_VOCAB_ROW:
if( eDetail==FTS5_DETAIL_FULL ){ /* Do not bother counting the number of instances if the "cnt"
while( 0==sqlite3Fts5PoslistNext64(pPos, nPos, &iOff, &iPos) ){ ** column is not being read (according to colUsed). */
if( eDetail==FTS5_DETAIL_FULL && (pCsr->colUsed & 0x04) ){
while( iPos<nPos ){
u32 ii;
fts5FastGetVarint32(pPos, iPos, ii);
if( ii==1 ){
/* New column in the position list */
fts5FastGetVarint32(pPos, iPos, ii);
}else{
/* An instance - increment pCsr->aCnt[] */
pCsr->aCnt[0]++; pCsr->aCnt[0]++;
} }
} }
}
pCsr->aDoc[0]++; pCsr->aDoc[0]++;
break; break;
@@ -625,6 +640,7 @@ static int fts5VocabFilterMethod(
if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++]; if( idxNum & FTS5_VOCAB_TERM_EQ ) pEq = apVal[iVal++];
if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++]; if( idxNum & FTS5_VOCAB_TERM_GE ) pGe = apVal[iVal++];
if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++]; if( idxNum & FTS5_VOCAB_TERM_LE ) pLe = apVal[iVal++];
pCsr->colUsed = (idxNum & FTS5_VOCAB_COLUSED_MASK);
if( pEq ){ if( pEq ){
zTerm = (const char *)sqlite3_value_text(pEq); zTerm = (const char *)sqlite3_value_text(pEq);

View File

@@ -114,6 +114,10 @@ proc fts5_test_rowcount {cmd} {
$cmd xRowCount $cmd xRowCount
} }
proc fts5_test_rowid {cmd} {
$cmd xRowid
}
proc test_queryphrase_cb {cnt cmd} { proc test_queryphrase_cb {cnt cmd} {
upvar $cnt L upvar $cnt L
for {set i 0} {$i < [$cmd xInstCount]} {incr i} { for {set i 0} {$i < [$cmd xInstCount]} {incr i} {
@@ -167,6 +171,7 @@ proc fts5_aux_test_functions {db} {
fts5_test_collist fts5_test_collist
fts5_test_tokenize fts5_test_tokenize
fts5_test_rowcount fts5_test_rowcount
fts5_test_rowid
fts5_test_all fts5_test_all
fts5_test_queryphrase fts5_test_queryphrase

View File

@@ -440,7 +440,7 @@ do_execsql_test 16.1 {
proc funk {} { proc funk {} {
db eval { UPDATE n1_config SET v=50 WHERE k='version' } db eval { UPDATE n1_config SET v=50 WHERE k='version' }
set fd [db incrblob main n1_data block 10] set fd [db incrblob main n1_data block 10]
fconfigure $fd -encoding binary -translation binary fconfigure $fd -translation binary
# puts -nonewline $fd "\x44\x45" # puts -nonewline $fd "\x44\x45"
close $fd close $fd
} }
@@ -453,7 +453,7 @@ db func funk funk
# statement no longer fails. # statement no longer fails.
# #
do_catchsql_test 16.2 { do_catchsql_test 16.2 {
SELECT funk(), bm25(n1), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d' SELECT funk(), format('%g',bm25(n1)), funk() FROM n1 WHERE n1 MATCH 'a+b+c+d'
} {0 {{} -1e-06 {}}} } {0 {{} -1e-06 {}}}
# {1 {SQL logic error}} # {1 {SQL logic error}}

View File

@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ab set testprefix fts5ab
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ac set testprefix fts5ac
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -18,7 +18,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ad set testprefix fts5ad
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ae set testprefix fts5ae
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -18,7 +18,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5af set testprefix fts5af
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ag set testprefix fts5ag
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ah set testprefix fts5ah
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ai set testprefix fts5ai
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -19,7 +19,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5aj set testprefix fts5aj
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ak set testprefix fts5ak
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5al set testprefix fts5al
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5alter set testprefix fts5alter
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5auto set testprefix fts5auto
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5aux set testprefix fts5aux
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return
@@ -377,4 +377,28 @@ do_catchsql_test 12.3.3 {
SELECT fts5_collist(t1, 1) FROM t1('one AND two'); SELECT fts5_collist(t1, 1) FROM t1('one AND two');
} {0 1} } {0 1}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 13.1 {
CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=ascii);
INSERT INTO t1 VALUES('a b c'), ('d e f');
PRAGMA integrity_check;
} {ok}
do_catchsql_test 13.2 {
SELECT highlight(t1, 0, '[', ']') FROM t1
} {0 {{a b c} {d e f}}}
do_execsql_test 13.3 {
PRAGMA writable_schema = 1;
UPDATE sqlite_schema SET sql = 'CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=blah)'
WHERE name = 't1';
}
db close
sqlite3 db test.db
do_catchsql_test 13.4 {
SELECT highlight(t1, 0, '[', ']') FROM t1
} {1 {SQL logic error}}
finish_test finish_test

View File

@@ -0,0 +1,71 @@
# 2024 June 24
#
# 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.
#
#***********************************************************************
#
# Tests focusing on the auxiliary function APIs.
#
source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5aux
# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 {
finish_test
return
}
do_execsql_test 1.0 {
CREATE VIRTUAL TABLE x1 USING fts5(a, b);
INSERT INTO x1 VALUES('a b', 'c d');
INSERT INTO x1 VALUES('d e', 'a b');
INSERT INTO x1 VALUES('a b', 'e f');
INSERT INTO x1 VALUES('d e', 'c d');
}
fts5_aux_test_functions db
do_execsql_test 1.1 {
SELECT fts5_test_all(x1) FROM x1 WHERE rowid=2
} [list [list {*}{
columnsize {2 2}
columntext {{d e} {a b}}
columntotalsize {8 8}
poslist {}
tokenize {{d e} {a b}}
rowcount 4
}]]
do_execsql_test 1.2 {
SELECT fts5_test_columntext(x1) FROM x1
} {
{{a b} {c d}}
{{d e} {a b}}
{{a b} {e f}}
{{d e} {c d}}
}
do_execsql_test 1.3 {
SELECT fts5_test_rowid(x1) FROM x1
} {
1 2 3 4
}
do_execsql_test 1.4 {
SELECT fts5_test_phrasecount(x1) FROM x1
} {
0 0 0 0
}
do_catchsql_test 1.5 {
SELECT fts5_queryphrase(x1, 0) FROM x1
} {1 SQLITE_RANGE}
do_execsql_test 1.6 {
SELECT fts5_test_rowcount(x1) FROM x1
} {4 4 4 4}
finish_test

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5auxdata set testprefix fts5auxdata
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5bigpl set testprefix fts5bigpl
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -79,7 +79,7 @@ foreach_detail_mode $::testprefix {
do_catchsql_test 4.1 { do_catchsql_test 4.1 {
SELECT * FROM t1 WHERE rowid MATCH 'a' SELECT * FROM t1 WHERE rowid MATCH 'a'
} {1 {unable to use function MATCH in the requested context}} } {1 {no query solution}}
} }
#------------------------------------------------------------------------- #-------------------------------------------------------------------------

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5columnsize set testprefix fts5columnsize
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5config set testprefix fts5config
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5content set testprefix fts5content
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return
@@ -328,4 +328,41 @@ do_execsql_test 8.3.2 { INSERT INTO t1(t1) VALUES('rebuild') }
do_execsql_test 8.3.3 { SELECT * FROM t1 WHERE rowid=1 } {one} do_execsql_test 8.3.3 { SELECT * FROM t1 WHERE rowid=1 } {one}
do_execsql_test 8.3.4 { SELECT rowid FROM t1('two') } {2} do_execsql_test 8.3.4 { SELECT rowid FROM t1('two') } {2}
#-------------------------------------------------------------------------
reset_db
do_execsql_test 9.1 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
INSERT INTO t1 VALUES(1, 'one two three');
INSERT INTO t1 VALUES(2, 'one two three');
CREATE VIRTUAL TABLE ft USING fts5(b, content=t1, content_rowid=a);
INSERT INTO ft(ft) VALUES('rebuild');
}
do_execsql_test 9.2 {
SELECT rowid, b FROM ft('two');
} {
1 {one two three}
2 {one two three}
}
do_execsql_test 9.3 {
DELETE FROM t1 WHERE a=2;
}
do_catchsql_test 9.4 {
SELECT rowid FROM ft('two');
} {0 {1 2}}
do_catchsql_test 9.5 {
SELECT * FROM ft('two');
} {1 {fts5: missing row 2 from content table 'main'.'t1'}}
fts5_aux_test_functions db
do_catchsql_test 9.6 {
SELECT rowid, fts5_columntext(ft, 0) FROM ft('two');
} {1 SQLITE_CORRUPT_VTAB}
finish_test finish_test

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5contentless set testprefix fts5contentless
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5contentless2 set testprefix fts5contentless2
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5contentless3 set testprefix fts5contentless3
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5contentless4 set testprefix fts5contentless4
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,11 +15,12 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5contentless5 set testprefix fts5contentless5
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return
} }
unset -nocomplain res
do_execsql_test 1.0 { do_execsql_test 1.0 {
CREATE VIRTUAL TABLE t1 USING fts5(a, b, c, content='', contentless_delete=1); CREATE VIRTUAL TABLE t1 USING fts5(a, b, c, content='', contentless_delete=1);

View File

@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt set testprefix fts5corrupt
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return
@@ -99,6 +99,6 @@ sqlite3_db_config db DEFENSIVE 0
do_catchsql_test 3.1 { do_catchsql_test 3.1 {
DELETE FROM t3_content WHERE rowid = 3; DELETE FROM t3_content WHERE rowid = 3;
SELECT * FROM t3 WHERE t3 MATCH 'o'; SELECT * FROM t3 WHERE t3 MATCH 'o';
} {1 {database disk image is malformed}} } {1 {fts5: missing row 3 from content table 'main'.'t3_content'}}
finish_test finish_test

View File

@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt2 set testprefix fts5corrupt2
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return
@@ -100,6 +100,7 @@ set lrowid [db one {SELECT max(rowid) FROM t1_data WHERE (rowid & $mask)=0}]
set nbyte [db one {SELECT length(block) FROM t1_data WHERE rowid=$lrowid}] set nbyte [db one {SELECT length(block) FROM t1_data WHERE rowid=$lrowid}]
set all [db eval {SELECT rowid FROM t1}] set all [db eval {SELECT rowid FROM t1}]
sqlite3_db_config db DEFENSIVE 0 sqlite3_db_config db DEFENSIVE 0
unset -nocomplain res
for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} { for {set i [expr $nbyte-2]} {$i>=0} {incr i -1} {
do_execsql_test 2.$i.1 { do_execsql_test 2.$i.1 {
BEGIN; BEGIN;
@@ -152,7 +153,7 @@ foreach {tn hdr} {
execsql BEGIN execsql BEGIN
set fd [db incrblob main x3_data block $rowid] set fd [db incrblob main x3_data block $rowid]
fconfigure $fd -encoding binary -translation binary fconfigure $fd -translation binary
set existing [read $fd [string length $hdr]] set existing [read $fd [string length $hdr]]
seek $fd 0 seek $fd 0
puts -nonewline $fd $hdr puts -nonewline $fd $hdr
@@ -238,7 +239,7 @@ foreach {tn hdr} {
execsql BEGIN execsql BEGIN
set fd [db incrblob main x5_data block $rowid] set fd [db incrblob main x5_data block $rowid]
fconfigure $fd -encoding binary -translation binary fconfigure $fd -translation binary
puts -nonewline $fd $hdr puts -nonewline $fd $hdr
close $fd close $fd

View File

@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt3 set testprefix fts5corrupt3
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return
@@ -4267,7 +4267,7 @@ do_test 35.0 {
do_catchsql_test 35.1 { do_catchsql_test 35.1 {
SELECT * FROM t1 WHERE t1 MATCH 'e*'; SELECT * FROM t1 WHERE t1 MATCH 'e*';
} {1 {database disk image is malformed}} } {1 {fts5: missing row 14 from content table 'main'.'t1_content'}}
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
reset_db reset_db

View File

@@ -14,7 +14,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt4 set testprefix fts5corrupt4
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt5 set testprefix fts5corrupt5
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt6 set testprefix fts5corrupt6
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -13,7 +13,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5corrupt7 set testprefix fts5corrupt7
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5dlidx set testprefix fts5dlidx
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5doclist set testprefix fts5doclist
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -16,7 +16,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5ea set testprefix fts5ea
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -13,7 +13,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5eb set testprefix fts5eb
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return
@@ -86,13 +86,13 @@ do_execsql_test 3.0 {
INSERT INTO e1 VALUES ('just a few words with a / inside'); INSERT INTO e1 VALUES ('just a few words with a / inside');
} }
do_execsql_test 3.1 { do_execsql_test 3.1 {
SELECT rowid, bm25(e1) FROM e1 WHERE e1 MATCH '"just"' ORDER BY rank; SELECT rowid, format('%g',bm25(e1)) FROM e1 WHERE e1 MATCH '"just"' ORDER BY rank;
} {1 -1e-06} } {1 -1e-06}
do_execsql_test 3.2 { do_execsql_test 3.2 {
SELECT rowid FROM e1 WHERE e1 MATCH '"/" OR "just"' SELECT rowid FROM e1 WHERE e1 MATCH '"/" OR "just"'
} 1 } 1
do_execsql_test 3.3 { do_execsql_test 3.3 {
SELECT rowid, bm25(e1) FROM e1 WHERE e1 MATCH '"/" OR "just"' ORDER BY rank; SELECT rowid, format('%g',bm25(e1)) FROM e1 WHERE e1 MATCH '"/" OR "just"' ORDER BY rank;
} {1 -1e-06} } {1 -1e-06}
do_execsql_test 3.4 " do_execsql_test 3.4 "

View File

@@ -16,7 +16,7 @@ source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl source $testdir/malloc_common.tcl
set testprefix fts5fault6 set testprefix fts5fault6
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -14,7 +14,7 @@ source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl source $testdir/malloc_common.tcl
set testprefix fts5faultG set testprefix fts5faultG
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -14,7 +14,7 @@ source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl source $testdir/malloc_common.tcl
set testprefix fts5faultG set testprefix fts5faultG
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -22,6 +22,7 @@ do_execsql_test 1.0 {
CREATE VIRTUAL TABLE x1 USING fts5(a, b); CREATE VIRTUAL TABLE x1 USING fts5(a, b);
} }
unset -nocomplain res
foreach {tn expr ok} { foreach {tn expr ok} {
1 {^abc} 1 1 {^abc} 1
2 {^abc + def} 1 2 {^abc + def} 1

View File

@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5full set testprefix fts5full
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5hash set testprefix fts5hash
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5integrity set testprefix fts5integrity
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return
@@ -153,6 +153,7 @@ do_execsql_test 5.3 {
INSERT INTO gg(gg) VALUES('integrity-check'); INSERT INTO gg(gg) VALUES('integrity-check');
} }
unset -nocomplain res
do_test 5.4.1 { do_test 5.4.1 {
set ok 0 set ok 0
for {set i 0} {$i < 10000} {incr i} { for {set i 0} {$i < 10000} {incr i} {
@@ -380,5 +381,32 @@ do_execsql_test 12.3 {
} {ok} } {ok}
#-------------------------------------------------------------------
reset_db
do_execsql_test 13.1 {
CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=ascii);
INSERT INTO t1 VALUES('a b c'), ('d e f');
PRAGMA integrity_check;
} {ok}
db close
sqlite3 db test.db
do_catchsql_test 13.2 {
PRAGMA integrity_check;
} {0 ok}
do_execsql_test 13.3 {
PRAGMA writable_schema = 1;
UPDATE sqlite_schema SET sql = 'CREATE VIRTUAL TABLE t1 USING fts5(a, tokenize=blah)'
WHERE name = 't1';
}
db close
sqlite3 db test.db
breakpoint
do_catchsql_test 13.4 {
PRAGMA integrity_check;
} {1 {SQL logic error}}
finish_test finish_test

View File

@@ -33,6 +33,7 @@ proc progress_handler {args} {
return 0 return 0
} }
unset -nocomplain res
foreach {tn sql} { foreach {tn sql} {
1 { INSERT INTO t1(rowid, a) VALUES(0, 'z z z z') } 1 { INSERT INTO t1(rowid, a) VALUES(0, 'z z z z') }
2 { COMMIT } 2 { COMMIT }
@@ -64,4 +65,3 @@ foreach {tn sql} {
} }
finish_test finish_test

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5lastrowid set testprefix fts5lastrowid
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -517,7 +517,7 @@ fts5_aux_test_functions db
do_execsql_test 15.3 { do_execsql_test 15.3 {
SELECT fts5_test_all(t1) FROM t1 LIMIT 1; SELECT fts5_test_all(t1) FROM t1 LIMIT 1;
} { } {
{columnsize {0 0} columntext {c d} columntotalsize {2 2} poslist {} tokenize {c d} rowcount 2} {columnsize {1 1} columntext {c d} columntotalsize {2 2} poslist {} tokenize {c d} rowcount 2}
} }
finish_test finish_test

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5merge set testprefix fts5merge
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -535,5 +535,36 @@ do_execsql_test 19.0 {
COMMIT; COMMIT;
} }
#-------------------------------------------------------------------------
reset_db
do_execsql_test 20.0 {
CREATE VIRTUAL TABLE x1 USING fts5(a);
INSERT INTO x1(rowid, a) VALUES
(1, 'a b c d'),
(2, 'x b c d'),
(3, 'x y z d'),
(4, 'a y c x');
}
do_execsql_test 20.1 {
SELECT rowid FROM x1 WHERE x1 MATCH 'a' AND x1 MATCH 'b';
} {1}
do_execsql_test 20.2 {
SELECT rowid FROM x1 WHERE x1 MATCH 'a' AND x1 MATCH 'y';
} {4}
do_execsql_test 20.3 {
SELECT rowid FROM x1 WHERE x1 MATCH 'a' OR x1 MATCH 'y';
} {1 4 3}
do_execsql_test 20.4 {
SELECT rowid FROM x1 WHERE x1 MATCH 'a' OR (x1 MATCH 'y' AND x1 MATCH 'd');
} {1 4 3}
do_execsql_test 20.5 {
SELECT rowid FROM x1 WHERE x1 MATCH 'z' OR (x1 MATCH 'a' AND x1 MATCH 'd');
} {3 1}
finish_test finish_test

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5near set testprefix fts5near
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -14,7 +14,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5optimize set testprefix fts5optimize
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5optimize2 set testprefix fts5optimize2
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5optimize2 set testprefix fts5optimize2
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5origintext set testprefix fts5origintext
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5origintext2 set testprefix fts5origintext2
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5origintext3 set testprefix fts5origintext3
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5origintext4 set testprefix fts5origintext4
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5origintext set testprefix fts5origintext
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5phrase set testprefix fts5phrase
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5plan set testprefix fts5plan
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -17,7 +17,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5porter set testprefix fts5porter
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -18,7 +18,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5porter2 set testprefix fts5porter2
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5prefix set testprefix fts5prefix
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5prefix2 set testprefix fts5prefix2
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5query set testprefix fts5query
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5rank set testprefix fts5rank
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -14,7 +14,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5rebuild set testprefix fts5rebuild
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5restart set testprefix fts5restart
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return
@@ -29,6 +29,7 @@ do_execsql_test 1.0 {
# Run the 'optimize' command. Check that it does not disturb ongoing # Run the 'optimize' command. Check that it does not disturb ongoing
# full-text queries. # full-text queries.
# #
unset -nocomplain lRowid
do_test 1.1 { do_test 1.1 {
for {set i 1} {$i < 1000} {incr i} { for {set i 1} {$i < 1000} {incr i} {
execsql { INSERT INTO f1 VALUES('a b c d e') } execsql { INSERT INTO f1 VALUES('a b c d e') }

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5rowid set testprefix fts5rowid
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -13,7 +13,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5savepoint set testprefix fts5savepoint
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -42,6 +42,22 @@ do_execsql_test 1.2 {
PRAGMA integrity_check; PRAGMA integrity_check;
} {ok} } {ok}
do_execsql_test 2.0 {
CREATE VIRTUAL TABLE xyz USING fts5 (
name,
content=''
);
INSERT INTO xyz(xyz, rank) VALUES('secure-delete', 1);
INSERT INTO xyz (rowid, name) VALUES(1, 'A');
INSERT INTO xyz (rowid, name) VALUES(2, 'A');
INSERT INTO xyz(xyz, rowid, name) VALUES('delete', 2, 'A');
}
do_execsql_test 2.1 {
pragma quick_check;
} {ok}

View File

@@ -16,7 +16,7 @@ source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl source $testdir/malloc_common.tcl
set testprefix fts5securefault set testprefix fts5securefault
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
return_if_no_fts5 return_if_no_fts5
do_execsql_test 1.0 { do_execsql_test 1.0 {

View File

@@ -13,7 +13,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5simple set testprefix fts5simple
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -13,7 +13,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5simple2 set testprefix fts5simple2
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -13,7 +13,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5simple3 set testprefix fts5simple3
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

View File

@@ -15,7 +15,7 @@
source [file join [file dirname [info script]] fts5_common.tcl] source [file join [file dirname [info script]] fts5_common.tcl]
set testprefix fts5synonym set testprefix fts5synonym
# If SQLITE_ENABLE_FTS5 is defined, omit this file. # If SQLITE_ENABLE_FTS5 is not defined, omit this file.
ifcapable !fts5 { ifcapable !fts5 {
finish_test finish_test
return return

Some files were not shown because too many files have changed in this diff Show More