Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Extra tests for fts3. And fixes for conflict-handling related problems in fts3. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | vtab-conflict |
Files: | files | file ages | folders |
SHA1: |
fb4a355871d9482ccb28b6ba03b842b3 |
User & Date: | dan 2011-04-26 19:21:34.191 |
Context
2011-04-27
| ||
12:08 | Fix problems related to savepoint rollback and fts3. (check-in: ff69f823f2 user: dan tags: vtab-conflict) | |
2011-04-26
| ||
19:21 | Extra tests for fts3. And fixes for conflict-handling related problems in fts3. (check-in: fb4a355871 user: dan tags: vtab-conflict) | |
2011-04-25
| ||
18:49 | Add support for on conflict clauses to fts3/fts4. (check-in: 6d2633a6d0 user: dan tags: vtab-conflict) | |
Changes
Changes to ext/fts3/fts3.c.
︙ | ︙ | |||
3539 3540 3541 3542 3543 3544 3545 3546 3547 | ); fts3DbExec(&rc, db, "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';", p->zDb, p->zName, zName ); return rc; } static const sqlite3_module fts3Module = { | > > > > > > > > > > > | > > > | 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 | ); fts3DbExec(&rc, db, "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';", p->zDb, p->zName, zName ); return rc; } static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ return sqlite3Fts3PendingTermsFlush((Fts3Table *)pVtab); } static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ return SQLITE_OK; } static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ sqlite3Fts3PendingTermsClear((Fts3Table *)pVtab); return SQLITE_OK; } static const sqlite3_module fts3Module = { /* iVersion */ 1, /* xCreate */ fts3CreateMethod, /* xConnect */ fts3ConnectMethod, /* xBestIndex */ fts3BestIndexMethod, /* xDisconnect */ fts3DisconnectMethod, /* xDestroy */ fts3DestroyMethod, /* xOpen */ fts3OpenMethod, /* xClose */ fts3CloseMethod, /* xFilter */ fts3FilterMethod, /* xNext */ fts3NextMethod, /* xEof */ fts3EofMethod, /* xColumn */ fts3ColumnMethod, /* xRowid */ fts3RowidMethod, /* xUpdate */ fts3UpdateMethod, /* xBegin */ fts3BeginMethod, /* xSync */ fts3SyncMethod, /* xCommit */ fts3CommitMethod, /* xRollback */ fts3RollbackMethod, /* xFindFunction */ fts3FindFunctionMethod, /* xRename */ fts3RenameMethod, /* xSavepoint */ fts3SavepointMethod, /* xRelease */ fts3ReleaseMethod, /* xRollbackTo */ fts3RollbackToMethod, }; /* ** This function is registered as the module destructor (called when an ** FTS3 enabled database connection is closed). It frees the memory ** allocated for the tokenizer hash table. */ |
︙ | ︙ | |||
3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 | const sqlite3_tokenizer_module *pSimple = 0; const sqlite3_tokenizer_module *pPorter = 0; #ifdef SQLITE_ENABLE_ICU const sqlite3_tokenizer_module *pIcu = 0; sqlite3Fts3IcuTokenizerModule(&pIcu); #endif rc = sqlite3Fts3InitAux(db); if( rc!=SQLITE_OK ) return rc; sqlite3Fts3SimpleTokenizerModule(&pSimple); sqlite3Fts3PorterTokenizerModule(&pPorter); | > > > > > | 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 | const sqlite3_tokenizer_module *pSimple = 0; const sqlite3_tokenizer_module *pPorter = 0; #ifdef SQLITE_ENABLE_ICU const sqlite3_tokenizer_module *pIcu = 0; sqlite3Fts3IcuTokenizerModule(&pIcu); #endif #ifdef SQLITE_TEST rc = sqlite3Fts3InitTerm(db); if( rc!=SQLITE_OK ) return rc; #endif rc = sqlite3Fts3InitAux(db); if( rc!=SQLITE_OK ) return rc; sqlite3Fts3SimpleTokenizerModule(&pSimple); sqlite3Fts3PorterTokenizerModule(&pPorter); |
︙ | ︙ |
Added ext/fts3/fts3_term.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 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 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 | /* ** 2011 Jan 27 ** ** 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. ** ****************************************************************************** ** */ #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) #ifdef SQLITE_TEST #include "fts3Int.h" #include <string.h> #include <assert.h> typedef struct Fts3termTable Fts3termTable; typedef struct Fts3termCursor Fts3termCursor; struct Fts3termTable { sqlite3_vtab base; /* Base class used by SQLite core */ Fts3Table *pFts3Tab; }; struct Fts3termCursor { sqlite3_vtab_cursor base; /* Base class used by SQLite core */ Fts3SegReaderCursor csr; /* Must be right after "base" */ Fts3SegFilter filter; int isEof; /* True if cursor is at EOF */ char *pNext; sqlite3_int64 iRowid; /* Current 'rowid' value */ sqlite3_int64 iDocid; /* Current 'docid' value */ int iCol; /* Current 'col' value */ int iPos; /* Current 'pos' value */ }; /* ** Schema of the terms table. */ #define FTS3_TERMS_SCHEMA "CREATE TABLE x(term, docid, col, pos)" /* ** This function does all the work for both the xConnect and xCreate methods. ** These tables have no persistent representation of their own, so xConnect ** and xCreate are identical operations. */ static int fts3termConnectMethod( sqlite3 *db, /* Database connection */ void *pUnused, /* Unused */ int argc, /* Number of elements in argv array */ const char * const *argv, /* xCreate/xConnect argument array */ sqlite3_vtab **ppVtab, /* OUT: New sqlite3_vtab object */ char **pzErr /* OUT: sqlite3_malloc'd error message */ ){ char const *zDb; /* Name of database (e.g. "main") */ char const *zFts3; /* Name of fts3 table */ int nDb; /* Result of strlen(zDb) */ int nFts3; /* Result of strlen(zFts3) */ int nByte; /* Bytes of space to allocate here */ int rc; /* value returned by declare_vtab() */ Fts3termTable *p; /* Virtual table object to return */ UNUSED_PARAMETER(pUnused); /* The user should specify a single argument - the name of an fts3 table. */ if( argc!=4 ){ *pzErr = sqlite3_mprintf( "wrong number of arguments to fts4term constructor" ); return SQLITE_ERROR; } zDb = argv[1]; nDb = strlen(zDb); zFts3 = argv[3]; nFts3 = strlen(zFts3); rc = sqlite3_declare_vtab(db, FTS3_TERMS_SCHEMA); if( rc!=SQLITE_OK ) return rc; nByte = sizeof(Fts3termTable) + sizeof(Fts3Table) + nDb + nFts3 + 2; p = (Fts3termTable *)sqlite3_malloc(nByte); if( !p ) return SQLITE_NOMEM; memset(p, 0, nByte); p->pFts3Tab = (Fts3Table *)&p[1]; p->pFts3Tab->zDb = (char *)&p->pFts3Tab[1]; p->pFts3Tab->zName = &p->pFts3Tab->zDb[nDb+1]; p->pFts3Tab->db = db; memcpy((char *)p->pFts3Tab->zDb, zDb, nDb); memcpy((char *)p->pFts3Tab->zName, zFts3, nFts3); sqlite3Fts3Dequote((char *)p->pFts3Tab->zName); *ppVtab = (sqlite3_vtab *)p; return SQLITE_OK; } /* ** This function does the work for both the xDisconnect and xDestroy methods. ** These tables have no persistent representation of their own, so xDisconnect ** and xDestroy are identical operations. */ static int fts3termDisconnectMethod(sqlite3_vtab *pVtab){ Fts3termTable *p = (Fts3termTable *)pVtab; Fts3Table *pFts3 = p->pFts3Tab; int i; /* Free any prepared statements held */ for(i=0; i<SizeofArray(pFts3->aStmt); i++){ sqlite3_finalize(pFts3->aStmt[i]); } sqlite3_free(pFts3->zSegmentsTbl); sqlite3_free(p); return SQLITE_OK; } #define FTS4AUX_EQ_CONSTRAINT 1 #define FTS4AUX_GE_CONSTRAINT 2 #define FTS4AUX_LE_CONSTRAINT 4 /* ** xBestIndex - Analyze a WHERE and ORDER BY clause. */ static int fts3termBestIndexMethod( sqlite3_vtab *pVTab, sqlite3_index_info *pInfo ){ UNUSED_PARAMETER(pVTab); UNUSED_PARAMETER(pInfo); return SQLITE_OK; } /* ** xOpen - Open a cursor. */ static int fts3termOpenMethod(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCsr){ Fts3termCursor *pCsr; /* Pointer to cursor object to return */ UNUSED_PARAMETER(pVTab); pCsr = (Fts3termCursor *)sqlite3_malloc(sizeof(Fts3termCursor)); if( !pCsr ) return SQLITE_NOMEM; memset(pCsr, 0, sizeof(Fts3termCursor)); *ppCsr = (sqlite3_vtab_cursor *)pCsr; return SQLITE_OK; } /* ** xClose - Close a cursor. */ static int fts3termCloseMethod(sqlite3_vtab_cursor *pCursor){ Fts3Table *pFts3 = ((Fts3termTable *)pCursor->pVtab)->pFts3Tab; Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; sqlite3Fts3SegmentsClose(pFts3); sqlite3Fts3SegReaderFinish(&pCsr->csr); sqlite3_free(pCsr); return SQLITE_OK; } /* ** xNext - Advance the cursor to the next row, if any. */ static int fts3termNextMethod(sqlite3_vtab_cursor *pCursor){ Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; Fts3Table *pFts3 = ((Fts3termTable *)pCursor->pVtab)->pFts3Tab; int rc; sqlite3_int64 v; /* Increment our pretend rowid value. */ pCsr->iRowid++; /* Advance to the next term in the full-text index. */ if( pCsr->csr.aDoclist==0 || pCsr->pNext>=&pCsr->csr.aDoclist[pCsr->csr.nDoclist-1] ){ rc = sqlite3Fts3SegReaderStep(pFts3, &pCsr->csr); if( rc!=SQLITE_ROW ){ pCsr->isEof = 1; return rc; } pCsr->iCol = 0; pCsr->iPos = 0; pCsr->iDocid = 0; pCsr->pNext = pCsr->csr.aDoclist; /* Read docid */ pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &pCsr->iDocid); } pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); if( v==0 ){ pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); pCsr->iDocid += v; pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); pCsr->iCol = 0; pCsr->iPos = 0; } if( v==1 ){ pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); pCsr->iCol += v; pCsr->iPos = 0; pCsr->pNext += sqlite3Fts3GetVarint(pCsr->pNext, &v); } pCsr->iPos += (v - 2); return SQLITE_OK; } /* ** xFilter - Initialize a cursor to point at the start of its data. */ static int fts3termFilterMethod( sqlite3_vtab_cursor *pCursor, /* The cursor used for this query */ int idxNum, /* Strategy index */ const char *idxStr, /* Unused */ int nVal, /* Number of elements in apVal */ sqlite3_value **apVal /* Arguments for the indexing scheme */ ){ Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; Fts3Table *pFts3 = ((Fts3termTable *)pCursor->pVtab)->pFts3Tab; int rc; UNUSED_PARAMETER(nVal); UNUSED_PARAMETER(idxNum); UNUSED_PARAMETER(idxStr); UNUSED_PARAMETER(apVal); assert( idxStr==0 && idxNum==0 ); /* In case this cursor is being reused, close and zero it. */ testcase(pCsr->filter.zTerm); sqlite3Fts3SegReaderFinish(&pCsr->csr); memset(&pCsr->csr, 0, ((u8*)&pCsr[1]) - (u8*)&pCsr->csr); pCsr->filter.flags = FTS3_SEGMENT_REQUIRE_POS|FTS3_SEGMENT_IGNORE_EMPTY; pCsr->filter.flags |= FTS3_SEGMENT_SCAN; rc = sqlite3Fts3SegReaderCursor(pFts3, FTS3_SEGCURSOR_ALL, pCsr->filter.zTerm, pCsr->filter.nTerm, 0, 1, &pCsr->csr ); if( rc==SQLITE_OK ){ rc = sqlite3Fts3SegReaderStart(pFts3, &pCsr->csr, &pCsr->filter); } if( rc==SQLITE_OK ){ rc = fts3termNextMethod(pCursor); } return rc; } /* ** xEof - Return true if the cursor is at EOF, or false otherwise. */ static int fts3termEofMethod(sqlite3_vtab_cursor *pCursor){ Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; return pCsr->isEof; } /* ** xColumn - Return a column value. */ static int fts3termColumnMethod( sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ sqlite3_context *pCtx, /* Context for sqlite3_result_xxx() calls */ int iCol /* Index of column to read value from */ ){ Fts3termCursor *p = (Fts3termCursor *)pCursor; assert( iCol>=0 && iCol<=3 ); switch( iCol ){ case 0: sqlite3_result_text(pCtx, p->csr.zTerm, p->csr.nTerm, SQLITE_TRANSIENT); break; case 1: sqlite3_result_int64(pCtx, p->iDocid); break; case 2: sqlite3_result_int64(pCtx, p->iCol); break; default: sqlite3_result_int64(pCtx, p->iPos); break; } return SQLITE_OK; } /* ** xRowid - Return the current rowid for the cursor. */ static int fts3termRowidMethod( sqlite3_vtab_cursor *pCursor, /* Cursor to retrieve value from */ sqlite_int64 *pRowid /* OUT: Rowid value */ ){ Fts3termCursor *pCsr = (Fts3termCursor *)pCursor; *pRowid = pCsr->iRowid; return SQLITE_OK; } /* ** Register the fts3term module with database connection db. Return SQLITE_OK ** if successful or an error code if sqlite3_create_module() fails. */ int sqlite3Fts3InitTerm(sqlite3 *db){ static const sqlite3_module fts3term_module = { 0, /* iVersion */ fts3termConnectMethod, /* xCreate */ fts3termConnectMethod, /* xConnect */ fts3termBestIndexMethod, /* xBestIndex */ fts3termDisconnectMethod, /* xDisconnect */ fts3termDisconnectMethod, /* xDestroy */ fts3termOpenMethod, /* xOpen */ fts3termCloseMethod, /* xClose */ fts3termFilterMethod, /* xFilter */ fts3termNextMethod, /* xNext */ fts3termEofMethod, /* xEof */ fts3termColumnMethod, /* xColumn */ fts3termRowidMethod, /* xRowid */ 0, /* xUpdate */ 0, /* xBegin */ 0, /* xSync */ 0, /* xCommit */ 0, /* xRollback */ 0, /* xFindFunction */ 0 /* xRename */ }; int rc; /* Return code */ rc = sqlite3_create_module(db, "fts4term", &fts3term_module, 0); return rc; } #endif #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3) */ |
Changes to ext/fts3/fts3_write.c.
︙ | ︙ | |||
2707 2708 2709 2710 2711 2712 2713 | ** If the on-conflict mode is REPLACE, this means that the existing row ** should be deleted from the database before inserting the new row. Or, ** if the on-conflict mode is other than REPLACE, then this method must ** detect the conflict and return SQLITE_CONSTRAINT before beginning to ** modify the database file. */ if( nArg>1 ){ | | > > > > > > > > > > > > > > > > | 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 | ** If the on-conflict mode is REPLACE, this means that the existing row ** should be deleted from the database before inserting the new row. Or, ** if the on-conflict mode is other than REPLACE, then this method must ** detect the conflict and return SQLITE_CONSTRAINT before beginning to ** modify the database file. */ if( nArg>1 ){ /* Find the value object that holds the new rowid value. */ sqlite3_value *pNewRowid = apVal[3+p->nColumn]; if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ pNewRowid = apVal[1]; } if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && ( sqlite3_value_type(apVal[0])==SQLITE_NULL || sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid) )){ /* The new rowid is not NULL (in this case the rowid will be ** automatically assigned and there is no chance of a conflict), and ** the statement is either an INSERT or an UPDATE that modifies the ** rowid column. So if the conflict mode is REPLACE, then delete any ** existing row with rowid=pNewRowid. ** ** Or, if the conflict mode is not REPLACE, insert the new record into ** the %_content table. If we hit the duplicate rowid constraint (or any ** other error) while doing so, return immediately. ** ** This branch may also run if pNewRowid contains a value that cannot ** be losslessly converted to an integer. In this case, the eventual ** call to fts3InsertData() (either just below or further on in this ** function) will return SQLITE_MISMATCH. */ if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel); }else{ rc = fts3InsertData(p, apVal, pRowid); bInsertDone = 1; } } |
︙ | ︙ |
Changes to main.mk.
︙ | ︙ | |||
295 296 297 298 299 300 301 302 303 304 305 306 307 308 | $(TOP)/src/vdbe.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/where.c \ parse.c \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c # Header files used by all library source files. # HDR = \ | > | 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | $(TOP)/src/vdbe.c \ $(TOP)/src/vdbemem.c \ $(TOP)/src/where.c \ parse.c \ $(TOP)/ext/fts3/fts3.c \ $(TOP)/ext/fts3/fts3_aux.c \ $(TOP)/ext/fts3/fts3_expr.c \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_tokenizer.c \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c # Header files used by all library source files. # HDR = \ |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 | int (*xSync)(sqlite3_vtab *pVTab); int (*xCommit)(sqlite3_vtab *pVTab); int (*xRollback)(sqlite3_vtab *pVTab); int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg); int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); }; /* ** CAPI3REF: Virtual Table Indexing Information ** KEYWORDS: sqlite3_index_info ** ** The sqlite3_index_info structure and its substructures is used as part | > > > > > | 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 | int (*xSync)(sqlite3_vtab *pVTab); int (*xCommit)(sqlite3_vtab *pVTab); int (*xRollback)(sqlite3_vtab *pVTab); int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), void **ppArg); int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); /* The methods above are in version 0 of the sqlite_module object. Those ** below are for version 1 and greater. */ int (*xSavepoint)(sqlite3_vtab *pVTab, int); int (*xRelease)(sqlite3_vtab *pVTab, int); int (*xRollbackTo)(sqlite3_vtab *pVTab, int); }; /* ** CAPI3REF: Virtual Table Indexing Information ** KEYWORDS: sqlite3_index_info ** ** The sqlite3_index_info structure and its substructures is used as part |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 | # define sqlite3VtabSync(X,Y) SQLITE_OK # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X) # define sqlite3VtabInSync(db) 0 # define sqlite3VtabLock(X) # define sqlite3VtabUnlock(X) # define sqlite3VtabUnlockList(X) #else void sqlite3VtabClear(sqlite3 *db, Table*); int sqlite3VtabSync(sqlite3 *db, char **); int sqlite3VtabRollback(sqlite3 *db); int sqlite3VtabCommit(sqlite3 *db); void sqlite3VtabLock(VTable *); void sqlite3VtabUnlock(VTable *); void sqlite3VtabUnlockList(sqlite3*); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif void sqlite3VtabMakeWritable(Parse*,Table*); void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); void sqlite3VtabFinishParse(Parse*, Token*); void sqlite3VtabArgInit(Parse*); void sqlite3VtabArgExtend(Parse*, Token*); | > > | 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 | # define sqlite3VtabSync(X,Y) SQLITE_OK # define sqlite3VtabRollback(X) # define sqlite3VtabCommit(X) # define sqlite3VtabInSync(db) 0 # define sqlite3VtabLock(X) # define sqlite3VtabUnlock(X) # define sqlite3VtabUnlockList(X) # define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK #else void sqlite3VtabClear(sqlite3 *db, Table*); int sqlite3VtabSync(sqlite3 *db, char **); int sqlite3VtabRollback(sqlite3 *db); int sqlite3VtabCommit(sqlite3 *db); void sqlite3VtabLock(VTable *); void sqlite3VtabUnlock(VTable *); void sqlite3VtabUnlockList(sqlite3*); int sqlite3VtabSavepoint(sqlite3 *, int, int); # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) #endif void sqlite3VtabMakeWritable(Parse*,Table*); void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); void sqlite3VtabFinishParse(Parse*, Token*); void sqlite3VtabArgInit(Parse*); void sqlite3VtabArgExtend(Parse*, Token*); |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
2817 2818 2819 2820 2821 2822 2823 | ){ assert( sqlite3BtreeIsInTrans(pBt) ); if( p->iStatement==0 ){ assert( db->nStatement>=0 && db->nSavepoint>=0 ); db->nStatement++; p->iStatement = db->nSavepoint + db->nStatement; } | > > > | > | 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 | ){ assert( sqlite3BtreeIsInTrans(pBt) ); if( p->iStatement==0 ){ assert( db->nStatement>=0 && db->nSavepoint>=0 ); db->nStatement++; p->iStatement = db->nSavepoint + db->nStatement; } rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement); if( rc==SQLITE_OK ){ rc = sqlite3BtreeBeginStmt(pBt, p->iStatement); } /* Store the current value of the database handles deferred constraint ** counter. If the statement transaction needs to be rolled back, ** the value of this counter needs to be restored too. */ p->nStmtDefCons = db->nDeferredCons; } } |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 | if( rc==SQLITE_OK ){ rc = rc2; } } } db->nStatement--; p->iStatement = 0; /* If the statement transaction is being rolled back, also restore the ** database handles deferred constraint counter to the value it had when ** the statement transaction was opened. */ if( eOp==SAVEPOINT_ROLLBACK ){ db->nDeferredCons = p->nStmtDefCons; } | > > > > > > > > > | 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 | if( rc==SQLITE_OK ){ rc = rc2; } } } db->nStatement--; p->iStatement = 0; if( rc==SQLITE_OK ){ if( eOp==SAVEPOINT_ROLLBACK ){ rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint); } if( rc==SQLITE_OK ){ rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint); } } /* If the statement transaction is being rolled back, also restore the ** database handles deferred constraint counter to the value it had when ** the statement transaction was opened. */ if( eOp==SAVEPOINT_ROLLBACK ){ db->nDeferredCons = p->nStmtDefCons; } |
︙ | ︙ |
Changes to src/vtab.c.
︙ | ︙ | |||
832 833 834 835 836 837 838 | return SQLITE_OK; } pModule = pVTab->pVtab->pModule; if( pModule->xBegin ){ int i; | < > > > > > > > > > > > > > > > > > > > > > > > > > > | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 | return SQLITE_OK; } pModule = pVTab->pVtab->pModule; if( pModule->xBegin ){ int i; /* If pVtab is already in the aVTrans array, return early */ for(i=0; i<db->nVTrans; i++){ if( db->aVTrans[i]==pVTab ){ return SQLITE_OK; } } /* Invoke the xBegin method */ rc = pModule->xBegin(pVTab->pVtab); if( rc==SQLITE_OK ){ rc = addToVTrans(db, pVTab); } } return rc; } int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ int i; int rc = SQLITE_OK; assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN ); for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){ sqlite3_vtab *pVtab = db->aVTrans[i]->pVtab; sqlite3_module *pMod = db->aVTrans[i]->pMod->pModule; if( pMod->iVersion>=1 ){ switch( op ){ case SAVEPOINT_BEGIN: rc = pMod->xSavepoint(pVtab, iSavepoint); break; case SAVEPOINT_ROLLBACK: rc = pMod->xRollbackTo(pVtab, iSavepoint); break; default: rc = pMod->xRelease(pVtab, iSavepoint); break; } } } return rc; } /* ** The first parameter (pDef) is a function implementation. The ** second parameter (pExpr) is the first argument to this function. |
︙ | ︙ |
Changes to test/fts3conf.test.
︙ | ︙ | |||
18 19 20 21 22 23 24 | # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > | > > > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 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 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | # If SQLITE_ENABLE_FTS3 is defined, omit this file. ifcapable !fts3 { finish_test return } proc fts3_integrity {tn db tbl} { if {[sqlite3_get_autocommit $db]==0} { error "fts3_integrity does not work with an open transaction" } set sql [db one {SELECT sql FROM sqlite_master WHERE name = $tbl}] regexp -nocase {[^(]* using (.*)} $sql -> tail set cols [list] $db eval "PRAGMA table_info($tbl)" { lappend cols $name } set cols [join [concat docid $cols] ,] $db eval [subst { CREATE VIRTUAL TABLE fts3check USING fts4term($tbl); CREATE VIRTUAL TABLE temp.fts3check2 USING $tail; INSERT INTO temp.fts3check2($cols) SELECT docid, * FROM $tbl; CREATE VIRTUAL TABLE temp.fts3check3 USING fts4term(fts3check2); }] set m1 [$db one {SELECT md5sum(term, docid, col, pos) FROM fts3check}] set m2 [$db one {SELECT md5sum(term, docid, col, pos) FROM fts3check3}] $db eval { DROP TABLE fts3check; DROP TABLE temp.fts3check2; DROP TABLE temp.fts3check3; } uplevel [list do_test $tn [list set {} $m1] $m2] } do_execsql_test 1.0.1 { CREATE VIRTUAL TABLE t1 USING fts3(x); INSERT INTO t1(rowid, x) VALUES(1, 'a b c d'); INSERT INTO t1(rowid, x) VALUES(2, 'e f g h'); CREATE TABLE source(a, b); INSERT INTO source VALUES(4, 'z'); INSERT INTO source VALUES(2, 'y'); } db_save_and_close set T1 "INTO t1(rowid, x) VALUES(1, 'x')" set T2 "INTO t1(rowid, x) SELECT * FROM source" set T3 "t1 SET docid = 2 WHERE docid = 1" set T4 "t1 SET docid = CASE WHEN docid = 1 THEN 4 ELSE 3 END WHERE docid <=2" foreach {tn sql constraint data} [subst { 1 "INSERT OR ROLLBACK $T1" 1 {{a b c d} {e f g h}} 2 "INSERT OR ABORT $T1" 1 {{a b c d} {e f g h} {i j k l}} 3 "INSERT OR FAIL $T1" 1 {{a b c d} {e f g h} {i j k l}} 4 "INSERT OR IGNORE $T1" 0 {{a b c d} {e f g h} {i j k l}} 5 "INSERT OR REPLACE $T1" 0 {x {e f g h} {i j k l}} 6 "INSERT OR ROLLBACK $T2" 1 {{a b c d} {e f g h}} 7 "INSERT OR ABORT $T2" 1 {{a b c d} {e f g h} {i j k l}} 8 "INSERT OR FAIL $T2" 1 {{a b c d} {e f g h} {i j k l} z} 9 "INSERT OR IGNORE $T2" 0 {{a b c d} {e f g h} {i j k l} z} 10 "INSERT OR REPLACE $T2" 0 {{a b c d} y {i j k l} z} 11 "UPDATE OR ROLLBACK $T3" 1 {{a b c d} {e f g h}} 12 "UPDATE OR ABORT $T3" 1 {{a b c d} {e f g h} {i j k l}} 13 "UPDATE OR FAIL $T3" 1 {{a b c d} {e f g h} {i j k l}} 14 "UPDATE OR IGNORE $T3" 0 {{a b c d} {e f g h} {i j k l}} 15 "UPDATE OR REPLACE $T3" 0 {{a b c d} {i j k l}} 16 "UPDATE OR ROLLBACK $T4" 1 {{a b c d} {e f g h}} 17 "UPDATE OR ABORT $T4" 1 {{a b c d} {e f g h} {i j k l}} 18 "UPDATE OR FAIL $T4" 1 {{e f g h} {i j k l} {a b c d}} 19 "UPDATE OR IGNORE $T4" 0 {{e f g h} {i j k l} {a b c d}} 20 "UPDATE OR REPLACE $T4" 0 {{e f g h} {a b c d}} }] { db_restore_and_reopen execsql { BEGIN; INSERT INTO t1(rowid, x) VALUES(3, 'i j k l'); } set R(0) {0 {}} set R(1) {1 {constraint failed}} do_catchsql_test 1.$tn.1 $sql $R($constraint) do_catchsql_test 1.$tn.2 { SELECT * FROM t1 } [list 0 $data] catchsql COMMIT fts3_integrity 1.$tn.3 db t1 } finish_test |