** INSERT Directives" section of the documentation. It should be updated if
** more commands are added to this function.
*/
-static int fts5SpecialCommand(
+static int fts5SpecialInsert(
Fts5Table *pTab, /* Fts5 table object */
sqlite3_value *pCmd, /* Value inserted into special column */
sqlite3_value *pVal /* Value inserted into rowid column */
rc = sqlite3Fts5StorageIntegrity(pTab->pStorage);
}else{
rc = sqlite3Fts5ConfigSetValue(pTab->pConfig, z, pVal, &bError);
- if( rc==SQLITE_OK && bError ){
- rc = SQLITE_ERROR;
- }else{
- rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, z, pVal);
+ if( rc==SQLITE_OK ){
+ if( bError ){
+ rc = SQLITE_ERROR;
+ }else{
+ rc = sqlite3Fts5StorageConfigValue(pTab->pStorage, z, pVal);
+ }
}
}
return rc;
assert( nArg==1 || nArg==(2 + pConfig->nCol + 2) );
if( nArg>1 && SQLITE_NULL!=sqlite3_value_type(apVal[2 + pConfig->nCol]) ){
- return fts5SpecialCommand(pTab,
+ return fts5SpecialInsert(pTab,
apVal[2 + pConfig->nCol], apVal[2 + pConfig->nCol + 1]
);
}
char buf[8];
assert( nArg==0 );
assert( sizeof(buf)>=sizeof(pGlobal) );
- memcpy(buf, pGlobal, sizeof(pGlobal));
+ memcpy(buf, (void*)&pGlobal, sizeof(pGlobal));
sqlite3_result_blob(pCtx, buf, sizeof(pGlobal), SQLITE_TRANSIENT);
}
int iCookie; /* Incremented when %_config is modified */
int pgsz; /* Approximate page size used in %_data */
int nAutomerge; /* 'automerge' setting */
+ char *zRank; /* Name of rank function */
+ char *zRankArgs; /* Arguments to rank function */
};
int sqlite3Fts5ConfigParse(
}
sqlite3_free(pConfig->azCol);
sqlite3_free(pConfig->aPrefix);
+ sqlite3_free(pConfig->zRank);
+ sqlite3_free(pConfig->zRankArgs);
sqlite3_free(pConfig);
}
}
return pConfig->pTokApi->xTokenize(pConfig->pTok, pCtx, pText, nText, xToken);
}
+/*
+** Argument pIn points to a character that is part of a nul-terminated
+** string. Return a pointer to the first character following *pIn in
+** the string that is not a white-space character.
+*/
+static const char *fts5ConfigSkipWhitespace(const char *pIn){
+ const char *p = pIn;
+ if( p ){
+ while( *p==' ' ){ p++; }
+ }
+ return p;
+}
+
+/*
+** Argument pIn points to a character that is part of a nul-terminated
+** string. Return a pointer to the first character following *pIn in
+** the string that is not a "bareword" character.
+*/
+static const char *fts5ConfigSkipBareword(const char *pIn){
+ const char *p = pIn;
+ while( *p && *p!=' ' && *p!=':' && *p!='!' && *p!='@'
+ && *p!='#' && *p!='$' && *p!='%' && *p!='^' && *p!='&'
+ && *p!='*' && *p!='(' && *p!=')'
+ ){
+ p++;
+ }
+ if( p==pIn ) p = 0;
+ return p;
+}
+
+static int fts5_isdigit(char a){
+ return (a>='0' && a<='9');
+}
+
+
+
+static const char *fts5ConfigSkipLiteral(const char *pIn){
+ const char *p = pIn;
+ if( p ){
+ switch( *p ){
+ case 'n': case 'N':
+ if( sqlite3_strnicmp("null", p, 4)==0 ){
+ p = &p[4];
+ }else{
+ p = 0;
+ }
+ break;
+
+ case 'x': case 'X':
+ p++;
+ if( *p=='\'' ){
+ p++;
+ while( (*p>='a' && *p<='f')
+ || (*p>='A' && *p<='F')
+ || (*p>='0' && *p<='9')
+ ){
+ p++;
+ }
+ if( *p=='\'' && 0==((p-pIn)%2) ){
+ p++;
+ }else{
+ p = 0;
+ }
+ }else{
+ p = 0;
+ }
+ break;
+
+ case '\'':
+ p++;
+ while( p ){
+ if( *p=='\'' ){
+ p++;
+ if( *p!='\'' ) break;
+ }
+ p++;
+ if( *p==0 ) p = 0;
+ }
+ break;
+
+ default:
+ /* maybe a number */
+ if( *p=='+' || *p=='-' ) p++;
+ while( fts5_isdigit(*p) ) p++;
+
+ /* At this point, if the literal was an integer, the parse is
+ ** finished. Or, if it is a floating point value, it may continue
+ ** with either a decimal point or an 'E' character. */
+ if( *p=='.' && fts5_isdigit(p[1]) ){
+ p += 2;
+ while( fts5_isdigit(*p) ) p++;
+ }
+
+ break;
+ }
+ }
+
+ return p;
+}
+
+/*
+** Argument pIn points to the first character in what is expected to be
+** a comma-separated list of SQL literals followed by a ')' character.
+** If it actually is this, return a pointer to the ')'. Otherwise, return
+** NULL to indicate a parse error.
+*/
+static const char *fts5ConfigSkipArgs(const char *pIn){
+ const char *p = pIn;
+
+ while( 1 ){
+ p = fts5ConfigSkipWhitespace(p);
+ p = fts5ConfigSkipLiteral(p);
+ p = fts5ConfigSkipWhitespace(p);
+ if( p==0 || *p==')' ) break;
+ if( *p!=',' ){
+ p = 0;
+ break;
+ }
+ p++;
+ }
+
+ return p;
+}
+
+/*
+** Parameter zIn contains a rank() function specification. The format of
+** this is:
+**
+** + Bareword (function name)
+** + Open parenthesis - "("
+** + Zero or more SQL literals in a comma separated list
+** + Close parenthesis - ")"
+*/
+static int fts5ConfigParseRank(
+ const char *zIn, /* Input string */
+ char **pzRank, /* OUT: Rank function name */
+ char **pzRankArgs /* OUT: Rank function arguments */
+){
+ const char *p = zIn;
+ const char *pRank;
+ char *zRank = 0;
+ char *zRankArgs = 0;
+ int rc = SQLITE_OK;
+
+ *pzRank = 0;
+ *pzRankArgs = 0;
+
+ p = fts5ConfigSkipWhitespace(p);
+ pRank = p;
+ p = fts5ConfigSkipBareword(p);
+
+ if( p ){
+ zRank = sqlite3Fts5MallocZero(&rc, 1 + p - pRank);
+ if( zRank ) memcpy(zRank, pRank, p-pRank);
+ }else{
+ rc = SQLITE_ERROR;
+ }
+
+ if( rc==SQLITE_OK ){
+ p = fts5ConfigSkipWhitespace(p);
+ if( *p!='(' ) rc = SQLITE_ERROR;
+ p++;
+ }
+ if( rc==SQLITE_OK ){
+ const char *pArgs = p;
+ p = fts5ConfigSkipArgs(p);
+ if( p==0 ){
+ rc = SQLITE_ERROR;
+ }else{
+ zRankArgs = sqlite3Fts5MallocZero(&rc, 1 + p - pArgs);
+ if( zRankArgs ) memcpy(zRankArgs, pArgs, p-pArgs);
+ }
+ }
+
+ if( rc!=SQLITE_OK ){
+ sqlite3_free(zRank);
+ assert( zRankArgs==0 );
+ }else{
+ *pzRank = zRank;
+ *pzRankArgs = zRankArgs;
+ }
+ return rc;
+}
+
int sqlite3Fts5ConfigSetValue(
Fts5Config *pConfig,
const char *zKey,
}
else if( 0==sqlite3_stricmp(zKey, "rank") ){
- // todo
+ const char *zIn = (const char*)sqlite3_value_text(pVal);
+ char *zRank;
+ char *zRankArgs;
+ rc = fts5ConfigParseRank(zIn, &zRank, &zRankArgs);
+ if( rc==SQLITE_OK ){
+ sqlite3_free(pConfig->zRank);
+ sqlite3_free(pConfig->zRankArgs);
+ pConfig->zRank = zRank;
+ pConfig->zRankArgs = zRankArgs;
+ }else if( rc==SQLITE_ERROR ){
+ rc = SQLITE_OK;
+ if( pbBadkey ) *pbBadkey = 1;
+ }
}else{
if( pbBadkey ) *pbBadkey = 1;
}
--- /dev/null
+/*
+** 2014 Dec 01
+**
+** 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.
+**
+******************************************************************************
+**
+*/
+
+
+#include "fts5.h"
+#include <tcl.h>
+#include <string.h>
+#include <assert.h>
+
+/*************************************************************************
+** This is a copy of the first part of the SqliteDb structure in
+** tclsqlite.c. We need it here so that the get_sqlite_pointer routine
+** can extract the sqlite3* pointer from an existing Tcl SQLite
+** connection.
+*/
+struct SqliteDb {
+ sqlite3 *db;
+};
+
+/*
+** Decode a pointer to an sqlite3 object.
+*/
+static int f5tDbPointer(Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3 **ppDb){
+ struct SqliteDb *p;
+ Tcl_CmdInfo cmdInfo;
+ char *z = Tcl_GetString(pObj);
+ if( Tcl_GetCommandInfo(interp, z, &cmdInfo) ){
+ p = (struct SqliteDb*)cmdInfo.objClientData;
+ *ppDb = p->db;
+ return TCL_OK;
+ }
+ return TCL_ERROR;
+}
+/* End of code that accesses the SqliteDb struct.
+**************************************************************************/
+
+typedef struct F5tFunction F5tFunction;
+struct F5tFunction {
+ Tcl_Interp *interp;
+ Tcl_Obj *pScript;
+};
+
+typedef struct F5tApi F5tApi;
+struct F5tApi {
+ const Fts5ExtensionApi *pApi;
+ Fts5Context *pFts;
+};
+
+/*
+** api sub-command...
+**
+** Description...
+*/
+static int xF5tApi(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ struct Sub {
+ const char *zName;
+ int nArg;
+ const char *zMsg;
+ } aSub[] = {
+ { "xRowid", 0, "" },
+ { "xInstCount", 0, "" },
+ { "xInst", 1, "IDX" },
+ { "xColumnText", 1, "COL" },
+ { "xColumnSize", 1, "COL" },
+ };
+ int rc;
+ int iSub = 0;
+ F5tApi *p = (F5tApi*)clientData;
+
+ if( objc<2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "SUB-COMMAND");
+ return TCL_ERROR;
+ }
+
+ rc = Tcl_GetIndexFromObjStruct(
+ interp, objv[1], aSub, sizeof(aSub[0]), "SUB-COMMAND", 0, &iSub
+ );
+ if( rc!=TCL_OK ) return rc;
+ if( aSub[iSub].nArg!=objc-2 ){
+ Tcl_WrongNumArgs(interp, 1, objv, aSub[iSub].zMsg);
+ return TCL_ERROR;
+ }
+
+ switch( iSub ){
+ case 0: { /* xRowid */
+ sqlite3_int64 iRowid = p->pApi->xRowid(p->pFts);
+ Tcl_SetObjResult(interp, Tcl_NewWideIntObj(iRowid));
+ break;
+ }
+
+ case 1: { /* xInstCount */
+ int nInst;
+ rc = p->pApi->xInstCount(p->pFts, &nInst);
+ if( rc==SQLITE_OK ){
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(nInst));
+ }
+ break;
+ }
+
+ case 2: { /* xInst */
+ int iIdx, ip, ic, io;
+ if( Tcl_GetIntFromObj(interp, objv[2], &iIdx) ){
+ return TCL_ERROR;
+ }
+ rc = p->pApi->xInst(p->pFts, iIdx, &ip, &ic, &io);
+ if( rc==SQLITE_OK ){
+ Tcl_Obj *pList = Tcl_NewObj();
+ Tcl_ListObjAppendElement(interp, pList, Tcl_NewIntObj(ip));
+ Tcl_ListObjAppendElement(interp, pList, Tcl_NewIntObj(ic));
+ Tcl_ListObjAppendElement(interp, pList, Tcl_NewIntObj(io));
+ Tcl_SetObjResult(interp, pList);
+ }
+ break;
+ }
+
+ case 3: { /* xColumnText */
+ const char *z = 0;
+ int n = 0;
+ int iCol;
+ if( Tcl_GetIntFromObj(interp, objv[2], &iCol) ){
+ return TCL_ERROR;
+ }
+ rc = p->pApi->xColumnText(p->pFts, iCol, &z, &n);
+ if( rc==SQLITE_OK ){
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(z, n));
+ }
+ break;
+ }
+
+ case 4: { /* xColumnSize */
+ int n = 0;
+ int iCol;
+ if( Tcl_GetIntFromObj(interp, objv[2], &iCol) ){
+ return TCL_ERROR;
+ }
+ rc = p->pApi->xColumnSize(p->pFts, iCol, &n);
+ if( rc==SQLITE_OK ){
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(n));
+ }
+ break;
+ }
+
+ default:
+ assert( 0 );
+ break;
+ }
+
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, "error in api call", 0);
+ return TCL_ERROR;
+ }
+
+ return TCL_OK;
+}
+
+static void xF5tFunction(
+ const Fts5ExtensionApi *pApi, /* API offered by current FTS version */
+ Fts5Context *pFts, /* First arg to pass to pApi functions */
+ sqlite3_context *pCtx, /* Context for returning result/error */
+ int nVal, /* Number of values in apVal[] array */
+ sqlite3_value **apVal /* Array of trailing arguments */
+){
+ F5tFunction *p = (F5tFunction*)pApi->xUserData(pFts);
+ Tcl_Obj *pEval; /* Script to evaluate */
+ int i;
+ int rc;
+
+ static sqlite3_int64 iCmd = 0;
+ char zCmd[64];
+ F5tApi sApi;
+ sApi.pApi = pApi;
+ sApi.pFts = pFts;
+
+ sprintf(zCmd, "f5t_%lld", iCmd++);
+ Tcl_CreateObjCommand(p->interp, zCmd, xF5tApi, &sApi, 0);
+ pEval = Tcl_DuplicateObj(p->pScript);
+ Tcl_IncrRefCount(pEval);
+ Tcl_ListObjAppendElement(p->interp, pEval, Tcl_NewStringObj(zCmd, -1));
+
+ for(i=0; i<nVal; i++){
+ Tcl_Obj *pObj = 0;
+ switch( sqlite3_value_type(apVal[i]) ){
+ case SQLITE_TEXT:
+ pObj = Tcl_NewStringObj((const char*)sqlite3_value_text(apVal[i]), -1);
+ break;
+ case SQLITE_BLOB:
+ pObj = Tcl_NewByteArrayObj(
+ sqlite3_value_blob(apVal[i]), sqlite3_value_bytes(apVal[i])
+ );
+ break;
+ case SQLITE_INTEGER:
+ pObj = Tcl_NewWideIntObj(sqlite3_value_int64(apVal[i]));
+ break;
+ case SQLITE_FLOAT:
+ pObj = Tcl_NewDoubleObj(sqlite3_value_double(apVal[i]));
+ break;
+ default:
+ pObj = Tcl_NewObj();
+ break;
+ }
+ Tcl_ListObjAppendElement(p->interp, pEval, pObj);
+ }
+
+ rc = Tcl_EvalObjEx(p->interp, pEval, TCL_GLOBAL_ONLY);
+ Tcl_DecrRefCount(pEval);
+ Tcl_DeleteCommand(p->interp, zCmd);
+
+ if( rc!=TCL_OK ){
+ sqlite3_result_error(pCtx, Tcl_GetStringResult(p->interp), -1);
+ }else{
+ Tcl_Obj *pVar = Tcl_GetObjResult(p->interp);
+ int n;
+ const char *zType = (pVar->typePtr ? pVar->typePtr->name : "");
+ char c = zType[0];
+ if( c=='b' && strcmp(zType,"bytearray")==0 && pVar->bytes==0 ){
+ /* Only return a BLOB type if the Tcl variable is a bytearray and
+ ** has no string representation. */
+ unsigned char *data = Tcl_GetByteArrayFromObj(pVar, &n);
+ sqlite3_result_blob(pCtx, data, n, SQLITE_TRANSIENT);
+ }else if( c=='b' && strcmp(zType,"boolean")==0 ){
+ Tcl_GetIntFromObj(0, pVar, &n);
+ sqlite3_result_int(pCtx, n);
+ }else if( c=='d' && strcmp(zType,"double")==0 ){
+ double r;
+ Tcl_GetDoubleFromObj(0, pVar, &r);
+ sqlite3_result_double(pCtx, r);
+ }else if( (c=='w' && strcmp(zType,"wideInt")==0) ||
+ (c=='i' && strcmp(zType,"int")==0) ){
+ Tcl_WideInt v;
+ Tcl_GetWideIntFromObj(0, pVar, &v);
+ sqlite3_result_int64(pCtx, v);
+ }else{
+ unsigned char *data = (unsigned char *)Tcl_GetStringFromObj(pVar, &n);
+ sqlite3_result_text(pCtx, (char *)data, n, SQLITE_TRANSIENT);
+ }
+ }
+}
+
+static void xF5tDestroy(void *pCtx){
+ F5tFunction *p = (F5tFunction*)pCtx;
+ Tcl_DecrRefCount(p->pScript);
+ ckfree(p);
+}
+
+/*
+** sqlite3_fts5_create_function DB NAME SCRIPT
+**
+** Description...
+*/
+static int f5tCreateFunction(
+ void * clientData,
+ Tcl_Interp *interp,
+ int objc,
+ Tcl_Obj *CONST objv[]
+){
+ char *zName;
+ Tcl_Obj *pScript;
+ sqlite3 *db = 0;
+ sqlite3_stmt *pStmt = 0;
+ fts5_api *pApi = 0;
+ F5tFunction *pCtx = 0;
+ int rc;
+
+ if( objc!=4 ){
+ Tcl_WrongNumArgs(interp, 1, objv, "DB NAME SCRIPT");
+ return TCL_ERROR;
+ }
+ if( f5tDbPointer(interp, objv[1], &db) ){
+ return TCL_ERROR;
+ }
+ zName = Tcl_GetString(objv[2]);
+ pScript = objv[3];
+
+ rc = sqlite3_prepare_v2(db, "SELECT fts5()", -1, &pStmt, 0);
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
+ return TCL_ERROR;
+ }
+
+ if( SQLITE_ROW==sqlite3_step(pStmt) ){
+ const void *pPtr = sqlite3_column_blob(pStmt, 0);
+ memcpy((void*)&pApi, pPtr, sizeof(pApi));
+ }
+ if( sqlite3_finalize(pStmt)!=SQLITE_OK ){
+ Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
+ return TCL_ERROR;
+ }
+
+ pCtx = (F5tFunction*)ckalloc(sizeof(F5tFunction));
+ pCtx->interp = interp;
+ pCtx->pScript = pScript;
+ Tcl_IncrRefCount(pScript);
+
+ rc = pApi->xCreateFunction(
+ pApi, zName, (void*)pCtx, xF5tFunction, xF5tDestroy
+ );
+ if( rc!=SQLITE_OK ){
+ Tcl_AppendResult(interp, "error: ", sqlite3_errmsg(db), 0);
+ return TCL_ERROR;
+ }
+
+ return TCL_OK;
+}
+
+/*
+** Entry point.
+*/
+int Fts5tcl_Init(Tcl_Interp *interp){
+ static struct Cmd {
+ char *zName;
+ Tcl_ObjCmdProc *xProc;
+ void *clientData;
+ } aCmd[] = {
+ { "sqlite3_fts5_create_function", f5tCreateFunction, 0 }
+ };
+ int i;
+
+ for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
+ struct Cmd *p = &aCmd[i];
+ Tcl_CreateObjCommand(interp, p->zName, p->xProc, p->clientData, 0);
+ }
+
+ return TCL_OK;
+}
+
$(TOP)/ext/misc/spellfix.c \
$(TOP)/ext/misc/totype.c \
$(TOP)/ext/misc/wholenumber.c \
- $(TOP)/ext/misc/vfslog.c
+ $(TOP)/ext/misc/vfslog.c \
+ $(TOP)/ext/fts5/fts5_tcl.c
#TESTSRC += $(TOP)/ext/fts2/fts2_tokenizer.c
-C Add\sa\scookie\smechanism\sto\sensure\sthat\sthe\s%_config\stable\sis\sre-read\sas\srequired.
-D 2014-11-28T20:01:13.778
+C Add\scode\sto\sparse\sa\srank()\sfunction\sspecification.\sAnd\sa\stcl\sinterface\sto\sadd\sauxiliary\sfunctions\sto\sfts5.
+D 2014-12-01T20:05:00.761
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in b03432313a3aad96c706f8164fb9f5307eaf19f5
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7
F ext/fts3/unicode/mkunicode.tcl dc6f268eb526710e2c6e496c372471d773d0c368
F ext/fts5/extract_api_docs.tcl 6320db4a1d0722a4e2069e661381ad75e9889786
-F ext/fts5/fts5.c b3a2574be6921512133d228a922bc0bfb221c569
+F ext/fts5/fts5.c 07f81ce7ebbffdd0acdad9eb090ff506fa503a10
F ext/fts5/fts5.h 72fc1e9995b1ddc254a487b9528614a83bd3dfb6
-F ext/fts5/fts5Int.h a466dd67c909ac05ce8330acf13c7c5bfd244e15
+F ext/fts5/fts5Int.h e16cf2213ae748ccc2c890f404fc341eb941d10b
F ext/fts5/fts5_aux.c 0e3e5fea6bf5772805afe14c95cb5f16e03e4b3f
F ext/fts5/fts5_buffer.c c79d67a5a611521f1f3b9d495981f22c02ef4bdb
-F ext/fts5/fts5_config.c c95d89bd3ee119681f0aeff0fa34ee9cd18fc430
+F ext/fts5/fts5_config.c bb87c2b915ae94002d94d02a6b1f81a0dac9c6db
F ext/fts5/fts5_expr.c d317be07d70223a6865444f17982570260b690a5
F ext/fts5/fts5_hash.c 63fa8379c5f2ac107d47c2b7d9ac04c95ef8a279
F ext/fts5/fts5_index.c 7e7023f3a29f104b44df2ca2474b296b8dfe447c
F ext/fts5/fts5_storage.c 0198c5976cefa5e8d3f1cfffa3587d0dd594fb2a
+F ext/fts5/fts5_tcl.c 5272224faf9be129679da5e19d788f0307afc375
F ext/fts5/fts5_tokenize.c 8360c0d1ae0d4696f3cc13f7c67a2db6011cdc5b
F ext/fts5/fts5parse.y 777da8e5819f75c217982c79c29d014c293acac9
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
-F main.mk 8a02fddafc05159c4b7d65200e912cf549f978c1
+F main.mk 863a6f5cdcc3a47a9dcbedc9af37d3c0d4172935
F mkopcodec.awk c2ff431854d702cdd2d779c9c0d1f58fa16fa4ea
F mkopcodeh.awk c6b3fa301db6ef7ac916b14c60868aeaec1337b5
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
-F src/tclsqlite.c e87c99e28a145943666b51b212dacae35fcea0bd
+F src/tclsqlite.c 3a274c56cfc66b1f957afef201547213fc2ccecc
F src/test1.c 3c8bc491d2f8de5adbbf306533cefc343c733927
F src/test2.c 98049e51a17dc62606a99a9eb95ee477f9996712
F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c
F test/fts5ai.test aa2b5fd0f8d2cf59ac0211111e63cbca3b40ed7d
F test/fts5aj.test bc3d91bd012c7ca175cdf266c2074920bb5fa5ba
F test/fts5ak.test e55bb0f3fac1291d32bc9485a3ee55a7d76f4d5f
-F test/fts5al.test 455b2bdc9f6ffb965a38a970a60c5075ee1e23bb
+F test/fts5al.test d716a933bb88eb6986b02b985924fa42960b6eec
F test/fts5ea.test afaf3497b43add578384dc1fd26b0342738abe87
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test ae97561957aba6ca9e3a7b8a13aac41830d701ef
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 83491c56661ca78f96020ba68184bb3fb19e674f
-R 14f6d2fef178e1939a8a8ad40901ad6e
+P bb4a37b53de60da9ec8b9317eec14afa99690828
+R efa8336057fcd1502b8cbf6d797345c7
U dan
-Z bcf001d05010ed5ade28bb9d53b64e80
+Z dc9192af5fedea55ad78c651e89e8c7b
-bb4a37b53de60da9ec8b9317eec14afa99690828
\ No newline at end of file
+9c1697a2aa1f601e6eb11704abe63a73c8105447
\ No newline at end of file
extern int Sqlitemultiplex_Init(Tcl_Interp*);
extern int SqliteSuperlock_Init(Tcl_Interp*);
extern int SqlitetestSyscall_Init(Tcl_Interp*);
+ extern int Fts5tcl_Init(Tcl_Interp *);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
extern int Sqlitetestfts3_Init(Tcl_Interp *interp);
Sqlitemultiplex_Init(interp);
SqliteSuperlock_Init(interp);
SqlitetestSyscall_Init(interp);
+ Fts5tcl_Init(interp);
#if defined(SQLITE_ENABLE_FTS3) || defined(SQLITE_ENABLE_FTS4)
Sqlitetestfts3_Init(interp);
SELECT * FROM ft1_config;
} {pgsz 64}
+#--------------------------------------------------------------------------
+# Test the logic for parsing the rank() function definition.
+#
+foreach {tn defn} {
+ 1 "fname()"
+ 2 "fname(1)"
+ 3 "fname(1,2)"
+ 4 "fname(null,NULL,nUlL)"
+ 5 " fname ( null , NULL , nUlL ) "
+ 6 "fname('abc')"
+ 7 "fname('a''bc')"
+ 8 "fname('''abc')"
+ 9 "fname('abc''')"
+
+ 7 "fname( 'a''bc' )"
+ 8 "fname('''abc' )"
+ 9 "fname( 'abc''' )"
+
+ 10 "fname(X'1234ab')"
+
+ 11 "myfunc(1.2)"
+ 12 "myfunc(-1.0)"
+ 13 "myfunc(.01,'abc')"
+} {
+ do_execsql_test 2.1.$tn {
+ INSERT INTO ft1(ft1, rank) VALUES('rank', $defn);
+ }
+}
+
+foreach {tn defn} {
+ 1 ""
+ 2 "fname"
+ 3 "fname(X'234ab')"
+ 4 "myfunc(-1.,'abc')"
+} {
+ do_test 2.2.$tn {
+ catchsql { INSERT INTO ft1(ft1, rank) VALUES('rank', $defn) }
+ } {1 {SQL logic error or missing database}}
+}
+
+#-------------------------------------------------------------------------
+#
+
+do_execsql_test 3.1 {
+ CREATE VIRTUAL TABLE t1 USING fts5(x);
+ INSERT INTO t1 VALUES('q w e r t y');
+ INSERT INTO t1 VALUES('y t r e w q');
+}
+
+proc argtest {cmd args} { return $args }
+sqlite3_fts5_create_function db argtest argtest
+
+do_execsql_test 3.2.1 {
+ SELECT argtest(t1, 123) FROM t1 WHERE t1 MATCH 'q'
+} {123 123}
+
+do_execsql_test 3.2.2 {
+ SELECT argtest(t1, 123, 456) FROM t1 WHERE t1 MATCH 'q'
+} {{123 456} {123 456}}
+
+proc rowidtest {cmd} { $cmd xRowid }
+sqlite3_fts5_create_function db rowidtest rowidtest
+
+do_execsql_test 3.3.1 {
+ SELECT rowidtest(t1) FROM t1 WHERE t1 MATCH 'q'
+} {2 1}
+
+proc insttest {cmd} {
+ set res [list]
+ for {set i 0} {$i < [$cmd xInstCount]} {incr i} {
+ lappend res [$cmd xInst $i]
+ }
+ set res
+}
+sqlite3_fts5_create_function db insttest insttest
+
+do_execsql_test 3.4.1 {
+ SELECT insttest(t1) FROM t1 WHERE t1 MATCH 'q'
+} {
+ {{0 0 5}}
+ {{0 0 0}}
+}
+
+do_execsql_test 3.4.2 {
+ SELECT insttest(t1) FROM t1 WHERE t1 MATCH 'r+e OR w'
+} {
+ {{0 0 2} {1 0 4}}
+ {{1 0 1}}
+}
+
+proc coltest {cmd} {
+ list [$cmd xColumnSize 0] [$cmd xColumnText 0]
+}
+sqlite3_fts5_create_function db coltest coltest
+
+do_execsql_test 3.4.1 {
+ SELECT coltest(t1) FROM t1 WHERE t1 MATCH 'q'
+} {
+ {6 {y t r e w q}} {6 {q w e r t y}}
+}
+
finish_test