Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: third_party/sqlite/sqlite-src-3100200/ext/fts5/fts5_storage.c

Issue 1610543003: [sql] Import reference version of SQLite 3.10.2. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 ** 2014 May 31
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
10 **
11 ******************************************************************************
12 **
13 */
14
15
16
17 #include "fts5Int.h"
18
19 struct Fts5Storage {
20 Fts5Config *pConfig;
21 Fts5Index *pIndex;
22 int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */
23 i64 nTotalRow; /* Total number of rows in FTS table */
24 i64 *aTotalSize; /* Total sizes of each column */
25 sqlite3_stmt *aStmt[11];
26 };
27
28
29 #if FTS5_STMT_SCAN_ASC!=0
30 # error "FTS5_STMT_SCAN_ASC mismatch"
31 #endif
32 #if FTS5_STMT_SCAN_DESC!=1
33 # error "FTS5_STMT_SCAN_DESC mismatch"
34 #endif
35 #if FTS5_STMT_LOOKUP!=2
36 # error "FTS5_STMT_LOOKUP mismatch"
37 #endif
38
39 #define FTS5_STMT_INSERT_CONTENT 3
40 #define FTS5_STMT_REPLACE_CONTENT 4
41 #define FTS5_STMT_DELETE_CONTENT 5
42 #define FTS5_STMT_REPLACE_DOCSIZE 6
43 #define FTS5_STMT_DELETE_DOCSIZE 7
44 #define FTS5_STMT_LOOKUP_DOCSIZE 8
45 #define FTS5_STMT_REPLACE_CONFIG 9
46 #define FTS5_STMT_SCAN 10
47
48 /*
49 ** Prepare the two insert statements - Fts5Storage.pInsertContent and
50 ** Fts5Storage.pInsertDocsize - if they have not already been prepared.
51 ** Return SQLITE_OK if successful, or an SQLite error code if an error
52 ** occurs.
53 */
54 static int fts5StorageGetStmt(
55 Fts5Storage *p, /* Storage handle */
56 int eStmt, /* FTS5_STMT_XXX constant */
57 sqlite3_stmt **ppStmt, /* OUT: Prepared statement handle */
58 char **pzErrMsg /* OUT: Error message (if any) */
59 ){
60 int rc = SQLITE_OK;
61
62 /* If there is no %_docsize table, there should be no requests for
63 ** statements to operate on it. */
64 assert( p->pConfig->bColumnsize || (
65 eStmt!=FTS5_STMT_REPLACE_DOCSIZE
66 && eStmt!=FTS5_STMT_DELETE_DOCSIZE
67 && eStmt!=FTS5_STMT_LOOKUP_DOCSIZE
68 ));
69
70 assert( eStmt>=0 && eStmt<ArraySize(p->aStmt) );
71 if( p->aStmt[eStmt]==0 ){
72 const char *azStmt[] = {
73 "SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC",
74 "SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC",
75 "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */
76
77 "INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */
78 "REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */
79 "DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */
80 "REPLACE INTO %Q.'%q_docsize' VALUES(?,?)", /* REPLACE_DOCSIZE */
81 "DELETE FROM %Q.'%q_docsize' WHERE id=?", /* DELETE_DOCSIZE */
82
83 "SELECT sz FROM %Q.'%q_docsize' WHERE id=?", /* LOOKUP_DOCSIZE */
84
85 "REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */
86 "SELECT %s FROM %s AS T", /* SCAN */
87 };
88 Fts5Config *pC = p->pConfig;
89 char *zSql = 0;
90
91 switch( eStmt ){
92 case FTS5_STMT_SCAN:
93 zSql = sqlite3_mprintf(azStmt[eStmt],
94 pC->zContentExprlist, pC->zContent
95 );
96 break;
97
98 case FTS5_STMT_SCAN_ASC:
99 case FTS5_STMT_SCAN_DESC:
100 zSql = sqlite3_mprintf(azStmt[eStmt], pC->zContentExprlist,
101 pC->zContent, pC->zContentRowid, pC->zContentRowid,
102 pC->zContentRowid
103 );
104 break;
105
106 case FTS5_STMT_LOOKUP:
107 zSql = sqlite3_mprintf(azStmt[eStmt],
108 pC->zContentExprlist, pC->zContent, pC->zContentRowid
109 );
110 break;
111
112 case FTS5_STMT_INSERT_CONTENT:
113 case FTS5_STMT_REPLACE_CONTENT: {
114 int nCol = pC->nCol + 1;
115 char *zBind;
116 int i;
117
118 zBind = sqlite3_malloc(1 + nCol*2);
119 if( zBind ){
120 for(i=0; i<nCol; i++){
121 zBind[i*2] = '?';
122 zBind[i*2 + 1] = ',';
123 }
124 zBind[i*2-1] = '\0';
125 zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName, zBind);
126 sqlite3_free(zBind);
127 }
128 break;
129 }
130
131 default:
132 zSql = sqlite3_mprintf(azStmt[eStmt], pC->zDb, pC->zName);
133 break;
134 }
135
136 if( zSql==0 ){
137 rc = SQLITE_NOMEM;
138 }else{
139 rc = sqlite3_prepare_v2(pC->db, zSql, -1, &p->aStmt[eStmt], 0);
140 sqlite3_free(zSql);
141 if( rc!=SQLITE_OK && pzErrMsg ){
142 *pzErrMsg = sqlite3_mprintf("%s", sqlite3_errmsg(pC->db));
143 }
144 }
145 }
146
147 *ppStmt = p->aStmt[eStmt];
148 return rc;
149 }
150
151
152 static int fts5ExecPrintf(
153 sqlite3 *db,
154 char **pzErr,
155 const char *zFormat,
156 ...
157 ){
158 int rc;
159 va_list ap; /* ... printf arguments */
160 char *zSql;
161
162 va_start(ap, zFormat);
163 zSql = sqlite3_vmprintf(zFormat, ap);
164
165 if( zSql==0 ){
166 rc = SQLITE_NOMEM;
167 }else{
168 rc = sqlite3_exec(db, zSql, 0, 0, pzErr);
169 sqlite3_free(zSql);
170 }
171
172 va_end(ap);
173 return rc;
174 }
175
176 /*
177 ** Drop all shadow tables. Return SQLITE_OK if successful or an SQLite error
178 ** code otherwise.
179 */
180 int sqlite3Fts5DropAll(Fts5Config *pConfig){
181 int rc = fts5ExecPrintf(pConfig->db, 0,
182 "DROP TABLE IF EXISTS %Q.'%q_data';"
183 "DROP TABLE IF EXISTS %Q.'%q_idx';"
184 "DROP TABLE IF EXISTS %Q.'%q_config';",
185 pConfig->zDb, pConfig->zName,
186 pConfig->zDb, pConfig->zName,
187 pConfig->zDb, pConfig->zName
188 );
189 if( rc==SQLITE_OK && pConfig->bColumnsize ){
190 rc = fts5ExecPrintf(pConfig->db, 0,
191 "DROP TABLE IF EXISTS %Q.'%q_docsize';",
192 pConfig->zDb, pConfig->zName
193 );
194 }
195 if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
196 rc = fts5ExecPrintf(pConfig->db, 0,
197 "DROP TABLE IF EXISTS %Q.'%q_content';",
198 pConfig->zDb, pConfig->zName
199 );
200 }
201 return rc;
202 }
203
204 static void fts5StorageRenameOne(
205 Fts5Config *pConfig, /* Current FTS5 configuration */
206 int *pRc, /* IN/OUT: Error code */
207 const char *zTail, /* Tail of table name e.g. "data", "config" */
208 const char *zName /* New name of FTS5 table */
209 ){
210 if( *pRc==SQLITE_OK ){
211 *pRc = fts5ExecPrintf(pConfig->db, 0,
212 "ALTER TABLE %Q.'%q_%s' RENAME TO '%q_%s';",
213 pConfig->zDb, pConfig->zName, zTail, zName, zTail
214 );
215 }
216 }
217
218 int sqlite3Fts5StorageRename(Fts5Storage *pStorage, const char *zName){
219 Fts5Config *pConfig = pStorage->pConfig;
220 int rc = sqlite3Fts5StorageSync(pStorage, 1);
221
222 fts5StorageRenameOne(pConfig, &rc, "data", zName);
223 fts5StorageRenameOne(pConfig, &rc, "idx", zName);
224 fts5StorageRenameOne(pConfig, &rc, "config", zName);
225 if( pConfig->bColumnsize ){
226 fts5StorageRenameOne(pConfig, &rc, "docsize", zName);
227 }
228 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
229 fts5StorageRenameOne(pConfig, &rc, "content", zName);
230 }
231 return rc;
232 }
233
234 /*
235 ** Create the shadow table named zPost, with definition zDefn. Return
236 ** SQLITE_OK if successful, or an SQLite error code otherwise.
237 */
238 int sqlite3Fts5CreateTable(
239 Fts5Config *pConfig, /* FTS5 configuration */
240 const char *zPost, /* Shadow table to create (e.g. "content") */
241 const char *zDefn, /* Columns etc. for shadow table */
242 int bWithout, /* True for without rowid */
243 char **pzErr /* OUT: Error message */
244 ){
245 int rc;
246 char *zErr = 0;
247
248 rc = fts5ExecPrintf(pConfig->db, &zErr, "CREATE TABLE %Q.'%q_%q'(%s)%s",
249 pConfig->zDb, pConfig->zName, zPost, zDefn, bWithout?" WITHOUT ROWID":""
250 );
251 if( zErr ){
252 *pzErr = sqlite3_mprintf(
253 "fts5: error creating shadow table %q_%s: %s",
254 pConfig->zName, zPost, zErr
255 );
256 sqlite3_free(zErr);
257 }
258
259 return rc;
260 }
261
262 /*
263 ** Open a new Fts5Index handle. If the bCreate argument is true, create
264 ** and initialize the underlying tables
265 **
266 ** If successful, set *pp to point to the new object and return SQLITE_OK.
267 ** Otherwise, set *pp to NULL and return an SQLite error code.
268 */
269 int sqlite3Fts5StorageOpen(
270 Fts5Config *pConfig,
271 Fts5Index *pIndex,
272 int bCreate,
273 Fts5Storage **pp,
274 char **pzErr /* OUT: Error message */
275 ){
276 int rc = SQLITE_OK;
277 Fts5Storage *p; /* New object */
278 int nByte; /* Bytes of space to allocate */
279
280 nByte = sizeof(Fts5Storage) /* Fts5Storage object */
281 + pConfig->nCol * sizeof(i64); /* Fts5Storage.aTotalSize[] */
282 *pp = p = (Fts5Storage*)sqlite3_malloc(nByte);
283 if( !p ) return SQLITE_NOMEM;
284
285 memset(p, 0, nByte);
286 p->aTotalSize = (i64*)&p[1];
287 p->pConfig = pConfig;
288 p->pIndex = pIndex;
289
290 if( bCreate ){
291 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
292 int nDefn = 32 + pConfig->nCol*10;
293 char *zDefn = sqlite3_malloc(32 + pConfig->nCol * 10);
294 if( zDefn==0 ){
295 rc = SQLITE_NOMEM;
296 }else{
297 int i;
298 int iOff;
299 sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY");
300 iOff = (int)strlen(zDefn);
301 for(i=0; i<pConfig->nCol; i++){
302 sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i);
303 iOff += (int)strlen(&zDefn[iOff]);
304 }
305 rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr);
306 }
307 sqlite3_free(zDefn);
308 }
309
310 if( rc==SQLITE_OK && pConfig->bColumnsize ){
311 rc = sqlite3Fts5CreateTable(
312 pConfig, "docsize", "id INTEGER PRIMARY KEY, sz BLOB", 0, pzErr
313 );
314 }
315 if( rc==SQLITE_OK ){
316 rc = sqlite3Fts5CreateTable(
317 pConfig, "config", "k PRIMARY KEY, v", 1, pzErr
318 );
319 }
320 if( rc==SQLITE_OK ){
321 rc = sqlite3Fts5StorageConfigValue(p, "version", 0, FTS5_CURRENT_VERSION);
322 }
323 }
324
325 if( rc ){
326 sqlite3Fts5StorageClose(p);
327 *pp = 0;
328 }
329 return rc;
330 }
331
332 /*
333 ** Close a handle opened by an earlier call to sqlite3Fts5StorageOpen().
334 */
335 int sqlite3Fts5StorageClose(Fts5Storage *p){
336 int rc = SQLITE_OK;
337 if( p ){
338 int i;
339
340 /* Finalize all SQL statements */
341 for(i=0; i<(int)ArraySize(p->aStmt); i++){
342 sqlite3_finalize(p->aStmt[i]);
343 }
344
345 sqlite3_free(p);
346 }
347 return rc;
348 }
349
350 typedef struct Fts5InsertCtx Fts5InsertCtx;
351 struct Fts5InsertCtx {
352 Fts5Storage *pStorage;
353 int iCol;
354 int szCol; /* Size of column value in tokens */
355 };
356
357 /*
358 ** Tokenization callback used when inserting tokens into the FTS index.
359 */
360 static int fts5StorageInsertCallback(
361 void *pContext, /* Pointer to Fts5InsertCtx object */
362 int tflags,
363 const char *pToken, /* Buffer containing token */
364 int nToken, /* Size of token in bytes */
365 int iStart, /* Start offset of token */
366 int iEnd /* End offset of token */
367 ){
368 Fts5InsertCtx *pCtx = (Fts5InsertCtx*)pContext;
369 Fts5Index *pIdx = pCtx->pStorage->pIndex;
370 if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
371 pCtx->szCol++;
372 }
373 return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken);
374 }
375
376 /*
377 ** If a row with rowid iDel is present in the %_content table, add the
378 ** delete-markers to the FTS index necessary to delete it. Do not actually
379 ** remove the %_content row at this time though.
380 */
381 static int fts5StorageDeleteFromIndex(Fts5Storage *p, i64 iDel){
382 Fts5Config *pConfig = p->pConfig;
383 sqlite3_stmt *pSeek; /* SELECT to read row iDel from %_data */
384 int rc; /* Return code */
385
386 rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0);
387 if( rc==SQLITE_OK ){
388 int rc2;
389 sqlite3_bind_int64(pSeek, 1, iDel);
390 if( sqlite3_step(pSeek)==SQLITE_ROW ){
391 int iCol;
392 Fts5InsertCtx ctx;
393 ctx.pStorage = p;
394 ctx.iCol = -1;
395 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
396 for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){
397 if( pConfig->abUnindexed[iCol-1] ) continue;
398 ctx.szCol = 0;
399 rc = sqlite3Fts5Tokenize(pConfig,
400 FTS5_TOKENIZE_DOCUMENT,
401 (const char*)sqlite3_column_text(pSeek, iCol),
402 sqlite3_column_bytes(pSeek, iCol),
403 (void*)&ctx,
404 fts5StorageInsertCallback
405 );
406 p->aTotalSize[iCol-1] -= (i64)ctx.szCol;
407 }
408 p->nTotalRow--;
409 }
410 rc2 = sqlite3_reset(pSeek);
411 if( rc==SQLITE_OK ) rc = rc2;
412 }
413
414 return rc;
415 }
416
417
418 /*
419 ** Insert a record into the %_docsize table. Specifically, do:
420 **
421 ** INSERT OR REPLACE INTO %_docsize(id, sz) VALUES(iRowid, pBuf);
422 **
423 ** If there is no %_docsize table (as happens if the columnsize=0 option
424 ** is specified when the FTS5 table is created), this function is a no-op.
425 */
426 static int fts5StorageInsertDocsize(
427 Fts5Storage *p, /* Storage module to write to */
428 i64 iRowid, /* id value */
429 Fts5Buffer *pBuf /* sz value */
430 ){
431 int rc = SQLITE_OK;
432 if( p->pConfig->bColumnsize ){
433 sqlite3_stmt *pReplace = 0;
434 rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
435 if( rc==SQLITE_OK ){
436 sqlite3_bind_int64(pReplace, 1, iRowid);
437 sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC);
438 sqlite3_step(pReplace);
439 rc = sqlite3_reset(pReplace);
440 }
441 }
442 return rc;
443 }
444
445 /*
446 ** Load the contents of the "averages" record from disk into the
447 ** p->nTotalRow and p->aTotalSize[] variables. If successful, and if
448 ** argument bCache is true, set the p->bTotalsValid flag to indicate
449 ** that the contents of aTotalSize[] and nTotalRow are valid until
450 ** further notice.
451 **
452 ** Return SQLITE_OK if successful, or an SQLite error code if an error
453 ** occurs.
454 */
455 static int fts5StorageLoadTotals(Fts5Storage *p, int bCache){
456 int rc = SQLITE_OK;
457 if( p->bTotalsValid==0 ){
458 rc = sqlite3Fts5IndexGetAverages(p->pIndex, &p->nTotalRow, p->aTotalSize);
459 p->bTotalsValid = bCache;
460 }
461 return rc;
462 }
463
464 /*
465 ** Store the current contents of the p->nTotalRow and p->aTotalSize[]
466 ** variables in the "averages" record on disk.
467 **
468 ** Return SQLITE_OK if successful, or an SQLite error code if an error
469 ** occurs.
470 */
471 static int fts5StorageSaveTotals(Fts5Storage *p){
472 int nCol = p->pConfig->nCol;
473 int i;
474 Fts5Buffer buf;
475 int rc = SQLITE_OK;
476 memset(&buf, 0, sizeof(buf));
477
478 sqlite3Fts5BufferAppendVarint(&rc, &buf, p->nTotalRow);
479 for(i=0; i<nCol; i++){
480 sqlite3Fts5BufferAppendVarint(&rc, &buf, p->aTotalSize[i]);
481 }
482 if( rc==SQLITE_OK ){
483 rc = sqlite3Fts5IndexSetAverages(p->pIndex, buf.p, buf.n);
484 }
485 sqlite3_free(buf.p);
486
487 return rc;
488 }
489
490 /*
491 ** Remove a row from the FTS table.
492 */
493 int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel){
494 Fts5Config *pConfig = p->pConfig;
495 int rc;
496 sqlite3_stmt *pDel = 0;
497
498 rc = fts5StorageLoadTotals(p, 1);
499
500 /* Delete the index records */
501 if( rc==SQLITE_OK ){
502 rc = fts5StorageDeleteFromIndex(p, iDel);
503 }
504
505 /* Delete the %_docsize record */
506 if( rc==SQLITE_OK && pConfig->bColumnsize ){
507 rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
508 if( rc==SQLITE_OK ){
509 sqlite3_bind_int64(pDel, 1, iDel);
510 sqlite3_step(pDel);
511 rc = sqlite3_reset(pDel);
512 }
513 }
514
515 /* Delete the %_content record */
516 if( pConfig->eContent==FTS5_CONTENT_NORMAL ){
517 if( rc==SQLITE_OK ){
518 rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_CONTENT, &pDel, 0);
519 }
520 if( rc==SQLITE_OK ){
521 sqlite3_bind_int64(pDel, 1, iDel);
522 sqlite3_step(pDel);
523 rc = sqlite3_reset(pDel);
524 }
525 }
526
527 /* Write the averages record */
528 if( rc==SQLITE_OK ){
529 rc = fts5StorageSaveTotals(p);
530 }
531
532 return rc;
533 }
534
535 int sqlite3Fts5StorageSpecialDelete(
536 Fts5Storage *p,
537 i64 iDel,
538 sqlite3_value **apVal
539 ){
540 Fts5Config *pConfig = p->pConfig;
541 int rc;
542 sqlite3_stmt *pDel = 0;
543
544 assert( pConfig->eContent!=FTS5_CONTENT_NORMAL );
545 rc = fts5StorageLoadTotals(p, 1);
546
547 /* Delete the index records */
548 if( rc==SQLITE_OK ){
549 int iCol;
550 Fts5InsertCtx ctx;
551 ctx.pStorage = p;
552 ctx.iCol = -1;
553
554 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 1, iDel);
555 for(iCol=0; rc==SQLITE_OK && iCol<pConfig->nCol; iCol++){
556 if( pConfig->abUnindexed[iCol] ) continue;
557 ctx.szCol = 0;
558 rc = sqlite3Fts5Tokenize(pConfig,
559 FTS5_TOKENIZE_DOCUMENT,
560 (const char*)sqlite3_value_text(apVal[iCol]),
561 sqlite3_value_bytes(apVal[iCol]),
562 (void*)&ctx,
563 fts5StorageInsertCallback
564 );
565 p->aTotalSize[iCol] -= (i64)ctx.szCol;
566 }
567 p->nTotalRow--;
568 }
569
570 /* Delete the %_docsize record */
571 if( pConfig->bColumnsize ){
572 if( rc==SQLITE_OK ){
573 rc = fts5StorageGetStmt(p, FTS5_STMT_DELETE_DOCSIZE, &pDel, 0);
574 }
575 if( rc==SQLITE_OK ){
576 sqlite3_bind_int64(pDel, 1, iDel);
577 sqlite3_step(pDel);
578 rc = sqlite3_reset(pDel);
579 }
580 }
581
582 /* Write the averages record */
583 if( rc==SQLITE_OK ){
584 rc = fts5StorageSaveTotals(p);
585 }
586
587 return rc;
588 }
589
590 /*
591 ** Delete all entries in the FTS5 index.
592 */
593 int sqlite3Fts5StorageDeleteAll(Fts5Storage *p){
594 Fts5Config *pConfig = p->pConfig;
595 int rc;
596
597 /* Delete the contents of the %_data and %_docsize tables. */
598 rc = fts5ExecPrintf(pConfig->db, 0,
599 "DELETE FROM %Q.'%q_data';"
600 "DELETE FROM %Q.'%q_idx';",
601 pConfig->zDb, pConfig->zName,
602 pConfig->zDb, pConfig->zName
603 );
604 if( rc==SQLITE_OK && pConfig->bColumnsize ){
605 rc = fts5ExecPrintf(pConfig->db, 0,
606 "DELETE FROM %Q.'%q_docsize';",
607 pConfig->zDb, pConfig->zName
608 );
609 }
610
611 /* Reinitialize the %_data table. This call creates the initial structure
612 ** and averages records. */
613 if( rc==SQLITE_OK ){
614 rc = sqlite3Fts5IndexReinit(p->pIndex);
615 }
616 if( rc==SQLITE_OK ){
617 rc = sqlite3Fts5StorageConfigValue(p, "version", 0, FTS5_CURRENT_VERSION);
618 }
619 return rc;
620 }
621
622 int sqlite3Fts5StorageRebuild(Fts5Storage *p){
623 Fts5Buffer buf = {0,0,0};
624 Fts5Config *pConfig = p->pConfig;
625 sqlite3_stmt *pScan = 0;
626 Fts5InsertCtx ctx;
627 int rc;
628
629 memset(&ctx, 0, sizeof(Fts5InsertCtx));
630 ctx.pStorage = p;
631 rc = sqlite3Fts5StorageDeleteAll(p);
632 if( rc==SQLITE_OK ){
633 rc = fts5StorageLoadTotals(p, 1);
634 }
635
636 if( rc==SQLITE_OK ){
637 rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
638 }
639
640 while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pScan) ){
641 i64 iRowid = sqlite3_column_int64(pScan, 0);
642
643 sqlite3Fts5BufferZero(&buf);
644 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
645 for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
646 ctx.szCol = 0;
647 if( pConfig->abUnindexed[ctx.iCol]==0 ){
648 rc = sqlite3Fts5Tokenize(pConfig,
649 FTS5_TOKENIZE_DOCUMENT,
650 (const char*)sqlite3_column_text(pScan, ctx.iCol+1),
651 sqlite3_column_bytes(pScan, ctx.iCol+1),
652 (void*)&ctx,
653 fts5StorageInsertCallback
654 );
655 }
656 sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
657 p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
658 }
659 p->nTotalRow++;
660
661 if( rc==SQLITE_OK ){
662 rc = fts5StorageInsertDocsize(p, iRowid, &buf);
663 }
664 }
665 sqlite3_free(buf.p);
666
667 /* Write the averages record */
668 if( rc==SQLITE_OK ){
669 rc = fts5StorageSaveTotals(p);
670 }
671 return rc;
672 }
673
674 int sqlite3Fts5StorageOptimize(Fts5Storage *p){
675 return sqlite3Fts5IndexOptimize(p->pIndex);
676 }
677
678 int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge){
679 return sqlite3Fts5IndexMerge(p->pIndex, nMerge);
680 }
681
682 /*
683 ** Allocate a new rowid. This is used for "external content" tables when
684 ** a NULL value is inserted into the rowid column. The new rowid is allocated
685 ** by inserting a dummy row into the %_docsize table. The dummy will be
686 ** overwritten later.
687 **
688 ** If the %_docsize table does not exist, SQLITE_MISMATCH is returned. In
689 ** this case the user is required to provide a rowid explicitly.
690 */
691 static int fts5StorageNewRowid(Fts5Storage *p, i64 *piRowid){
692 int rc = SQLITE_MISMATCH;
693 if( p->pConfig->bColumnsize ){
694 sqlite3_stmt *pReplace = 0;
695 rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_DOCSIZE, &pReplace, 0);
696 if( rc==SQLITE_OK ){
697 sqlite3_bind_null(pReplace, 1);
698 sqlite3_bind_null(pReplace, 2);
699 sqlite3_step(pReplace);
700 rc = sqlite3_reset(pReplace);
701 }
702 if( rc==SQLITE_OK ){
703 *piRowid = sqlite3_last_insert_rowid(p->pConfig->db);
704 }
705 }
706 return rc;
707 }
708
709 /*
710 ** Insert a new row into the FTS content table.
711 */
712 int sqlite3Fts5StorageContentInsert(
713 Fts5Storage *p,
714 sqlite3_value **apVal,
715 i64 *piRowid
716 ){
717 Fts5Config *pConfig = p->pConfig;
718 int rc = SQLITE_OK;
719
720 /* Insert the new row into the %_content table. */
721 if( pConfig->eContent!=FTS5_CONTENT_NORMAL ){
722 if( sqlite3_value_type(apVal[1])==SQLITE_INTEGER ){
723 *piRowid = sqlite3_value_int64(apVal[1]);
724 }else{
725 rc = fts5StorageNewRowid(p, piRowid);
726 }
727 }else{
728 sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */
729 int i; /* Counter variable */
730 rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0);
731 for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){
732 rc = sqlite3_bind_value(pInsert, i, apVal[i]);
733 }
734 if( rc==SQLITE_OK ){
735 sqlite3_step(pInsert);
736 rc = sqlite3_reset(pInsert);
737 }
738 *piRowid = sqlite3_last_insert_rowid(pConfig->db);
739 }
740
741 return rc;
742 }
743
744 /*
745 ** Insert new entries into the FTS index and %_docsize table.
746 */
747 int sqlite3Fts5StorageIndexInsert(
748 Fts5Storage *p,
749 sqlite3_value **apVal,
750 i64 iRowid
751 ){
752 Fts5Config *pConfig = p->pConfig;
753 int rc = SQLITE_OK; /* Return code */
754 Fts5InsertCtx ctx; /* Tokenization callback context object */
755 Fts5Buffer buf; /* Buffer used to build up %_docsize blob */
756
757 memset(&buf, 0, sizeof(Fts5Buffer));
758 ctx.pStorage = p;
759 rc = fts5StorageLoadTotals(p, 1);
760
761 if( rc==SQLITE_OK ){
762 rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid);
763 }
764 for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){
765 ctx.szCol = 0;
766 if( pConfig->abUnindexed[ctx.iCol]==0 ){
767 rc = sqlite3Fts5Tokenize(pConfig,
768 FTS5_TOKENIZE_DOCUMENT,
769 (const char*)sqlite3_value_text(apVal[ctx.iCol+2]),
770 sqlite3_value_bytes(apVal[ctx.iCol+2]),
771 (void*)&ctx,
772 fts5StorageInsertCallback
773 );
774 }
775 sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol);
776 p->aTotalSize[ctx.iCol] += (i64)ctx.szCol;
777 }
778 p->nTotalRow++;
779
780 /* Write the %_docsize record */
781 if( rc==SQLITE_OK ){
782 rc = fts5StorageInsertDocsize(p, iRowid, &buf);
783 }
784 sqlite3_free(buf.p);
785
786 /* Write the averages record */
787 if( rc==SQLITE_OK ){
788 rc = fts5StorageSaveTotals(p);
789 }
790
791 return rc;
792 }
793
794 static int fts5StorageCount(Fts5Storage *p, const char *zSuffix, i64 *pnRow){
795 Fts5Config *pConfig = p->pConfig;
796 char *zSql;
797 int rc;
798
799 zSql = sqlite3_mprintf("SELECT count(*) FROM %Q.'%q_%s'",
800 pConfig->zDb, pConfig->zName, zSuffix
801 );
802 if( zSql==0 ){
803 rc = SQLITE_NOMEM;
804 }else{
805 sqlite3_stmt *pCnt = 0;
806 rc = sqlite3_prepare_v2(pConfig->db, zSql, -1, &pCnt, 0);
807 if( rc==SQLITE_OK ){
808 if( SQLITE_ROW==sqlite3_step(pCnt) ){
809 *pnRow = sqlite3_column_int64(pCnt, 0);
810 }
811 rc = sqlite3_finalize(pCnt);
812 }
813 }
814
815 sqlite3_free(zSql);
816 return rc;
817 }
818
819 /*
820 ** Context object used by sqlite3Fts5StorageIntegrity().
821 */
822 typedef struct Fts5IntegrityCtx Fts5IntegrityCtx;
823 struct Fts5IntegrityCtx {
824 i64 iRowid;
825 int iCol;
826 int szCol;
827 u64 cksum;
828 Fts5Config *pConfig;
829 };
830
831 /*
832 ** Tokenization callback used by integrity check.
833 */
834 static int fts5StorageIntegrityCallback(
835 void *pContext, /* Pointer to Fts5InsertCtx object */
836 int tflags,
837 const char *pToken, /* Buffer containing token */
838 int nToken, /* Size of token in bytes */
839 int iStart, /* Start offset of token */
840 int iEnd /* End offset of token */
841 ){
842 Fts5IntegrityCtx *pCtx = (Fts5IntegrityCtx*)pContext;
843 if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){
844 pCtx->szCol++;
845 }
846 pCtx->cksum ^= sqlite3Fts5IndexCksum(
847 pCtx->pConfig, pCtx->iRowid, pCtx->iCol, pCtx->szCol-1, pToken, nToken
848 );
849 return SQLITE_OK;
850 }
851
852 /*
853 ** Check that the contents of the FTS index match that of the %_content
854 ** table. Return SQLITE_OK if they do, or SQLITE_CORRUPT if not. Return
855 ** some other SQLite error code if an error occurs while attempting to
856 ** determine this.
857 */
858 int sqlite3Fts5StorageIntegrity(Fts5Storage *p){
859 Fts5Config *pConfig = p->pConfig;
860 int rc; /* Return code */
861 int *aColSize; /* Array of size pConfig->nCol */
862 i64 *aTotalSize; /* Array of size pConfig->nCol */
863 Fts5IntegrityCtx ctx;
864 sqlite3_stmt *pScan;
865
866 memset(&ctx, 0, sizeof(Fts5IntegrityCtx));
867 ctx.pConfig = p->pConfig;
868 aTotalSize = (i64*)sqlite3_malloc(pConfig->nCol * (sizeof(int)+sizeof(i64)));
869 if( !aTotalSize ) return SQLITE_NOMEM;
870 aColSize = (int*)&aTotalSize[pConfig->nCol];
871 memset(aTotalSize, 0, sizeof(i64) * pConfig->nCol);
872
873 /* Generate the expected index checksum based on the contents of the
874 ** %_content table. This block stores the checksum in ctx.cksum. */
875 rc = fts5StorageGetStmt(p, FTS5_STMT_SCAN, &pScan, 0);
876 if( rc==SQLITE_OK ){
877 int rc2;
878 while( SQLITE_ROW==sqlite3_step(pScan) ){
879 int i;
880 ctx.iRowid = sqlite3_column_int64(pScan, 0);
881 ctx.szCol = 0;
882 if( pConfig->bColumnsize ){
883 rc = sqlite3Fts5StorageDocsize(p, ctx.iRowid, aColSize);
884 }
885 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
886 if( pConfig->abUnindexed[i] ) continue;
887 ctx.iCol = i;
888 ctx.szCol = 0;
889 rc = sqlite3Fts5Tokenize(pConfig,
890 FTS5_TOKENIZE_DOCUMENT,
891 (const char*)sqlite3_column_text(pScan, i+1),
892 sqlite3_column_bytes(pScan, i+1),
893 (void*)&ctx,
894 fts5StorageIntegrityCallback
895 );
896 if( pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){
897 rc = FTS5_CORRUPT;
898 }
899 aTotalSize[i] += ctx.szCol;
900 }
901 if( rc!=SQLITE_OK ) break;
902 }
903 rc2 = sqlite3_reset(pScan);
904 if( rc==SQLITE_OK ) rc = rc2;
905 }
906
907 /* Test that the "totals" (sometimes called "averages") record looks Ok */
908 if( rc==SQLITE_OK ){
909 int i;
910 rc = fts5StorageLoadTotals(p, 0);
911 for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){
912 if( p->aTotalSize[i]!=aTotalSize[i] ) rc = FTS5_CORRUPT;
913 }
914 }
915
916 /* Check that the %_docsize and %_content tables contain the expected
917 ** number of rows. */
918 if( rc==SQLITE_OK && pConfig->eContent==FTS5_CONTENT_NORMAL ){
919 i64 nRow = 0;
920 rc = fts5StorageCount(p, "content", &nRow);
921 if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
922 }
923 if( rc==SQLITE_OK && pConfig->bColumnsize ){
924 i64 nRow = 0;
925 rc = fts5StorageCount(p, "docsize", &nRow);
926 if( rc==SQLITE_OK && nRow!=p->nTotalRow ) rc = FTS5_CORRUPT;
927 }
928
929 /* Pass the expected checksum down to the FTS index module. It will
930 ** verify, amongst other things, that it matches the checksum generated by
931 ** inspecting the index itself. */
932 if( rc==SQLITE_OK ){
933 rc = sqlite3Fts5IndexIntegrityCheck(p->pIndex, ctx.cksum);
934 }
935
936 sqlite3_free(aTotalSize);
937 return rc;
938 }
939
940 /*
941 ** Obtain an SQLite statement handle that may be used to read data from the
942 ** %_content table.
943 */
944 int sqlite3Fts5StorageStmt(
945 Fts5Storage *p,
946 int eStmt,
947 sqlite3_stmt **pp,
948 char **pzErrMsg
949 ){
950 int rc;
951 assert( eStmt==FTS5_STMT_SCAN_ASC
952 || eStmt==FTS5_STMT_SCAN_DESC
953 || eStmt==FTS5_STMT_LOOKUP
954 );
955 rc = fts5StorageGetStmt(p, eStmt, pp, pzErrMsg);
956 if( rc==SQLITE_OK ){
957 assert( p->aStmt[eStmt]==*pp );
958 p->aStmt[eStmt] = 0;
959 }
960 return rc;
961 }
962
963 /*
964 ** Release an SQLite statement handle obtained via an earlier call to
965 ** sqlite3Fts5StorageStmt(). The eStmt parameter passed to this function
966 ** must match that passed to the sqlite3Fts5StorageStmt() call.
967 */
968 void sqlite3Fts5StorageStmtRelease(
969 Fts5Storage *p,
970 int eStmt,
971 sqlite3_stmt *pStmt
972 ){
973 assert( eStmt==FTS5_STMT_SCAN_ASC
974 || eStmt==FTS5_STMT_SCAN_DESC
975 || eStmt==FTS5_STMT_LOOKUP
976 );
977 if( p->aStmt[eStmt]==0 ){
978 sqlite3_reset(pStmt);
979 p->aStmt[eStmt] = pStmt;
980 }else{
981 sqlite3_finalize(pStmt);
982 }
983 }
984
985 static int fts5StorageDecodeSizeArray(
986 int *aCol, int nCol, /* Array to populate */
987 const u8 *aBlob, int nBlob /* Record to read varints from */
988 ){
989 int i;
990 int iOff = 0;
991 for(i=0; i<nCol; i++){
992 if( iOff>=nBlob ) return 1;
993 iOff += fts5GetVarint32(&aBlob[iOff], aCol[i]);
994 }
995 return (iOff!=nBlob);
996 }
997
998 /*
999 ** Argument aCol points to an array of integers containing one entry for
1000 ** each table column. This function reads the %_docsize record for the
1001 ** specified rowid and populates aCol[] with the results.
1002 **
1003 ** An SQLite error code is returned if an error occurs, or SQLITE_OK
1004 ** otherwise.
1005 */
1006 int sqlite3Fts5StorageDocsize(Fts5Storage *p, i64 iRowid, int *aCol){
1007 int nCol = p->pConfig->nCol; /* Number of user columns in table */
1008 sqlite3_stmt *pLookup = 0; /* Statement to query %_docsize */
1009 int rc; /* Return Code */
1010
1011 assert( p->pConfig->bColumnsize );
1012 rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP_DOCSIZE, &pLookup, 0);
1013 if( rc==SQLITE_OK ){
1014 int bCorrupt = 1;
1015 sqlite3_bind_int64(pLookup, 1, iRowid);
1016 if( SQLITE_ROW==sqlite3_step(pLookup) ){
1017 const u8 *aBlob = sqlite3_column_blob(pLookup, 0);
1018 int nBlob = sqlite3_column_bytes(pLookup, 0);
1019 if( 0==fts5StorageDecodeSizeArray(aCol, nCol, aBlob, nBlob) ){
1020 bCorrupt = 0;
1021 }
1022 }
1023 rc = sqlite3_reset(pLookup);
1024 if( bCorrupt && rc==SQLITE_OK ){
1025 rc = FTS5_CORRUPT;
1026 }
1027 }
1028
1029 return rc;
1030 }
1031
1032 int sqlite3Fts5StorageSize(Fts5Storage *p, int iCol, i64 *pnToken){
1033 int rc = fts5StorageLoadTotals(p, 0);
1034 if( rc==SQLITE_OK ){
1035 *pnToken = 0;
1036 if( iCol<0 ){
1037 int i;
1038 for(i=0; i<p->pConfig->nCol; i++){
1039 *pnToken += p->aTotalSize[i];
1040 }
1041 }else if( iCol<p->pConfig->nCol ){
1042 *pnToken = p->aTotalSize[iCol];
1043 }else{
1044 rc = SQLITE_RANGE;
1045 }
1046 }
1047 return rc;
1048 }
1049
1050 int sqlite3Fts5StorageRowCount(Fts5Storage *p, i64 *pnRow){
1051 int rc = fts5StorageLoadTotals(p, 0);
1052 if( rc==SQLITE_OK ){
1053 *pnRow = p->nTotalRow;
1054 }
1055 return rc;
1056 }
1057
1058 /*
1059 ** Flush any data currently held in-memory to disk.
1060 */
1061 int sqlite3Fts5StorageSync(Fts5Storage *p, int bCommit){
1062 if( bCommit && p->bTotalsValid ){
1063 int rc = fts5StorageSaveTotals(p);
1064 p->bTotalsValid = 0;
1065 if( rc!=SQLITE_OK ) return rc;
1066 }
1067 return sqlite3Fts5IndexSync(p->pIndex, bCommit);
1068 }
1069
1070 int sqlite3Fts5StorageRollback(Fts5Storage *p){
1071 p->bTotalsValid = 0;
1072 return sqlite3Fts5IndexRollback(p->pIndex);
1073 }
1074
1075 int sqlite3Fts5StorageConfigValue(
1076 Fts5Storage *p,
1077 const char *z,
1078 sqlite3_value *pVal,
1079 int iVal
1080 ){
1081 sqlite3_stmt *pReplace = 0;
1082 int rc = fts5StorageGetStmt(p, FTS5_STMT_REPLACE_CONFIG, &pReplace, 0);
1083 if( rc==SQLITE_OK ){
1084 sqlite3_bind_text(pReplace, 1, z, -1, SQLITE_STATIC);
1085 if( pVal ){
1086 sqlite3_bind_value(pReplace, 2, pVal);
1087 }else{
1088 sqlite3_bind_int(pReplace, 2, iVal);
1089 }
1090 sqlite3_step(pReplace);
1091 rc = sqlite3_reset(pReplace);
1092 }
1093 if( rc==SQLITE_OK && pVal ){
1094 int iNew = p->pConfig->iCookie + 1;
1095 rc = sqlite3Fts5IndexSetCookie(p->pIndex, iNew);
1096 if( rc==SQLITE_OK ){
1097 p->pConfig->iCookie = iNew;
1098 }
1099 }
1100 return rc;
1101 }
1102
1103
OLDNEW
« no previous file with comments | « third_party/sqlite/sqlite-src-3100200/ext/fts5/fts5_main.c ('k') | third_party/sqlite/sqlite-src-3100200/ext/fts5/fts5_tcl.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698