#define FTS5_CURRENT_VERSION 4
#define FTS5_CURRENT_VERSION_SECUREDELETE 5
-#define FTS5_CONTENT_NORMAL 0
-#define FTS5_CONTENT_NONE 1
-#define FTS5_CONTENT_EXTERNAL 2
+#define FTS5_CONTENT_NORMAL 0
+#define FTS5_CONTENT_NONE 1
+#define FTS5_CONTENT_EXTERNAL 2
+#define FTS5_CONTENT_UNINDEXED 3
#define FTS5_DETAIL_FULL 0
#define FTS5_DETAIL_NONE 1
Fts5Config *p,
char *zCol,
char *zArg,
- char **pzErr
+ char **pzErr,
+ int *pbUnindexed
){
int rc = SQLITE_OK;
if( 0==sqlite3_stricmp(zCol, FTS5_RANK_NAME)
}else if( zArg ){
if( 0==sqlite3_stricmp(zArg, "unindexed") ){
p->abUnindexed[p->nCol] = 1;
+ *pbUnindexed = 1;
}else{
*pzErr = sqlite3_mprintf("unrecognized column option: %s", zArg);
rc = SQLITE_ERROR;
sqlite3Fts5BufferAppendPrintf(&rc, &buf, "T.%Q", p->zContentRowid);
if( p->eContent!=FTS5_CONTENT_NONE ){
+ assert( p->eContent==FTS5_CONTENT_EXTERNAL
+ || p->eContent==FTS5_CONTENT_NORMAL
+ || p->eContent==FTS5_CONTENT_UNINDEXED
+ );
for(i=0; i<p->nCol; i++){
if( p->eContent==FTS5_CONTENT_EXTERNAL ){
sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.%Q", p->azCol[i]);
- }else{
+ }else if( p->eContent==FTS5_CONTENT_NORMAL || p->abUnindexed[i] ){
sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", T.c%d", i);
+ }else{
+ sqlite3Fts5BufferAppendPrintf(&rc, &buf, ", NULL");
}
}
}
Fts5Config *pRet; /* New object to return */
int i;
sqlite3_int64 nByte;
+ int bUnindexed = 0; /* True if there are one or more UNINDEXED */
*ppOut = pRet = (Fts5Config*)sqlite3_malloc(sizeof(Fts5Config));
if( pRet==0 ) return SQLITE_NOMEM;
pzErr
);
}else{
- rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr);
+ rc = fts5ConfigParseColumn(pRet, zOne, zTwo, pzErr, &bUnindexed);
zOne = 0;
}
}
/* If no zContent option was specified, fill in the default values. */
if( rc==SQLITE_OK && pRet->zContent==0 ){
const char *zTail = 0;
- assert( pRet->eContent==FTS5_CONTENT_NORMAL
- || pRet->eContent==FTS5_CONTENT_NONE
+ assert( pRet->eContent==FTS5_CONTENT_NORMAL
+ || pRet->eContent==FTS5_CONTENT_NONE
);
if( pRet->eContent==FTS5_CONTENT_NORMAL ){
zTail = "content";
+ }else if( bUnindexed ){
+ pRet->eContent = FTS5_CONTENT_UNINDEXED;
+ zTail = "content";
}else if( pRet->bColumnsize ){
zTail = "docsize";
}
}
bLoadConfig = 1;
}else if( 0==sqlite3_stricmp("rebuild", zCmd) ){
- if( pConfig->eContent==FTS5_CONTENT_NONE ){
+ if( pConfig->eContent==FTS5_CONTENT_NONE
+ || pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
fts5SetVtabError(pTab,
"'rebuild' may not be used with a contentless fts5 table"
);
case FTS5_STMT_INSERT_CONTENT:
case FTS5_STMT_REPLACE_CONTENT: {
int nCol = pC->nCol + 1;
- char *zBind;
+ char *zBind = 0;
int i;
- zBind = sqlite3_malloc64(1 + nCol*2);
- if( zBind ){
- for(i=0; i<nCol; i++){
- zBind[i*2] = '?';
- zBind[i*2 + 1] = ',';
+ assert( pC->eContent==FTS5_CONTENT_NORMAL
+ || pC->eContent==FTS5_CONTENT_UNINDEXED
+ );
+
+ for(i=0; rc==SQLITE_OK && i<nCol; i++){
+ if( !i || pC->eContent==FTS5_CONTENT_NORMAL || pC->abUnindexed[i-1] ){
+ zBind = sqlite3Fts5Mprintf(&rc, "%z%s?%d", zBind, zBind?",":"",i+1);
}
- zBind[i*2-1] = '\0';
- zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind);
- sqlite3_free(zBind);
}
+
+ zSql = sqlite3Fts5Mprintf(&rc, azStmt[eStmt], pC->zDb, pC->zName,zBind);
+ sqlite3_free(zBind);
break;
}
p->pIndex = pIndex;
if( bCreate ){
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
int nDefn = 32 + pConfig->nCol*10;
char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 10);
if( zDefn==0 ){
sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
iOff = (int)strlen(zDefn);
for(i=0; i<pConfig->nCol; i++){
- sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
- iOff += (int)strlen(&zDefn[iOff]);
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->abUnindexed[i]
+ ){
+ sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
+ iOff += (int)strlen(&zDefn[iOff]);
+ }
}
rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
}
int rc = SQLITE_OK;
assert( p->pConfig->bContentlessDelete );
- assert( p->pConfig->eContent==FTS5_CONTENT_NONE );
+ assert( p->pConfig->eContent==FTS5_CONTENT_NONE
+ || p->pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ );
/* Look up the origin of the document in the %_docsize table. Store
** this in stack variable iOrigin. */
}
/* Delete the %_content record */
- if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->eContent==FTS5_CONTENT_UNINDEXED
+ ){
if( rc==SQLITE_OK ){
rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
}
);
if( rc==SQLITE_OK && pConfig->bColumnsize ){
rc = fts5ExecPrintf(pConfig->db, 0,
- "DELETE FROM %Q.'%q_docsize';",
- pConfig->zDb, pConfig->zName
+ "DELETE FROM %Q.'%q_docsize';", pConfig->zDb, pConfig->zName
+ );
+ }
+
+ if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_UNINDEXED ){
+ rc = fts5ExecPrintf(pConfig->db, 0,
+ "DELETE FROM %Q.'%q_content';", pConfig->zDb, pConfig->zName
);
}
int rc = SQLITE_OK;
/* Insert the new row into the %_content table. */
- if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
+ if( pConfig->eContent!=FTS5_CONTENT_NORMAL
+ && pConfig->eContent!=FTS5_CONTENT_UNINDEXED
+ ){
if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
*piRowid = sqlite3_value_int64(apVal[1]);
}else{
int i; /* Counter variable */
rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
- sqlite3_value *pVal = apVal[i];
- if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
- /* This is an UPDATE statement, and column (i-2) was not modified.
- ** Retrieve the value from Fts5Storage.pSavedRow instead. */
- pVal = sqlite3_column_value(p->pSavedRow, i-1);
- }else if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE ){
- assert( pConfig->bLocale );
- assert( i>1 );
- if( pConfig->abUnindexed[i-2] ){
- /* At attempt to insert an fts5_locale() value into an UNINDEXED
- ** column. Strip the locale away and just bind the text. */
- const char *pText = 0;
- int nText = 0;
- rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, 0, &pText, &nText);
- sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
- }else{
- const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal);
- int nBlob = sqlite3_value_bytes(pVal);
- assert( nBlob>4 );
- sqlite3_bind_blob(pInsert, i, pBlob+4, nBlob-4, SQLITE_TRANSIENT);
+ if( i==1
+ || pConfig->eContent==FTS5_CONTENT_NORMAL
+ || pConfig->abUnindexed[i-2]
+ ){
+ sqlite3_value *pVal = apVal[i];
+ if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
+ /* This is an UPDATE statement, and column (i-2) was not modified.
+ ** Retrieve the value from Fts5Storage.pSavedRow instead. */
+ pVal = sqlite3_column_value(p->pSavedRow, i-1);
+ }else if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE ){
+ assert( pConfig->bLocale );
+ assert( i>1 );
+ if( pConfig->abUnindexed[i-2] ){
+ /* At attempt to insert an fts5_locale() value into an UNINDEXED
+ ** column. Strip the locale away and just bind the text. */
+ const char *pText = 0;
+ int nText = 0;
+ rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, 0, &pText, &nText);
+ sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT);
+ }else{
+ const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal);
+ int nBlob = sqlite3_value_bytes(pVal);
+ assert( nBlob>4 );
+ sqlite3_bind_blob(pInsert, i, pBlob+4, nBlob-4, SQLITE_TRANSIENT);
+ }
+ continue;
}
- continue;
+
+ rc = sqlite3_bind_value(pInsert, i, pVal);
}
-
- rc = sqlite3_bind_value(pInsert, i, pVal);
}
if( rc==SQLITE_OK ){
sqlite3_step(pInsert);
--- /dev/null
+# 2015 Apr 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.
+#
+#***********************************************************************
+#
+# The tests in this file focus on "unindexed" columns in contentless
+# tables.
+#
+
+source [file join [file dirname [info script]] fts5_common.tcl]
+set testprefix fts5unindexed2
+
+# If SQLITE_ENABLE_FTS5 is not defined, omit this file.
+ifcapable !fts5 {
+ finish_test
+ return
+}
+
+
+do_execsql_test 1.1 {
+ CREATE VIRTUAL TABLE t1 USING fts5(a, b UNINDEXED, content=);
+} {}
+
+do_execsql_test 1.2 {
+ INSERT INTO t1 VALUES('abc def', 'ghi jkl');
+}
+
+do_execsql_test 1.3 {
+ SELECT rowid, a, b FROM t1
+} {1 {} {ghi jkl}}
+
+do_execsql_test 1.4 {
+ INSERT INTO t1(rowid, a, b) VALUES(11, 'hello world', 'one two three');
+}
+
+do_execsql_test 1.5 {
+ INSERT INTO t1(t1, rowid, a, b) VALUES('delete', 1, 'abc def', 'ghi jkl');
+}
+
+do_execsql_test 1.6 {
+ SELECT rowid, a, b FROM t1
+} {
+ 11 {} {one two three}
+}
+
+do_execsql_test 1.7 {
+ PRAGMA integrity_check
+} {ok}
+
+do_execsql_test 1.8 {
+ INSERT INTO t1(rowid, a, b) VALUES(12, 'abc def', 'ghi jkl');
+}
+
+do_execsql_test 1.9 {
+ SELECT rowid, a, b FROM t1('def')
+} {12 {} {ghi jkl}}
+
+do_execsql_test 1.10 {
+ SELECT rowid, a, b FROM t1('def OR hello') ORDER BY rank
+} {11 {} {one two three} 12 {} {ghi jkl}}
+
+do_execsql_test 1.11 {
+ SELECT rowid, a, b FROM t1 WHERE rowid=11
+} {11 {} {one two three}}
+
+do_execsql_test 1.12 {
+ SELECT rowid, a, b FROM t1
+} {11 {} {one two three} 12 {} {ghi jkl}}
+
+
+fts5_aux_test_functions db
+do_execsql_test 1.12.2 {
+ SELECT rowid, fts5_test_columntext(t1) FROM t1('def OR hello')
+} {11 {{} {one two three}} 12 {{} {ghi jkl}}}
+
+do_execsql_test 1.13 {
+ INSERT INTO t1(t1) VALUES('delete-all');
+}
+
+do_execsql_test 1.14 {
+ SELECT rowid, a, b FROM t1
+}
+
+do_execsql_test 1.15 {
+ PRAGMA integrity_check
+} {ok}
+
+do_execsql_test 2.0 {
+ CREATE VIRTUAL TABLE t4 USING fts5(
+ x, y UNINDEXED, z, columnsize=0, content=''
+ );
+}
+
+do_execsql_test 2.1 {
+ INSERT INTO t4(rowid, x, y, z) VALUES(1, 'a a', 'b b b', 'c');
+}
+
+#-------------------------------------------------------------------------
+reset_db
+
+do_execsql_test 3.0 {
+ CREATE VIRTUAL TABLE x1 USING fts5(
+ a UNINDEXED, b, c UNINDEXED, d, content=, contentless_delete=1
+ );
+}
+
+do_execsql_test 3.1 {
+ INSERT INTO x1(rowid, a, b, c, d) VALUES(131, 'aaa', 'bbb', 'ccc', 'ddd');
+}
+
+do_execsql_test 3.2 {
+ SELECT * FROM x1
+} {aaa {} ccc {}}
+
+do_execsql_test 3.3 {
+ INSERT INTO x1(rowid, a, b, c, d) VALUES(1000, 'AAA', 'BBB', 'CCC', 'DDD');
+}
+
+do_execsql_test 3.4 {
+ SELECT rowid, * FROM x1
+} {
+ 131 aaa {} ccc {}
+ 1000 AAA {} CCC {}
+}
+
+do_execsql_test 3.5 {
+ DELETE FROM x1 WHERE rowid=131;
+ SELECT rowid, * FROM x1
+} {
+ 1000 AAA {} CCC {}
+}
+
+do_execsql_test 3.6 {
+ INSERT INTO x1(rowid, a, b, c, d) VALUES(112, 'aaa', 'bbb', 'ccc', 'ddd');
+ SELECT rowid, * FROM x1
+} {
+ 112 aaa {} ccc {}
+ 1000 AAA {} CCC {}
+}
+
+do_execsql_test 3.7 {
+ UPDATE x1 SET b='hello', d='world', rowid=1120 WHERE rowid=112
+}
+
+do_execsql_test 3.8 {
+ SELECT rowid, * FROM x1
+} {
+ 1000 AAA {} CCC {}
+ 1120 aaa {} ccc {}
+}
+
+do_execsql_test 3.9 {
+ SELECT rowid, * FROM x1('hello');
+} {
+ 1120 aaa {} ccc {}
+}
+
+do_execsql_test 3.9 {
+ SELECT rowid, * FROM x1('bbb');
+} {
+ 1000 AAA {} CCC {}
+}
+
+fts5_aux_test_functions db
+do_execsql_test 3.10 {
+ SELECT rowid, fts5_test_columntext(x1) FROM x1('b*')
+} {1000 {AAA {} CCC {}}}
+
+finish_test
+
-C In\stestrunner.tcl,\sallow\ssetting\snjob\sto\szero,\swhich\scauses\sno\snew\sjobs\nto\sbe\slaunched\sand\sfor\sthe\sprocess\sto\sshut\sdown\sonce\sall\scurrent\sjobs\sare\ncompleted.
-D 2024-09-03T10:53:32.903
+C Store\sthe\svalues\sof\sany\sUNINDEXED\scolumns\sof\sa\scontentless\sfts5\stable\spersistently\sin\sthe\sdatabase.\sWarning:\sThis\scurrently\screates\sa\s(technically)\sincompatible\sfile-format\sfor\scontentless\sfts5\stables\sthat\shave\sUNINDEXED\scolumns.
+D 2024-09-03T18:55:38.957
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb
F ext/fts5/extract_api_docs.tcl 009cf59c77afa86d137b0cca3e3b1a5efbe2264faa2df233f9a7aa8563926d15
F ext/fts5/fts5.h efaaac0df3d3bc740383044c144b582f47921aafa21d7b10eb98f42c24c740b0
-F ext/fts5/fts5Int.h 26a71a09cefa4ef6b4516b204ed48da3e1380970a19b3482eea7c5d805655360
+F ext/fts5/fts5Int.h d0c9bee4edfff9f0899648a9efc0afdebabbadb24403e2e50a1bb17aed6267d0
F ext/fts5/fts5_aux.c 65a0468dd177d6093aa9ae1622e6d86b0136b8d267c62c0ad6493ad1e9a3d759
F ext/fts5/fts5_buffer.c 0eec58bff585f1a44ea9147eae5da2447292080ea435957f7488c70673cb6f09
-F ext/fts5/fts5_config.c 353d2a0d12678cae6ab5b9ce54aed8dac0825667b69248b5a4ed81cbefc109ea
+F ext/fts5/fts5_config.c 8dba11620a7964e1e561aaae3d27fdd2d16b2769c979f157dd55a53903a9b734
F ext/fts5/fts5_expr.c 9a56f53700d1860f0ee2f373c2b9074eaf2a7aa0637d0e27a6476de26a3fee33
F ext/fts5/fts5_hash.c adda4272be401566a6e0ba1acbe70ee5cb97fce944bc2e04dc707152a0ec91b1
F ext/fts5/fts5_index.c 571483823193f09439356741669aa8c81da838ae6f5e1bfa7517f7ee2fb3addd
-F ext/fts5/fts5_main.c 1fddb53f495425d9314c74b30c5848a9dd254be0e5f445bfe38292d5ab21c288
-F ext/fts5/fts5_storage.c 9a9b880be12901f1962ae2a5a7e1b74348b3099a1e728764e419f75d98e3e612
+F ext/fts5/fts5_main.c 402a65b6d922203a90e7d440f29d71f19f6863e6b663ca9f06c7321f291bda40
+F ext/fts5/fts5_storage.c ca3bdb799b9b039133e9b6e4881fc974ba34ae4ea57530210289f82313b409b5
F ext/fts5/fts5_tcl.c 4db9258a7882c5eac0da4433042132aaf15b87dd1e1636c7a6ca203abd2c8bfe
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b
F ext/fts5/test/fts5unicode3.test f4891a3dac3b49c3d7c0fdb29566e9eb0ecff35263370c89f9661b1952b20818
F ext/fts5/test/fts5unicode4.test 728c8f0caafb05567f524ad313d9f8b780fa45987b8a8df04eff87923c74b4d0
F ext/fts5/test/fts5unindexed.test 168838d2c385e131120bbf5b516d2432a5fabc4caa2259c932e1d49ae209a4ae
+F ext/fts5/test/fts5unindexed2.test f8453dcf1df11544263d350d388d5c612be4b379079b308f1ad74cdaa940804e
F ext/fts5/test/fts5update.test b8affd796e45c94a4d19ad5c26606ea06065a0f162a9562d9f005b5a80ccf0bc
F ext/fts5/test/fts5version.test c22d163c17e60a99f022cbc52de5a48bb7f84deaa00fe15e9bc4c3aa1996204e
F ext/fts5/test/fts5vocab.test 2a2bdb60d0998fa3124d541b6d30b019504918dc43a6584645b63a24be72f992
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 7891a266c4425722ae8b9231397ef9e42e2432be9e6b70632dfaf9ff15300d2c
-R 6a86d12ea82ce01298969ad043e5cc65
-U drh
-Z 5112afd2e4dab18f4b12bbba01825cee
+P 0ef65fd4ba17def4c13986365b3af300c4024725af4bc314845d1af8be568ab4
+R 87dfb79be977919afc56ac91ca0cf0b0
+T *branch * fts5-contentless-unindexed
+T *sym-fts5-contentless-unindexed *
+T -sym-trunk *
+U dan
+Z f39a0e93422c865c24dfd629a9a47017
# Remove this line to create a well-formed Fossil manifest.
-0ef65fd4ba17def4c13986365b3af300c4024725af4bc314845d1af8be568ab4
+dcacb1a8ef359b4507b4733356d3150ba5dc105cc9867c103d16a0908a1a9f64