Ensure that an fts5 UPDATE does not strip the locale from columns that it does not write to.
FossilOrigin-Name: 69205264debd829573b1c777a5a493cfeb6083c4cdec106b1f819989f859ac75
This commit is contained in:
+4
-1
@@ -720,7 +720,7 @@ int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName);
|
||||
int sqlite3Fts5DropAll(Fts5Config*);
|
||||
int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **);
|
||||
|
||||
int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**);
|
||||
int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int);
|
||||
int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*);
|
||||
int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64);
|
||||
|
||||
@@ -746,6 +746,9 @@ int sqlite3Fts5StorageOptimize(Fts5Storage *p);
|
||||
int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge);
|
||||
int sqlite3Fts5StorageReset(Fts5Storage *p);
|
||||
|
||||
void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage*);
|
||||
int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel);
|
||||
|
||||
/*
|
||||
** End of interface to code in fts5_storage.c.
|
||||
**************************************************************************/
|
||||
|
||||
+50
-28
@@ -1746,7 +1746,7 @@ static int fts5SpecialDelete(
|
||||
int eType1 = sqlite3_value_type(apVal[1]);
|
||||
if( eType1==SQLITE_INTEGER ){
|
||||
sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]);
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]);
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2], 0);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
@@ -1870,7 +1870,7 @@ static int fts5UpdateMethod(
|
||||
/* DELETE */
|
||||
else if( nArg==1 ){
|
||||
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0);
|
||||
bUpdateOrDelete = 1;
|
||||
}
|
||||
|
||||
@@ -1878,16 +1878,18 @@ static int fts5UpdateMethod(
|
||||
else{
|
||||
int eType1 = sqlite3_value_numeric_type(apVal[1]);
|
||||
|
||||
if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){
|
||||
if( (eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL)
|
||||
|| (eType0==SQLITE_INTEGER && eType1==SQLITE_NULL)
|
||||
){
|
||||
rc = SQLITE_MISMATCH;
|
||||
}
|
||||
|
||||
else if( eType0!=SQLITE_INTEGER ){
|
||||
else if( eType0!=SQLITE_INTEGER ){
|
||||
/* An INSERT statement. If the conflict-mode is REPLACE, first remove
|
||||
** the current entry (if any). */
|
||||
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
|
||||
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
|
||||
bUpdateOrDelete = 1;
|
||||
}
|
||||
fts5StorageInsert(&rc, pTab, apVal, pRowid);
|
||||
@@ -1897,28 +1899,34 @@ static int fts5UpdateMethod(
|
||||
else{
|
||||
i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */
|
||||
i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */
|
||||
if( eType1==SQLITE_INTEGER && iOld!=iNew ){
|
||||
assert( eType1==SQLITE_INTEGER );
|
||||
if( iOld!=iNew ){
|
||||
if( eConflict==SQLITE_REPLACE ){
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0);
|
||||
}
|
||||
fts5StorageInsert(&rc, pTab, apVal, pRowid);
|
||||
}else{
|
||||
rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid);
|
||||
rc = sqlite3Fts5StorageFindDeleteRow(pTab->pStorage, iOld);
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
|
||||
rc = sqlite3Fts5StorageContentInsert(pTab->pStorage,apVal,pRowid);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
|
||||
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1);
|
||||
fts5StorageInsert(&rc, pTab, apVal, pRowid);
|
||||
}
|
||||
bUpdateOrDelete = 1;
|
||||
sqlite3Fts5StorageReleaseDeleteRow(pTab->pStorage);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2606,6 +2614,16 @@ static Fts5Cursor *fts5CursorFromCsrid(Fts5Global *pGlobal, i64 iCsrId){
|
||||
return pCsr;
|
||||
}
|
||||
|
||||
static void fts5ResultError(sqlite3_context *pCtx, const char *zFmt, ...){
|
||||
char *zErr = 0;
|
||||
va_list ap;
|
||||
va_start(ap, zFmt);
|
||||
zErr = sqlite3_vmprintf(zFmt, ap);
|
||||
sqlite3_result_error(pCtx, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void fts5ApiCallback(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
@@ -2622,9 +2640,7 @@ static void fts5ApiCallback(
|
||||
|
||||
pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId);
|
||||
if( pCsr==0 || pCsr->ePlan==0 ){
|
||||
char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId);
|
||||
sqlite3_result_error(context, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
fts5ResultError(context, "no such cursor: %lld", iCsrId);
|
||||
}else{
|
||||
sqlite3_vtab *pTab = pCsr->base.pVtab;
|
||||
fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]);
|
||||
@@ -2776,8 +2792,8 @@ static int fts5ColumnMethod(
|
||||
** auxiliary function. */
|
||||
sqlite3_result_int64(pCtx, pCsr->iCsrId);
|
||||
}else if( iCol==pConfig->nCol+1 ){
|
||||
|
||||
/* The value of the "rank" column. */
|
||||
|
||||
if( pCsr->ePlan==FTS5_PLAN_SOURCE ){
|
||||
fts5PoslistBlob(pCtx, pCsr);
|
||||
}else if(
|
||||
@@ -2788,21 +2804,27 @@ static int fts5ColumnMethod(
|
||||
fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg);
|
||||
}
|
||||
}
|
||||
}else if( !fts5IsContentless(pTab) ){
|
||||
pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
|
||||
rc = fts5SeekCursor(pCsr, 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
|
||||
fts5ExtractValueFromColumn(pCtx, pConfig, pVal);
|
||||
}else{
|
||||
/* A column created by the user containing values. */
|
||||
int bNochange = sqlite3_vtab_nochange(pCtx);
|
||||
|
||||
if( fts5IsContentless(pTab) ){
|
||||
if( bNochange && pConfig->bContentlessDelete ){
|
||||
fts5ResultError(pCtx, "cannot UPDATE a subset of "
|
||||
"columns on fts5 contentless-delete table: %s", pConfig->zName
|
||||
);
|
||||
}
|
||||
}else if( bNochange==0 || pConfig->eContent!=FTS5_CONTENT_NORMAL ){
|
||||
pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
|
||||
rc = fts5SeekCursor(pCsr, 1);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1);
|
||||
fts5ExtractValueFromColumn(pCtx, pConfig, pVal);
|
||||
}
|
||||
pConfig->pzErrmsg = 0;
|
||||
}
|
||||
pConfig->pzErrmsg = 0;
|
||||
}else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){
|
||||
char *zErr = sqlite3_mprintf("cannot UPDATE a subset of "
|
||||
"columns on fts5 contentless-delete table: %s", pConfig->zName
|
||||
);
|
||||
sqlite3_result_error(pCtx, zErr, -1);
|
||||
sqlite3_free(zErr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
+81
-24
@@ -22,7 +22,8 @@ struct Fts5Storage {
|
||||
int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */
|
||||
i64 nTotalRow; /* Total number of rows in FTS table */
|
||||
i64 *aTotalSize; /* Total sizes of each column */
|
||||
sqlite3_stmt *aStmt[11];
|
||||
sqlite3_stmt *pSavedRow;
|
||||
sqlite3_stmt *aStmt[12];
|
||||
};
|
||||
|
||||
|
||||
@@ -36,14 +37,15 @@ struct Fts5Storage {
|
||||
# error "FTS5_STMT_LOOKUP mismatch"
|
||||
#endif
|
||||
|
||||
#define FTS5_STMT_INSERT_CONTENT 3
|
||||
#define FTS5_STMT_REPLACE_CONTENT 4
|
||||
#define FTS5_STMT_DELETE_CONTENT 5
|
||||
#define FTS5_STMT_REPLACE_DOCSIZE 6
|
||||
#define FTS5_STMT_DELETE_DOCSIZE 7
|
||||
#define FTS5_STMT_LOOKUP_DOCSIZE 8
|
||||
#define FTS5_STMT_REPLACE_CONFIG 9
|
||||
#define FTS5_STMT_SCAN 10
|
||||
#define FTS5_STMT_LOOKUP2 3
|
||||
#define FTS5_STMT_INSERT_CONTENT 4
|
||||
#define FTS5_STMT_REPLACE_CONTENT 5
|
||||
#define FTS5_STMT_DELETE_CONTENT 6
|
||||
#define FTS5_STMT_REPLACE_DOCSIZE 7
|
||||
#define FTS5_STMT_DELETE_DOCSIZE 8
|
||||
#define FTS5_STMT_LOOKUP_DOCSIZE 9
|
||||
#define FTS5_STMT_REPLACE_CONFIG 10
|
||||
#define FTS5_STMT_SCAN 11
|
||||
|
||||
/*
|
||||
** Prepare the two insert statements - Fts5Storage.pInsertContent and
|
||||
@@ -73,6 +75,7 @@ static int fts5StorageGetStmt(
|
||||
"SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
|
||||
"SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
|
||||
"SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */
|
||||
"SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP2 */
|
||||
|
||||
"INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
|
||||
"REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
|
||||
@@ -88,6 +91,8 @@ static int fts5StorageGetStmt(
|
||||
Fts5Config *pC = p->pConfig;
|
||||
char *zSql = 0;
|
||||
|
||||
assert( ArraySize(azStmt)==ArraySize(p->aStmt) );
|
||||
|
||||
switch( eStmt ){
|
||||
case FTS5_STMT_SCAN:
|
||||
zSql = sqlite3_mprintf(azStmt[eStmt],
|
||||
@@ -104,6 +109,7 @@ static int fts5StorageGetStmt(
|
||||
break;
|
||||
|
||||
case FTS5_STMT_LOOKUP:
|
||||
case FTS5_STMT_LOOKUP2:
|
||||
zSql = sqlite3_mprintf(azStmt[eStmt],
|
||||
pC->zContentExprlist, pC->zContent, pC->zContentRowid
|
||||
);
|
||||
@@ -150,7 +156,7 @@ static int fts5StorageGetStmt(
|
||||
rc = SQLITE_NOMEM;
|
||||
}else{
|
||||
int f = SQLITE_PREPARE_PERSISTENT;
|
||||
if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB;
|
||||
if( eStmt>FTS5_STMT_LOOKUP2 ) f |= SQLITE_PREPARE_NO_VTAB;
|
||||
p->pConfig->bLock++;
|
||||
rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0);
|
||||
p->pConfig->bLock--;
|
||||
@@ -399,6 +405,24 @@ static int fts5StorageInsertCallback(
|
||||
return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken);
|
||||
}
|
||||
|
||||
int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt *pSeek = 0;
|
||||
|
||||
assert( p->pSavedRow==0 );
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+1, &pSeek, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_bind_int64(pSeek, 1, iDel);
|
||||
if( sqlite3_step(pSeek)!=SQLITE_ROW ){
|
||||
rc = sqlite3_reset(pSeek);
|
||||
}else{
|
||||
p->pSavedRow = pSeek;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
** If a row with rowid iDel is present in the %_content table, add the
|
||||
** delete-markers to the FTS index necessary to delete it. Do not actually
|
||||
@@ -407,7 +431,8 @@ static int fts5StorageInsertCallback(
|
||||
static int fts5StorageDeleteFromIndex(
|
||||
Fts5Storage *p,
|
||||
i64 iDel,
|
||||
sqlite3_value **apVal
|
||||
sqlite3_value **apVal,
|
||||
int bSaveRow
|
||||
){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */
|
||||
@@ -416,12 +441,21 @@ static int fts5StorageDeleteFromIndex(
|
||||
int iCol;
|
||||
Fts5InsertCtx ctx;
|
||||
|
||||
assert( bSaveRow==0 || apVal==0 );
|
||||
assert( bSaveRow==0 || bSaveRow==1 );
|
||||
assert( FTS5_STMT_LOOKUP2==FTS5_STMT_LOOKUP+1 );
|
||||
|
||||
if( apVal==0 ){
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
sqlite3_bind_int64(pSeek, 1, iDel);
|
||||
if( sqlite3_step(pSeek)!=SQLITE_ROW ){
|
||||
return sqlite3_reset(pSeek);
|
||||
if( p->pSavedRow && bSaveRow ){
|
||||
pSeek = p->pSavedRow;
|
||||
p->pSavedRow = 0;
|
||||
}else{
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+bSaveRow, &pSeek, 0);
|
||||
if( rc!=SQLITE_OK ) return rc;
|
||||
sqlite3_bind_int64(pSeek, 1, iDel);
|
||||
if( sqlite3_step(pSeek)!=SQLITE_ROW ){
|
||||
return sqlite3_reset(pSeek);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,11 +496,21 @@ static int fts5StorageDeleteFromIndex(
|
||||
p->nTotalRow--;
|
||||
}
|
||||
|
||||
rc2 = sqlite3_reset(pSeek);
|
||||
if( rc==SQLITE_OK ) rc = rc2;
|
||||
if( rc==SQLITE_OK && bSaveRow ){
|
||||
assert( p->pSavedRow==0 );
|
||||
p->pSavedRow = pSeek;
|
||||
}else{
|
||||
rc2 = sqlite3_reset(pSeek);
|
||||
if( rc==SQLITE_OK ) rc = rc2;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){
|
||||
sqlite3_reset(pStorage->pSavedRow);
|
||||
pStorage->pSavedRow = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called to process a DELETE on a contentless_delete=1
|
||||
** table. It adds the tombstone required to delete the entry with rowid
|
||||
@@ -582,7 +626,12 @@ static int fts5StorageSaveTotals(Fts5Storage *p){
|
||||
/*
|
||||
** Remove a row from the FTS table.
|
||||
*/
|
||||
int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
|
||||
int sqlite3Fts5StorageDelete(
|
||||
Fts5Storage *p, /* Storage object */
|
||||
i64 iDel, /* Rowid to delete from table */
|
||||
sqlite3_value **apVal, /* Optional - values to remove from index */
|
||||
int bSaveRow
|
||||
){
|
||||
Fts5Config *pConfig = p->pConfig;
|
||||
int rc;
|
||||
sqlite3_stmt *pDel = 0;
|
||||
@@ -599,7 +648,7 @@ int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){
|
||||
if( p->pConfig->bContentlessDelete ){
|
||||
rc = fts5StorageContentlessDelete(p, iDel);
|
||||
}else{
|
||||
rc = fts5StorageDeleteFromIndex(p, iDel, apVal);
|
||||
rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -787,7 +836,11 @@ int sqlite3Fts5StorageContentInsert(
|
||||
int i; /* Counter variable */
|
||||
rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
|
||||
for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
|
||||
rc = sqlite3_bind_value(pInsert, i, apVal[i]);
|
||||
sqlite3_value *pVal = apVal[i];
|
||||
if( sqlite3_value_nochange(pVal) && p->pSavedRow ){
|
||||
pVal = sqlite3_column_value(p->pSavedRow, i-1);
|
||||
}
|
||||
rc = sqlite3_bind_value(pInsert, i, pVal);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
sqlite3_step(pInsert);
|
||||
@@ -825,9 +878,13 @@ int sqlite3Fts5StorageIndexInsert(
|
||||
int bReset = 0;
|
||||
int nText = 0;
|
||||
const char *pText = 0;
|
||||
rc = sqlite3Fts5ExtractText(
|
||||
pConfig, 0, apVal[ctx.iCol+2], &bReset, &pText, &nText
|
||||
);
|
||||
sqlite3_value *pVal = apVal[ctx.iCol+2];
|
||||
int bDisk = 0;
|
||||
if( p->pSavedRow && sqlite3_value_nochange(pVal) ){
|
||||
pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1);
|
||||
bDisk = 1;
|
||||
}
|
||||
rc = sqlite3Fts5ExtractText(pConfig, bDisk, pVal, &bReset,&pText,&nText);
|
||||
if( rc==SQLITE_OK ){
|
||||
if( bReset && pConfig->bLocale==0 ){
|
||||
rc = SQLITE_ERROR;
|
||||
|
||||
@@ -167,9 +167,54 @@ do_execsql_test 3.4 {
|
||||
hello world
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# Test that an UPDATE that updates a subset of the columns does not
|
||||
# magically discard the locale from those columns not updated.
|
||||
#
|
||||
reset_db
|
||||
sqlite3_fts5_create_tokenizer -v2 db tcl tcl_create
|
||||
|
||||
do_execsql_test 4.1 {
|
||||
CREATE VIRTUAL TABLE d1 USING fts5(x, y, locale=1, tokenize=tcl);
|
||||
CREATE VIRTUAL TABLE d2 USING fts5vocab('d1', instance);
|
||||
|
||||
# execsql_pp { SELECT * FROM ttt }
|
||||
INSERT INTO d1(rowid, x, y) VALUES(1, 'abc', 'def');
|
||||
INSERT INTO d1(rowid, x, y) VALUES(2, 'ghi', fts5_locale('reverse', 'hello'));
|
||||
}
|
||||
|
||||
do_execsql_test 4.2 {
|
||||
SELECT DISTINCT term FROM d2 ORDER BY 1
|
||||
} {
|
||||
abc def ghi olleh
|
||||
}
|
||||
|
||||
do_execsql_test 4.3 {
|
||||
UPDATE d1 SET x='jkl' WHERE rowid=2;
|
||||
}
|
||||
|
||||
do_execsql_test 4.4 {
|
||||
SELECT DISTINCT term FROM d2 ORDER BY 1
|
||||
} {
|
||||
abc def jkl olleh
|
||||
}
|
||||
|
||||
do_execsql_test 4.5 {
|
||||
SELECT rowid, * FROM d1
|
||||
} {
|
||||
1 abc def
|
||||
2 jkl hello
|
||||
}
|
||||
|
||||
do_execsql_test 4.6 {
|
||||
UPDATE d1 SET rowid=4 WHERE rowid=2
|
||||
}
|
||||
|
||||
do_execsql_test 4.7 {
|
||||
SELECT rowid, * FROM d1
|
||||
} {
|
||||
1 abc def
|
||||
4 jkl hello
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
|
||||
@@ -312,6 +312,7 @@ do_execsql_test 13.1 {
|
||||
INSERT INTO xy(rowid, x) VALUES(3, '3 4 5');
|
||||
}
|
||||
|
||||
breakpoint
|
||||
do_execsql_test 13.2 {
|
||||
UPDATE OR REPLACE xy SET rowid=3 WHERE rowid = 2;
|
||||
SELECT rowid, x FROM xy;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
C Add\sthe\sfts5_locale()\sfunction,\sand\sbegin\sadding\sthe\srelated\sfunctionality\sto\sfts5.
|
||||
D 2024-07-26T20:50:33.303
|
||||
C Ensure\sthat\san\sfts5\sUPDATE\sdoes\snot\sstrip\sthe\slocale\sfrom\scolumns\sthat\sit\sdoes\snot\swrite\sto.
|
||||
D 2024-07-27T19:46:10.539
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -93,15 +93,15 @@ F ext/fts3/unicode/mkunicode.tcl d5aebf022fa4577ee8cdf27468f0d847879993959101f6d
|
||||
F ext/fts3/unicode/parseunicode.tcl a981bd6466d12dd17967515801c3ff23f74a281be1a03cf1e6f52a6959fc77eb
|
||||
F ext/fts5/extract_api_docs.tcl bc3a0ca78be7d3df08e7602c00ca48021ebae40682d75eb001bfdf6e54ffb44e
|
||||
F ext/fts5/fts5.h 38a9553791828b3cf677b9347735fc531d54015ce4f5229d5cf1e2a5c1d3955a
|
||||
F ext/fts5/fts5Int.h b4a5ed934cb3da55737c4d75cb5f26a39b17470fca67c06c7fe6878992998c99
|
||||
F ext/fts5/fts5Int.h 330b1e2dad9ea9cccc9fa93817062fa21e89f00e7eac9a84be440f7e93bf7c3c
|
||||
F ext/fts5/fts5_aux.c 4584e88878e54828bf7d4d0d83deedd232ec60628b7731be02bad6adb62304b1
|
||||
F ext/fts5/fts5_buffer.c 0eec58bff585f1a44ea9147eae5da2447292080ea435957f7488c70673cb6f09
|
||||
F ext/fts5/fts5_config.c 0c96490fbad746b3780174f38b2ee5e3d719f2f81ee6b58ca828772871e0f680
|
||||
F ext/fts5/fts5_expr.c c7336d5f9ecc0e2b014d700be2bec0ea383b0e82c494a7c5c4ac622327c2bfad
|
||||
F ext/fts5/fts5_hash.c adda4272be401566a6e0ba1acbe70ee5cb97fce944bc2e04dc707152a0ec91b1
|
||||
F ext/fts5/fts5_index.c eb9a0dda3bc6ef969a6be8d2746af56856e67251810ddba08622b45be8477abe
|
||||
F ext/fts5/fts5_main.c 5b6f85aae5f25ee4e8762f26eb8c998c9c53443bb56483ebf712aca591bcb41e
|
||||
F ext/fts5/fts5_storage.c 1d7b358af3d4a7a4c5a7258a847229ca54c1b26d4f1b9e971ea5f2539631c3d4
|
||||
F ext/fts5/fts5_main.c f08525b3378b9131f76b415b44b882aa9f0a861fb135caaf3faf6a9ba5a409a1
|
||||
F ext/fts5/fts5_storage.c 6beefaa9229193e85fe9b920aa62f46a79cac867feb8a5af8ce6df28dec90e8d
|
||||
F ext/fts5/fts5_tcl.c a1c307785bb505735a8d914fff7d08881e64ba28c40c406b218c591010d1bc9e
|
||||
F ext/fts5/fts5_test_mi.c 08c11ec968148d4cb4119d96d819f8c1f329812c568bac3684f5464be177d3ee
|
||||
F ext/fts5/fts5_test_tok.c 3cb0a9b508b30d17ef025ccddd26ae3dc8ddffbe76c057616e59a9aa85d36f3b
|
||||
@@ -184,7 +184,7 @@ F ext/fts5/test/fts5interrupt.test 09613247b273a99889808ef852898177e671406fe71fd
|
||||
F ext/fts5/test/fts5lastrowid.test f36298a1fb9f988bde060a274a7ce638faa9c38a31400f8d2d27ea9373e0c4a1
|
||||
F ext/fts5/test/fts5leftjoin.test c0b4cafb9661379e576dc4405c0891d8fcc2782680740513c4d1fc114b43d4ad
|
||||
F ext/fts5/test/fts5limits.test 8ab67cf5d311c124b6ceb0062d0297767176df4572d955fce79fa43004dff01c
|
||||
F ext/fts5/test/fts5locale.test 92c6ae79df0aa57b379c50e400151f4a9a36d292819beefc31019c749249844a
|
||||
F ext/fts5/test/fts5locale.test 60217c6f67331e2b3218b4da3f96f54b856a341b23e7328c9f30efe9ca343130
|
||||
F ext/fts5/test/fts5matchinfo.test 877520582feb86bbfd95ab780099bcba4526f18ac75ee34979144cf86ba3a5a3
|
||||
F ext/fts5/test/fts5merge.test 2654df0bcdb2d117c2d38b6aeb0168061be01c643f9e9194b36c43a2970e8082
|
||||
F ext/fts5/test/fts5merge2.test 3ebad1a59d6ad3fb66eff6523a09e95dc6367cbefb3cd73196801dea0425c8e2
|
||||
@@ -222,7 +222,7 @@ F ext/fts5/test/fts5secure6.test 74bf04733cc523bccca519bb03d3b4e2ed6f6e3db7c59bf
|
||||
F ext/fts5/test/fts5secure7.test fd03d0868d64340a1db8615b02e5508fea409de13910114e4f19eaefc120777a
|
||||
F ext/fts5/test/fts5secure8.test e68c0ac4447f415ff3e4e82531e99548289286f9f3a29c8cd53036113fe28602
|
||||
F ext/fts5/test/fts5securefault.test c34a28c7cd2f31a8b8907563889e1329a97da975c08df2d951422bcef8e2ebc5
|
||||
F ext/fts5/test/fts5simple.test 847fb828262328744733847dc76d6b5d4a6bd4c5d9b282cb819f6504340e061a
|
||||
F ext/fts5/test/fts5simple.test 453b2348193911c2d51c208bfe247a09b936c4ddd9a836160495a5554340c256
|
||||
F ext/fts5/test/fts5simple2.test d10d963a357b8ec77b99032e4c816459b4dbdb1f6eee25eada7ef3ed245cb2dc
|
||||
F ext/fts5/test/fts5simple3.test 146ec3dc8f5763d6212641c9f0a2f1cba41679353d2add7b963beceb115dc7f4
|
||||
F ext/fts5/test/fts5synonym.test becc8cea6cfc958a50b30c572c68cbfdf7455971d0fe988202ce67638d2c6cf6
|
||||
@@ -2196,11 +2196,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P bcc31846964102385d5a21eb5e85d7db153b155e76b4e2847c9453d3d0e1af04
|
||||
R f9f51b6d625a93fd57b76dfee17ab828
|
||||
T *branch * fts5-locale
|
||||
T *sym-fts5-locale *
|
||||
T -sym-trunk *
|
||||
P 8839ef7cfb49239e7f1c4812a53a93a672827c88d6921408b1d5062b352c87cc
|
||||
R 8e79393df1bdcc86ce7609abeba8cbda
|
||||
U dan
|
||||
Z 2b42cc25153434047e86f4740a226c4e
|
||||
Z 68a8dc4d8e1906054989de2a0038cabe
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
8839ef7cfb49239e7f1c4812a53a93a672827c88d6921408b1d5062b352c87cc
|
||||
69205264debd829573b1c777a5a493cfeb6083c4cdec106b1f819989f859ac75
|
||||
|
||||
Reference in New Issue
Block a user