Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | More work on updating an fts5 index. Add a pragma that checks if the index and table contents match. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
4693eb7bcc6714f4bd44d03af7f736e9 |
User & Date: | dan 2012-12-22 19:59:46.127 |
Context
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 | |
2012-12-21
| ||
19:58 | Add update function to fts5.c. check-in: 49eff5d82d user: dan tags: trunk | |
Changes
Changes to src/fts5.c.
︙ | ︙ | |||
741 742 743 744 745 746 747 | static void fts5TokenizerCreate( Parse *pParse, Fts5Index *pFts, Fts5Tokenizer **ppTokenizer, sqlite4_tokenizer **pp ){ Fts5Tokenizer *pTok; | > > > > > | > > > > > > | > < | | 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 | static void fts5TokenizerCreate( Parse *pParse, Fts5Index *pFts, Fts5Tokenizer **ppTokenizer, sqlite4_tokenizer **pp ){ Fts5Tokenizer *pTok; char *zTok; /* Tokenizer name */ const char **azArg; /* Tokenizer arguments */ int nArg; /* Number of elements in azArg */ if( pFts->nTokenizer ){ zTok = pFts->azTokenizer[0]; azArg = (const char **)&pFts->azTokenizer[1]; nArg = pFts->nTokenizer-1; }else{ zTok = "simple"; azArg = 0; nArg = 0; } *ppTokenizer = pTok = fts5FindTokenizer(pParse->db, zTok); if( !pTok ){ sqlite4ErrorMsg(pParse, "no such tokenizer: \"%s\"", zTok); }else{ int rc = pTok->xCreate(pTok->pCtx, azArg, nArg, pp); if( rc!=SQLITE4_OK ){ assert( *pp==0 ); sqlite4ErrorMsg(pParse, "error creating tokenizer"); } } } |
︙ | ︙ | |||
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 | } /* ** Context structure passed to tokenizer callback when tokenizing a document. ** ** The hash table maps between tokens and TokenizeTerm structures. */ typedef struct TokenizeCtx TokenizeCtx; typedef struct TokenizeTerm TokenizeTerm; struct TokenizeCtx { int rc; int iCol; sqlite4 *db; int nMax; Hash hash; }; struct TokenizeTerm { int iWeight; /* Weight of previous entry */ int iCol; /* Column containing previous entry */ int iOff; /* Token offset of previous entry */ int nData; /* Bytes of data in value */ int nAlloc; /* Bytes of data allocated */ }; TokenizeTerm *fts5TokenizeAppendInt( TokenizeCtx *p, TokenizeTerm *pTerm, int iVal ){ unsigned char *a; | > > > > > > > > > > > | > | | | < > | > | | > > | | 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 | } /* ** Context structure passed to tokenizer callback when tokenizing a document. ** ** The hash table maps between tokens and TokenizeTerm structures. ** ** TokenizeTerm structures are allocated using sqlite4DbMalloc(). Immediately ** following the structure in memory is the token itself (TokenizeTerm.nToken ** bytes of data). Following this is the list of token instances in the same ** format as it is stored in the database. ** ** All of the above is a single allocation, size TokenizeTerm.nAlloc bytes. ** If the initial allocation is too small, it is extended using ** sqlite4DbRealloc(). */ typedef struct TokenizeCtx TokenizeCtx; typedef struct TokenizeTerm TokenizeTerm; struct TokenizeCtx { int rc; int iCol; sqlite4 *db; int nMax; Hash hash; }; struct TokenizeTerm { int iWeight; /* Weight of previous entry */ int iCol; /* Column containing previous entry */ int iOff; /* Token offset of previous entry */ int nToken; /* Size of token in bytes */ int nData; /* Bytes of data in value */ int nAlloc; /* Bytes of data allocated */ }; TokenizeTerm *fts5TokenizeAppendInt( TokenizeCtx *p, TokenizeTerm *pTerm, int iVal ){ unsigned char *a; int nSpace = pTerm->nAlloc-pTerm->nData-pTerm->nToken-sizeof(TokenizeTerm); if( nSpace < 5 ){ int nAlloc = (pTerm->nAlloc<256) ? 256 : pTerm->nAlloc * 2; pTerm = sqlite4DbReallocOrFree(p->db, pTerm, nAlloc); if( !pTerm ) return 0; pTerm->nAlloc = sqlite4DbMallocSize(p->db, pTerm); } a = &(((unsigned char *)&pTerm[1])[pTerm->nToken+pTerm->nData]); pTerm->nData += putVarint32(a, iVal); return pTerm; } static int fts5TokenizeCb( void *pCtx, int iWeight, int iOff, const char *zToken, int nToken, int iSrc, int nSrc ){ TokenizeCtx *p = (TokenizeCtx *)pCtx; TokenizeTerm *pTerm = 0; TokenizeTerm *pOrig = 0; if( nToken>p->nMax ) p->nMax = nToken; pTerm = (TokenizeTerm *)sqlite4HashFind(&p->hash, zToken, nToken); if( pTerm==0 ){ /* Size the initial allocation so that it fits in the lookaside buffer */ int nAlloc = sizeof(TokenizeTerm) + nToken + 32; pTerm = sqlite4DbMallocZero(p->db, nAlloc); if( pTerm ){ void *pFree; pTerm->nAlloc = sqlite4DbMallocSize(p->db, pTerm); pTerm->nToken = nToken; memcpy(&pTerm[1], zToken, nToken); pFree = sqlite4HashInsert(&p->hash, (char *)&pTerm[1], nToken, pTerm); if( pFree ){ sqlite4DbFree(p->db, pFree); pTerm = 0; } if( pTerm==0 ) goto tokenize_cb_out; } } |
︙ | ︙ | |||
982 983 984 985 986 987 988 | pTerm = fts5TokenizeAppendInt(p, pTerm, (iOff-pTerm->iOff) << 1); if( !pTerm ) goto tokenize_cb_out; pTerm->iOff = iOff; tokenize_cb_out: if( pTerm!=pOrig ){ | | > > > | | | | > > > > | | | 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 | pTerm = fts5TokenizeAppendInt(p, pTerm, (iOff-pTerm->iOff) << 1); if( !pTerm ) goto tokenize_cb_out; pTerm->iOff = iOff; tokenize_cb_out: if( pTerm!=pOrig ){ sqlite4HashInsert(&p->hash, (char *)&pTerm[1], nToken, pTerm); } if( !pTerm ){ p->rc = SQLITE4_NOMEM; return 1; } return 0; } /* ** Update an fts index. */ int sqlite4Fts5Update( sqlite4 *db, /* Database handle */ Fts5Info *pInfo, /* Description of fts index to update */ Mem *pKey, /* Primary key blob */ Mem *aArg, /* Array of arguments (see above) */ int bDel, /* True for a delete, false for insert */ char **pzErr /* OUT: Error message */ ){ int i; int rc = SQLITE4_OK; KVStore *pStore; TokenizeCtx sCtx; u8 *aKey = 0; int nKey = 0; int nTnum = 0; u32 dummy = 0; const u8 *pPK; int nPK; HashElem *pElem; pStore = db->aDb[pInfo->iDb].pKV; sCtx.rc = SQLITE4_OK; sCtx.db = db; sCtx.nMax = 0; sqlite4HashInit(db->pEnv, &sCtx.hash); pPK = (const u8 *)sqlite4_value_blob(pKey); nPK = sqlite4_value_bytes(pKey); nTnum = getVarint32(pPK, dummy); nPK -= nTnum; pPK += nTnum; for(i=0; rc==SQLITE4_OK && i<pInfo->nCol; i++){ sqlite4_value *pArg = (sqlite4_value *)(&aArg[i]); if( pArg->flags & MEM_Str ){ const char *zText; int nText; zText = (const char *)sqlite4_value_text(pArg); nText = sqlite4_value_bytes(pArg); sCtx.iCol = i; rc = pInfo->pTokenizer->xTokenize( |
︙ | ︙ | |||
1047 1048 1049 1050 1051 1052 1053 | for(pElem=sqliteHashFirst(&sCtx.hash); pElem; pElem=sqliteHashNext(pElem)){ TokenizeTerm *pTerm = (TokenizeTerm *)sqliteHashData(pElem); if( rc==SQLITE4_OK ){ int nToken = sqliteHashKeysize(pElem); char *zToken = (char *)sqliteHashKey(pElem); | | > < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 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 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 | for(pElem=sqliteHashFirst(&sCtx.hash); pElem; pElem=sqliteHashNext(pElem)){ TokenizeTerm *pTerm = (TokenizeTerm *)sqliteHashData(pElem); if( rc==SQLITE4_OK ){ int nToken = sqliteHashKeysize(pElem); char *zToken = (char *)sqliteHashKey(pElem); nKey = putVarint32(aKey, pInfo->iRoot); aKey[nKey++] = 0x24; memcpy(&aKey[nKey], zToken, nToken); nKey += nToken; aKey[nKey++] = 0x00; memcpy(&aKey[nKey], pPK, nPK); nKey += nPK; if( bDel ){ /* delete key aKey/nKey... */ assert( 0 ); }else{ const KVByteArray *aData = (const KVByteArray *)&pTerm[1]; aData += pTerm->nToken; rc = sqlite4KVStoreReplace(pStore, aKey, nKey, aData, pTerm->nData); } } sqlite4DbFree(db, pTerm); } sqlite4DbFree(db, aKey); sqlite4HashClear(&sCtx.hash); return rc; } static Fts5Info *fts5InfoCreate(Parse *pParse, Index *pIdx){ sqlite4 *db = pParse->db; Fts5Info *pInfo; /* p4 argument for FtsUpdate opcode */ pInfo = sqlite4DbMallocZero(db, sizeof(Fts5Info)); if( pInfo ){ pInfo->iDb = sqlite4SchemaToIndex(db, pIdx->pSchema); pInfo->iRoot = pIdx->tnum; pInfo->nCol = pIdx->pTable->nCol; fts5TokenizerCreate(pParse, pIdx->pFts, &pInfo->pTokenizer, &pInfo->p); if( pInfo->p==0 ){ assert( pParse->nErr ); sqlite4DbFree(db, pInfo); pInfo = 0; } } return pInfo; } void sqlite4Fts5CodeUpdate( Parse *pParse, Index *pIdx, int iRegPk, int iRegData ){ 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); } void sqlite4Fts5FreeInfo(sqlite4 *db, Fts5Info *p){ if( db->pnBytesFreed==0 ){ if( p->p ) p->pTokenizer->xDestroy(p->p); sqlite4DbFree(db, p); } } void sqlite4Fts5CodeCksum( Parse *pParse, Index *pIdx, int iCksum, int iReg, int bIdx /* True for fts index, false for table */ ){ Vdbe *v; Fts5Info *pInfo; /* p4 argument for FtsCksum opcode */ if( 0==(pInfo = fts5InfoCreate(pParse, pIdx)) ) return; v = sqlite4GetVdbe(pParse); sqlite4VdbeAddOp3(v, OP_FtsCksum, iCksum, 0, iReg); sqlite4VdbeChangeP4(v, -1, (const char *)pInfo, P4_FTS5INFO); sqlite4VdbeChangeP5(v, bIdx); } /* ** Calculate a 64-bit checksum for a term instance. The index checksum is ** the XOR of the checksum for each term instance in the table. A term ** instance checksum is calculated based on: ** ** * the term itself, ** * the pk of the row the instance appears in, ** * the weight assigned to the instance, ** * the column number, and ** * the term offset. */ static i64 fts5TermInstanceCksum( const u8 *aTerm, int nTerm, const u8 *aPk, int nPk, int iWeight, int iCol, int iOff ){ int i; i64 cksum = 0; /* Add the term to the checksum */ for(i=0; i<nTerm; i++){ cksum += (cksum << 3) + aTerm[i]; } /* Add the primary key blob to the checksum */ for(i=0; i<nPk; i++){ cksum += (cksum << 3) + aPk[i]; } /* Add the weight, column number and offset (in that order) to the checksum */ cksum += (cksum << 3) + iWeight; cksum += (cksum << 3) + iCol; cksum += (cksum << 3) + iOff; return cksum; } int sqlite4Fts5EntryCksum( sqlite4 *db, /* Database handle */ Fts5Info *p, /* Index description */ Mem *pKey, /* Database key */ Mem *pVal, /* Database value */ i64 *piCksum /* OUT: Checksum value */ ){ i64 cksum = 0; u8 const *aKey; int nKey; /* Key blob */ u8 const *aVal; int nVal; /* List of token instances */ u8 const *aToken; int nToken; /* Token for this entry */ u8 const *aPk; int nPk; /* Entry primary key blob */ int nTnum; u32 tnum; int iOff = 0; int iCol = 0; int iWeight = 0; int i = 0; aKey = (const u8 *)sqlite4_value_blob(pKey); nKey = sqlite4_value_bytes(pKey); aVal = (const u8 *)sqlite4_value_blob(pVal); nVal = sqlite4_value_bytes(pVal); /* Find the token and primary key blobs for this entry. */ nTnum = getVarint32(aKey, tnum); aToken = &aKey[nTnum+1]; nToken = sqlite4Strlen30((const char *)aToken); aPk = &aToken[nToken+1]; nPk = (&aKey[nKey] - aPk); while( i<nVal ){ u32 iVal; i += getVarint32(&aVal[i], iVal); if( (iVal & 0x03)==0x01 ){ iCol = (iVal>>2); iOff = 0; } else if( (iVal & 0x03)==0x03 ){ iWeight = (iVal>>2); } else{ i64 v; iOff += (iVal>>1); v = fts5TermInstanceCksum(aPk, nPk, aToken, nToken, iWeight, iCol, iOff); cksum = cksum ^ v; } } *piCksum = cksum; return SQLITE4_OK; } typedef struct CksumCtx CksumCtx; struct CksumCtx { const u8 *pPK; int nPK; int iCol; i64 cksum; }; static int fts5CksumCb( void *pCtx, int iWeight, int iOff, const char *zToken, int nToken, int iSrc, int nSrc ){ CksumCtx *p = (CksumCtx *)pCtx; i64 cksum; cksum = fts5TermInstanceCksum(p->pPK, p->nPK, (const u8 *)zToken, nToken, iWeight, p->iCol, iOff ); p->cksum = (p->cksum ^ cksum); return 0; } int sqlite4Fts5RowCksum( sqlite4 *db, /* Database handle */ Fts5Info *pInfo, /* Index description */ Mem *pKey, /* Primary key blob */ Mem *aArg, /* Array of column values */ i64 *piCksum /* OUT: Checksum value */ ){ int i; int rc = SQLITE4_OK; CksumCtx sCtx; int nTnum = 0; u32 dummy = 0; sCtx.cksum = 0; sCtx.pPK = (const u8 *)sqlite4_value_blob(pKey); sCtx.nPK = sqlite4_value_bytes(pKey); nTnum = getVarint32(sCtx.pPK, dummy); sCtx.nPK -= nTnum; sCtx.pPK += nTnum; for(i=0; rc==SQLITE4_OK && i<pInfo->nCol; i++){ sqlite4_value *pArg = (sqlite4_value *)(&aArg[i]); if( pArg->flags & MEM_Str ){ const char *zText; int nText; zText = (const char *)sqlite4_value_text(pArg); nText = sqlite4_value_bytes(pArg); sCtx.iCol = i; rc = pInfo->pTokenizer->xTokenize( &sCtx, pInfo->p, zText, nText, fts5CksumCb ); } } *piCksum = sCtx.cksum; return rc; } /************************************************************************** *************************************************************************** ** Below this point is test code. */ #ifdef SQLITE4_TEST static int fts5PrintExprNode(sqlite4 *, const char **, Fts5ExprNode *, char **); |
︙ | ︙ |
Changes to src/fts5func.c.
︙ | ︙ | |||
33 34 35 36 37 38 39 | } static int fts5SimpleTokenize( void *pCtx, sqlite4_tokenizer *p, const char *zDoc, int nDoc, | | > | | | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | } static int fts5SimpleTokenize( void *pCtx, sqlite4_tokenizer *p, const char *zDoc, int nDoc, int(*x)(void*, int, int, const char*, int, int, int) ){ sqlite4_env *pEnv = (sqlite4_env *)p; char *aBuf; int nBuf; int iBuf; int i; int brk = 0; int iOff = 0; nBuf = 128; aBuf = (char *)sqlite4_malloc(pEnv, nBuf); if( !aBuf ) return SQLITE4_NOMEM; iBuf = 0; for(i=0; brk==0 && i<nDoc; i++){ if( sqlite4Isalnum(zDoc[i]) ){ aBuf[iBuf++] = fts5Tolower(zDoc[i]); }else if( iBuf>0 ){ brk = x(pCtx, 0, iOff++, aBuf, iBuf, i-iBuf, iBuf); iBuf = 0; } } if( iBuf>0 ) x(pCtx, 0, iOff++, aBuf, iBuf, i-iBuf, iBuf); sqlite4_free(pEnv, aBuf); return SQLITE4_OK; } int sqlite4InitFts5Func(sqlite4 *db){ int rc; |
︙ | ︙ |
Changes to src/insert.c.
︙ | ︙ | |||
1415 1416 1417 1418 1419 1420 1421 | sqlite4VdbeAddOp3(v, OP_MakeRecord, regContent, pTab->nCol, regRec); sqlite4TableAffinityStr(v, pTab); sqlite4ExprCacheAffinityChange(pParse, regContent, pTab->nCol); /* 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] ); | > > > > > | | 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 | sqlite4VdbeAddOp3(v, OP_MakeRecord, regContent, pTab->nCol, regRec); sqlite4TableAffinityStr(v, pTab); sqlite4ExprCacheAffinityChange(pParse, regContent, pTab->nCol); /* 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); } else if( aRegIdx[i] ){ int regData = 0; int flags = 0; if( pIdx->eIndexType==SQLITE4_INDEX_PRIMARYKEY ){ regData = regRec; flags = pik_flags; } sqlite4VdbeAddOp3(v, OP_IdxInsert, baseCur+i, regData, aRegIdx[i]); |
︙ | ︙ |
Changes to src/pragma.c.
︙ | ︙ | |||
234 235 236 237 238 239 240 241 242 243 244 245 246 247 | if( sqlite4StrICmp(zLeft, "lsm_merge")==0 ){ int nPage = zRight ? sqlite4Atoi(zRight) : 1000; sqlite4_kvstore_control(db, zDb, SQLITE4_KVCTRL_LSM_MERGE, &nPage); returnSingleInt(pParse, "nWrite", (sqlite4_int64)nPage); }else #ifndef SQLITE4_OMIT_SCHEMA_PRAGMAS /* ** PRAGMA table_info(<table>) ** | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | if( sqlite4StrICmp(zLeft, "lsm_merge")==0 ){ int nPage = zRight ? sqlite4Atoi(zRight) : 1000; sqlite4_kvstore_control(db, zDb, SQLITE4_KVCTRL_LSM_MERGE, &nPage); returnSingleInt(pParse, "nWrite", (sqlite4_int64)nPage); }else /* ** PRAGMA fts_check(<index>) */ if( sqlite4StrICmp(zLeft, "fts_check")==0 && zRight ){ int iCksum1; int iCksum2; Index *pIdx; Table *pTab; Vdbe *v = sqlite4GetVdbe(pParse); if( v==0 || sqlite4ReadSchema(pParse) ) goto pragma_out; iCksum1 = ++pParse->nMem; iCksum2 = ++pParse->nMem; sqlite4VdbeAddOp2(v, OP_Integer, 0, iCksum1); sqlite4VdbeAddOp2(v, OP_Integer, 0, iCksum2); pIdx = sqlite4FindIndex(db, zRight, zDb); if( pIdx && pIdx->eIndexType==SQLITE4_INDEX_FTS5 ){ int iTab = pParse->nTab++; int iAddr; int iReg; int i; pTab = pIdx->pTable; sqlite4OpenPrimaryKey(pParse, iTab, iDb, pTab, OP_OpenRead); iAddr = sqlite4VdbeAddOp2(v, OP_Rewind, iTab, 0); iReg = pParse->nMem+1; pParse->nMem += (1 + pTab->nCol); sqlite4VdbeAddOp2(v, OP_RowKey, iTab, iReg); for(i=0; i<pTab->nCol; i++){ sqlite4VdbeAddOp3(v, OP_Column, iTab, i, iReg+1+i); } sqlite4Fts5CodeCksum(pParse, pIdx, iCksum1, iReg, 0); sqlite4VdbeAddOp2(v, OP_Next, iTab, iAddr+1); sqlite4VdbeJumpHere(v, iAddr); sqlite4VdbeAddOp1(v, OP_Close, iTab); sqlite4VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); iAddr = sqlite4VdbeAddOp2(v, OP_Rewind, iTab, 0); iReg = pParse->nMem+1; pParse->nMem += 2; sqlite4VdbeAddOp2(v, OP_RowKey, iTab, iReg); sqlite4VdbeAddOp2(v, OP_RowData, iTab, iReg+1); sqlite4Fts5CodeCksum(pParse, pIdx, iCksum2, iReg, 1); sqlite4VdbeAddOp2(v, OP_Next, iTab, iAddr+1); sqlite4VdbeJumpHere(v, iAddr); sqlite4VdbeAddOp1(v, OP_Close, iTab); iReg = ++pParse->nMem; sqlite4VdbeAddOp4(v, OP_String8, 0, iReg, 0, "ok", 0); iAddr = sqlite4VdbeAddOp3(v, OP_Eq, iCksum1, 0, iCksum2); sqlite4VdbeAddOp4(v, OP_String8, 0, iReg, 0, "error - cksum mismatch", 0); sqlite4VdbeJumpHere(v, iAddr); sqlite4VdbeAddOp2(v, OP_ResultRow, iReg, 1); sqlite4VdbeSetNumCols(v, 1); } } #ifndef SQLITE4_OMIT_SCHEMA_PRAGMAS /* ** PRAGMA table_info(<table>) ** |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
3265 3266 3267 3268 3269 3270 3271 | void sqlite4ShutdownFts5(sqlite4 *db); void sqlite4CreateUsingIndex(Parse*, CreateIndex*, ExprList*, Token*, Token*); int sqlite4Fts5IndexSz(void); void sqlite4Fts5IndexInit(Parse *, Index *, ExprList *); void sqlite4Fts5IndexFree(sqlite4 *, Index *); | | > > > | 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 | void sqlite4ShutdownFts5(sqlite4 *db); void sqlite4CreateUsingIndex(Parse*, CreateIndex*, ExprList*, Token*, Token*); 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); void sqlite4Fts5CodeCksum(Parse *, Index *, int, int, int); #endif /* _SQLITEINT_H_ */ |
Changes to src/vdbe.c.
︙ | ︙ | |||
4823 4824 4825 4826 4827 4828 4829 | sqlite4DebugPrintf("SQL-trace: %s\n", zTrace); } #endif /* SQLITE4_DEBUG */ break; } #endif | | > | | < | > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 | sqlite4DebugPrintf("SQL-trace: %s\n", zTrace); } #endif /* SQLITE4_DEBUG */ break; } #endif /* Opcode: FtsUpdate P1 * P3 P4 P5 ** ** This opcode is used to write to an FTS index. P4 points to an Fts5Info ** object describing the index. ** ** If argument P5 is non-zero, then entries are removed from the FTS index. ** If it is zero, then entries are inserted. In other words, when a row ** is deleted from a table with an FTS index, this opcode is invoked with ** P5==1. When a row is inserted, it is invoked with P5==0. If an existing ** row is updated, this opcode is invoked twice - once with P5==1 and then ** again with P5==0. ** ** Register P1 contains the PK (a blob in key format) of the affected row. ** P3 is the first in an array of N registers, where N is the number of ** columns in the indexed table. Each register contains the value for the ** corresponding table column. */ case OP_FtsUpdate: { Fts5Info *pInfo; /* Description of fts5 index to update */ Mem *pKey; /* Primary key of indexed row */ Mem *aArg; /* Pointer to array of N arguments */ assert( pOp->p4type==P4_FTS5INFO ); pInfo = pOp->p4.pFtsInfo; aArg = &aMem[pOp->p3]; pKey = &aMem[pOp->p1]; rc = sqlite4Fts5Update(db, pInfo, pKey, aArg, pOp->p5, &p->zErrMsg); break; } /* ** Opcode: FtsCksum P1 * P3 P4 P5 */ case OP_FtsCksum: { Fts5Info *pInfo; /* Description of fts5 index to update */ Mem *pKey; /* Primary key of row */ Mem *aArg; /* Pointer to array of N values */ i64 cksum; assert( pOp->p4type==P4_FTS5INFO ); pInfo = pOp->p4.pFtsInfo; pOut = &aMem[pOp->p1]; pKey = &aMem[pOp->p3]; aArg = &aMem[pOp->p3+1]; cksum = 0; if( pOp->p5 ){ sqlite4Fts5EntryCksum(db, pInfo, pKey, aArg, &cksum); pOut->u.i = pOut->u.i ^ cksum; }else{ sqlite4Fts5RowCksum(db, pInfo, pKey, aArg, &cksum); pOut->u.i = pOut->u.i ^ cksum; } break; } /* Opcode: Noop * * * * * ** ** Do nothing. This instruction is often useful as a jump |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
623 624 625 626 627 628 629 630 631 632 633 634 635 636 | sqlite4DbFree(db, p); } break; } case P4_VTAB : { if( db->pnBytesFreed==0 ) sqlite4VtabUnlock((VTable *)p4); break; } } } } /* ** Free the space allocated for aOp and any p4 values allocated for the | > > > > | 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 | sqlite4DbFree(db, p); } break; } case P4_VTAB : { if( db->pnBytesFreed==0 ) sqlite4VtabUnlock((VTable *)p4); break; } case P4_FTS5INFO : { sqlite4Fts5FreeInfo(db, (Fts5Info *)p4); break; } } } } /* ** Free the space allocated for aOp and any p4 values allocated for the |
︙ | ︙ |