Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Fixes for updates and deletes on tables with fts5 indexes. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
8161b139108fa7ea07ad0075049b00f0 |
User & Date: | dan 2012-12-24 15:32:08.881 |
Context
2012-12-26
| ||
19:40 | Modify where.c and so on to handle fts scans. Opcodes do not work yet. check-in: 58a5617da3 user: dan tags: trunk | |
2012-12-24
| ||
15:32 | Fixes for updates and deletes on tables with fts5 indexes. check-in: 8161b13910 user: dan tags: trunk | |
2012-12-22
| ||
19:59 | More work on updating an fts5 index. Add a pragma that checks if the index and table contents match. check-in: 4693eb7bcc user: dan tags: trunk | |
Changes
Changes to src/delete.c.
︙ | ︙ | |||
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 | int bCount, /* Non-zero to increment change counter */ int baseCur, /* Cursor number for the table */ int *aRegIdx /* Only delete if (aRegIdx && aRegIdx[i]>0) */ ){ Vdbe *v = pParse->pVdbe; Index *pPk; int iPk; int i; int regKey; Index *pIdx; regKey = sqlite4GetTempReg(pParse); pPk = sqlite4FindPrimaryKey(pTab, &iPk); for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ | > > > > > > > > > > > | | 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 | int bCount, /* Non-zero to increment change counter */ int baseCur, /* Cursor number for the table */ int *aRegIdx /* Only delete if (aRegIdx && aRegIdx[i]>0) */ ){ Vdbe *v = pParse->pVdbe; Index *pPk; int iPk; int iPkCsr; int i; int regKey; Index *pIdx; regKey = sqlite4GetTempReg(pParse); pPk = sqlite4FindPrimaryKey(pTab, &iPk); iPkCsr = baseCur+iPk; for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){ if( pIdx->eIndexType==SQLITE4_INDEX_FTS5 ){ int iCol; int iReg = pParse->nMem+1; pParse->nMem += (1 + pTab->nCol); for(iCol=0; iCol<pTab->nCol; iCol++){ sqlite4VdbeAddOp3(v, OP_Column, iPkCsr, iCol, iReg+iCol); } sqlite4VdbeAddOp2(v, OP_RowKey, iPkCsr, iReg+pTab->nCol); sqlite4Fts5CodeUpdate(pParse, pIdx, iReg+pTab->nCol, iReg, 1); }else if( pIdx!=pPk && (aRegIdx==0 || aRegIdx[i]>0) ){ int addrNotFound; sqlite4EncodeIndexKey(pParse, pPk, baseCur+iPk, pIdx, baseCur+i,0,regKey); addrNotFound = sqlite4VdbeAddOp4(v, OP_NotFound, baseCur+i, 0, regKey, 0, P4_INT32 ); sqlite4VdbeAddOp1(v, OP_Delete, baseCur+i); sqlite4VdbeJumpHere(v, addrNotFound); |
︙ | ︙ |
Changes to src/fts5.c.
︙ | ︙ | |||
1090 1091 1092 1093 1094 1095 1096 | nKey += nToken; aKey[nKey++] = 0x00; memcpy(&aKey[nKey], pPK, nPK); nKey += nPK; if( bDel ){ /* delete key aKey/nKey... */ | | | 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 | nKey += nToken; aKey[nKey++] = 0x00; memcpy(&aKey[nKey], pPK, nPK); nKey += nPK; if( bDel ){ /* delete key aKey/nKey... */ rc = sqlite4KVStoreReplace(pStore, aKey, nKey, 0, -1); }else{ const KVByteArray *aData = (const KVByteArray *)&pTerm[1]; aData += pTerm->nToken; rc = sqlite4KVStoreReplace(pStore, aKey, nKey, aData, pTerm->nData); } } sqlite4DbFree(db, pTerm); |
︙ | ︙ | |||
1131 1132 1133 1134 1135 1136 1137 | } void sqlite4Fts5CodeUpdate( Parse *pParse, Index *pIdx, int iRegPk, | | > > | 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 | } void sqlite4Fts5CodeUpdate( Parse *pParse, Index *pIdx, int iRegPk, int iRegData, int bDel ){ Vdbe *v; Fts5Info *pInfo; /* p4 argument for FtsUpdate opcode */ if( 0==(pInfo = fts5InfoCreate(pParse, pIdx)) ) return; v = sqlite4GetVdbe(pParse); sqlite4VdbeAddOp3(v, OP_FtsUpdate, iRegPk, 0, iRegData); sqlite4VdbeChangeP4(v, -1, (const char *)pInfo, P4_FTS5INFO); sqlite4VdbeChangeP5(v, (u8)bDel); } void sqlite4Fts5FreeInfo(sqlite4 *db, Fts5Info *p){ if( db->pnBytesFreed==0 ){ if( p->p ) p->pTokenizer->xDestroy(p->p); sqlite4DbFree(db, p); } |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
1418 1419 1420 1421 1422 1423 1424 | /* Write the entry to each index. */ for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ assert( pIdx->eIndexType!=SQLITE4_INDEX_PRIMARYKEY || aRegIdx[i] ); if( pIdx->eIndexType==SQLITE4_INDEX_FTS5 ){ int iPK; sqlite4FindPrimaryKey(pTab, &iPK); | | | 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 | /* Write the entry to each index. */ for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ assert( pIdx->eIndexType!=SQLITE4_INDEX_PRIMARYKEY || aRegIdx[i] ); if( pIdx->eIndexType==SQLITE4_INDEX_FTS5 ){ int iPK; sqlite4FindPrimaryKey(pTab, &iPK); sqlite4Fts5CodeUpdate(pParse, pIdx, aRegIdx[iPK], regContent, 0); } else if( aRegIdx[i] ){ int regData = 0; int flags = 0; if( pIdx->eIndexType==SQLITE4_INDEX_PRIMARYKEY ){ regData = regRec; flags = pik_flags; |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
3267 3268 3269 3270 3271 3272 3273 | int sqlite4Fts5IndexSz(void); void sqlite4Fts5IndexInit(Parse *, Index *, ExprList *); void sqlite4Fts5IndexFree(sqlite4 *, Index *); int sqlite4Fts5Update(sqlite4 *, Fts5Info *, Mem *pPk, Mem *aArg, int, char **); void sqlite4Fts5FreeInfo(sqlite4 *db, Fts5Info *); | | | 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 | int sqlite4Fts5IndexSz(void); void sqlite4Fts5IndexInit(Parse *, Index *, ExprList *); void sqlite4Fts5IndexFree(sqlite4 *, Index *); int sqlite4Fts5Update(sqlite4 *, Fts5Info *, Mem *pPk, Mem *aArg, int, char **); void sqlite4Fts5FreeInfo(sqlite4 *db, Fts5Info *); void sqlite4Fts5CodeUpdate(Parse *, Index *pIdx, int iRegPk, int iRegData, int); void sqlite4Fts5CodeCksum(Parse *, Index *, int, int, int); #endif /* _SQLITEINT_H_ */ |
Changes to src/update.c.
︙ | ︙ | |||
504 505 506 507 508 509 510 | /* Delete the index entries associated with the current record. */ j1 = sqlite4VdbeAddOp4(v, OP_NotFound, iCur+iPk, 0, regOldKey, 0, P4_INT32); sqlite4GenerateRowIndexDelete(pParse, pTab, 0, iCur, aRegIdx); /* Delete the old record */ if( hasFK || bChngPk ){ | | | 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 | /* Delete the index entries associated with the current record. */ j1 = sqlite4VdbeAddOp4(v, OP_NotFound, iCur+iPk, 0, regOldKey, 0, P4_INT32); sqlite4GenerateRowIndexDelete(pParse, pTab, 0, iCur, aRegIdx); /* Delete the old record */ if( hasFK || bChngPk ){ sqlite4VdbeAddOp2(v, OP_Delete, iCur+iPk, 0); } sqlite4VdbeJumpHere(v, j1); if( hasFK ){ sqlite4FkCheck(pParse, pTab, 0, regNew); } |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 | int bDist = !!pDistinct; /* True if index cannot help with DISTINCT */ int bLookup = 0; /* True if not the PK index */ WhereTerm *pTerm; /* A single term of the WHERE clause */ #ifdef SQLITE4_ENABLE_STAT3 WhereTerm *pFirstTerm = 0; /* First term matching the index */ #endif int nCol = pProbe->nColumn; /* Total columns in index record */ /* Unless pProbe is the primary key index, then the encoded PK column ** values are at the end of each record. Set variable nCol to the total ** number of columns encoded into each index record, including the PK ** columns. */ if( pProbe!=pPk ) nCol += pPk->nColumn; | > > | 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 | int bDist = !!pDistinct; /* True if index cannot help with DISTINCT */ int bLookup = 0; /* True if not the PK index */ WhereTerm *pTerm; /* A single term of the WHERE clause */ #ifdef SQLITE4_ENABLE_STAT3 WhereTerm *pFirstTerm = 0; /* First term matching the index */ #endif int nCol = pProbe->nColumn; /* Total columns in index record */ if( pProbe->eIndexType==SQLITE4_INDEX_FTS5 ) continue; /* Unless pProbe is the primary key index, then the encoded PK column ** values are at the end of each record. Set variable nCol to the total ** number of columns encoded into each index record, including the PK ** columns. */ if( pProbe!=pPk ) nCol += pPk->nColumn; |
︙ | ︙ |
Added test/fts5query1.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | # 2012 December 17 # # 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. # #************************************************************************* # # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix fts5query1 do_execsql_test 1.0 { CREATE TABLE t1(a PRIMARY KEY, b, c); CREATE INDEX i1 ON t1 USING fts5(); } foreach {tn stmt} { 1 "INSERT INTO t1 VALUES(1, 'a b c', 'd e f')" 2 "INSERT INTO t1 VALUES(2, 'b c e', 'A A a')" 3 "INSERT INTO t1 VALUES(3, 'd A A', 'e c a')" 4 "DELETE FROM t1 WHERE a=1" 5 "DELETE FROM t1" 6 "INSERT INTO t1 VALUES(1, 'May you do', 'good and not evil')" 7 "INSERT INTO t1 VALUES(2, 'May you find', 'forgiveness for yourself')" 8 "UPDATE t1 SET b = 'and forgive others' WHERE a = 2" 9 "UPDATE t1 SET a = 4 AND c = 'a b c d' WHERE a = 2" } { do_execsql_test 1.$tn.1 $stmt do_execsql_test 1.$tn.2 {PRAGMA fts_check(i1)} ok } finish_test |